Use extension install activity for pre A12 or ext. is installed from elsewhere

This commit is contained in:
Jays2Kings 2021-08-07 13:27:40 -04:00
parent 37abd2aa2e
commit b9c7666ca6
3 changed files with 119 additions and 39 deletions

View File

@ -174,6 +174,11 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".extension.util.ExtensionInstallActivity"
android:icon="@mipmap/ic_launcher"
android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<activity <activity
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity" android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:theme="@style/Theme.OSS" /> android:theme="@style/Theme.OSS" />

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.extension.util package eu.kanade.tachiyomi.extension.util
import android.app.Activity
import android.app.DownloadManager import android.app.DownloadManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
@ -9,17 +10,20 @@ import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionParams import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED import android.content.pm.PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED
import android.os.Build import android.os.Build
import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import com.hippo.unifile.UniFile import com.hippo.unifile.UniFile
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.extension.util.ExtensionInstallBroadcast.Companion.EXTRA_SESSION_ID
import eu.kanade.tachiyomi.extension.util.ExtensionInstallBroadcast.Companion.PACKAGE_INSTALLED_ACTION
import eu.kanade.tachiyomi.extension.util.ExtensionInstallBroadcast.Companion.packageInstallStep
import eu.kanade.tachiyomi.util.system.MiuiUtil import eu.kanade.tachiyomi.util.system.MiuiUtil
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
/** /**
* Activity used to install extensions, because we can only receive the result of the installation * Broadcast used to install extensions, that receives callbacks from package installer.
* with [startActivityForResult], which we need to update the UI.
*/ */
class ExtensionInstallBroadcast : BroadcastReceiver() { class ExtensionInstallBroadcast : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
@ -66,40 +70,98 @@ class ExtensionInstallBroadcast : BroadcastReceiver() {
} }
} }
private fun packageInstallStep(context: Context, intent: Intent) { companion object {
val extras = intent.extras ?: return
if (PACKAGE_INSTALLED_ACTION == intent.action) {
val downloadId = extras.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
val extensionManager: ExtensionManager by injectLazy()
when (val status = extras.getInt(PackageInstaller.EXTRA_STATUS)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val confirmIntent = extras[Intent.EXTRA_INTENT] as? Intent
context.startActivity(confirmIntent?.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
PackageInstaller.STATUS_SUCCESS -> {
extensionManager.setInstallationResult(downloadId, true)
}
PackageInstaller.STATUS_FAILURE, PackageInstaller.STATUS_FAILURE_ABORTED, PackageInstaller.STATUS_FAILURE_BLOCKED, PackageInstaller.STATUS_FAILURE_CONFLICT, PackageInstaller.STATUS_FAILURE_INCOMPATIBLE, PackageInstaller.STATUS_FAILURE_INVALID, PackageInstaller.STATUS_FAILURE_STORAGE -> {
extensionManager.setInstallationResult(downloadId, false)
if (status != PackageInstaller.STATUS_FAILURE_ABORTED) {
if (MiuiUtil.isMiui()) {
context.toast(R.string.extensions_miui_warning, Toast.LENGTH_LONG)
} else {
context.toast(R.string.could_not_install_extension)
}
}
}
else -> {
extensionManager.setInstallationResult(downloadId, false)
}
}
}
}
private companion object {
const val INSTALL_REQUEST_CODE = 500 const val INSTALL_REQUEST_CODE = 500
const val EXTRA_SESSION_ID = "ExtensionInstaller.extra.SESSION_ID" const val EXTRA_SESSION_ID = "ExtensionInstaller.extra.SESSION_ID"
const val PACKAGE_INSTALLED_ACTION = const val PACKAGE_INSTALLED_ACTION =
"eu.kanade.tachiyomi.SESSION_API_PACKAGE_INSTALLED" "eu.kanade.tachiyomi.SESSION_API_PACKAGE_INSTALLED"
fun packageInstallStep(context: Context, intent: Intent) {
val extras = intent.extras ?: return
if (PACKAGE_INSTALLED_ACTION == intent.action) {
val downloadId = extras.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
val extensionManager: ExtensionManager by injectLazy()
when (val status = extras.getInt(PackageInstaller.EXTRA_STATUS)) {
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
val confirmIntent = extras[Intent.EXTRA_INTENT] as? Intent
if (context is Activity) {
context.startActivity(confirmIntent)
} else {
context.startActivity(confirmIntent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
}
}
PackageInstaller.STATUS_SUCCESS -> {
extensionManager.setInstallationResult(downloadId, true)
}
PackageInstaller.STATUS_FAILURE, PackageInstaller.STATUS_FAILURE_ABORTED, PackageInstaller.STATUS_FAILURE_BLOCKED, PackageInstaller.STATUS_FAILURE_CONFLICT, PackageInstaller.STATUS_FAILURE_INCOMPATIBLE, PackageInstaller.STATUS_FAILURE_INVALID, PackageInstaller.STATUS_FAILURE_STORAGE -> {
extensionManager.setInstallationResult(downloadId, false)
if (status != PackageInstaller.STATUS_FAILURE_ABORTED) {
if (MiuiUtil.isMiui()) {
context.toast(R.string.extensions_miui_warning, Toast.LENGTH_LONG)
} else {
context.toast(R.string.could_not_install_extension)
}
}
}
else -> {
extensionManager.setInstallationResult(downloadId, false)
}
}
}
}
}
}
/**
* Activity used to install extensions, that receives callbacks from package installer.
* Used when we need to prompt the user to install multiple apps
*/
class ExtensionInstallActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
if (PACKAGE_INSTALLED_ACTION == intent.action) {
packageInstallStep(this, intent)
finish()
return
}
val downloadId = intent.extras!!.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
val packageInstaller = packageManager.packageInstaller
val data = UniFile.fromUri(this, intent.data).openInputStream()
val params = SessionParams(
SessionParams.MODE_FULL_INSTALL
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
params.setRequireUserAction(USER_ACTION_NOT_REQUIRED)
}
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)
session.openWrite("package", 0, -1).use { packageInSession ->
data.copyTo(packageInSession)
}
val newIntent = Intent(this, ExtensionInstallActivity::class.java)
.setAction(PACKAGE_INSTALLED_ACTION)
.putExtra(ExtensionInstaller.EXTRA_DOWNLOAD_ID, downloadId)
.putExtra(EXTRA_SESSION_ID, sessionId)
val pendingIntent = PendingIntent.getActivity(this, downloadId.hashCode(), newIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val statusReceiver = pendingIntent.intentSender
session.commit(statusReceiver)
val extensionManager: ExtensionManager by injectLazy()
extensionManager.setInstalling(downloadId, sessionId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
(getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager).remove(downloadId)
}
data.close()
} catch (error: Exception) {
// Either install package can't be found (probably bots) or there's a security exception
// with the download manager. Nothing we can workaround.
toast(error.message)
}
finish()
} }
} }

View File

@ -6,6 +6,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Environment import android.os.Environment
import androidx.core.net.toUri import androidx.core.net.toUri
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
@ -211,12 +212,24 @@ internal class ExtensionInstaller(private val context: Context) {
* @param uri The uri of the extension to install. * @param uri The uri of the extension to install.
*/ */
fun installApk(downloadId: Long, uri: Uri) { fun installApk(downloadId: Long, uri: Uri) {
val intent = Intent(context, ExtensionInstallBroadcast::class.java) val pkgName = activeDownloads.entries.find { it.value == downloadId }?.key
.setDataAndType(uri, APK_MIME) val useActivity =
.putExtra(EXTRA_DOWNLOAD_ID, downloadId) pkgName?.let { !ExtensionLoader.isExtensionInstalledByApp(context, pkgName) } ?: true ||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION) Build.VERSION.SDK_INT < Build.VERSION_CODES.S
val intent =
context.sendBroadcast(intent) if (useActivity) {
Intent(context, ExtensionInstallActivity::class.java)
} else {
Intent(context, ExtensionInstallBroadcast::class.java)
}
.setDataAndType(uri, APK_MIME)
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
if (useActivity) {
context.startActivity(intent)
} else {
context.sendBroadcast(intent)
}
} }
/** /**