mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2025-01-09 23:59:24 +01:00
Use extension install activity for pre A12 or ext. is installed from elsewhere
This commit is contained in:
parent
37abd2aa2e
commit
b9c7666ca6
@ -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" />
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user