Implement new extension install methods (#5904)
* Implement new extension install methods * Fixes * Resolve feedback * Keep pending status when waiting to install * Cancellable installation * Remove auto error now that we have cancellable job
This commit is contained in:
@@ -4,6 +4,7 @@ import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -40,10 +41,13 @@ class ExtensionInstallActivity : Activity() {
|
||||
|
||||
private fun checkInstallationResult(resultCode: Int) {
|
||||
val downloadId = intent.extras!!.getLong(ExtensionInstaller.EXTRA_DOWNLOAD_ID)
|
||||
val success = resultCode == RESULT_OK
|
||||
|
||||
val extensionManager = Injekt.get<ExtensionManager>()
|
||||
extensionManager.setInstallationResult(downloadId, success)
|
||||
val newStep = when (resultCode) {
|
||||
RESULT_OK -> InstallStep.Installed
|
||||
RESULT_CANCELED -> InstallStep.Idle
|
||||
else -> InstallStep.Error
|
||||
}
|
||||
extensionManager.updateInstallStep(downloadId, newStep)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package eu.kanade.tachiyomi.extension.util
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.IBinder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.extension.installer.Installer
|
||||
import eu.kanade.tachiyomi.extension.installer.PackageInstallerInstaller
|
||||
import eu.kanade.tachiyomi.extension.installer.ShizukuInstaller
|
||||
import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_DOWNLOAD_ID
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import timber.log.Timber
|
||||
|
||||
class ExtensionInstallService : Service() {
|
||||
|
||||
private var installer: Installer? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
val notification = notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
setAutoCancel(false)
|
||||
setOngoing(true)
|
||||
setShowWhen(false)
|
||||
setContentTitle(getString(R.string.ext_install_service_notif))
|
||||
setProgress(100, 100, true)
|
||||
}.build()
|
||||
startForeground(Notifications.ID_EXTENSION_INSTALLER, notification)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
val uri = intent?.data
|
||||
val id = intent?.getLongExtra(EXTRA_DOWNLOAD_ID, -1)?.takeIf { it != -1L }
|
||||
val installerUsed = intent?.getSerializableExtra(EXTRA_INSTALLER) as? PreferenceValues.ExtensionInstaller
|
||||
if (uri == null || id == null || installerUsed == null) {
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
if (installer == null) {
|
||||
installer = when (installerUsed) {
|
||||
PreferenceValues.ExtensionInstaller.PACKAGEINSTALLER -> PackageInstallerInstaller(this)
|
||||
PreferenceValues.ExtensionInstaller.SHIZUKU -> ShizukuInstaller(this)
|
||||
else -> {
|
||||
Timber.e("Not implemented for installer $installerUsed")
|
||||
stopSelf()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
}
|
||||
}
|
||||
installer!!.addToQueue(id, uri)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
installer?.onDestroy()
|
||||
installer = null
|
||||
}
|
||||
|
||||
override fun onBind(i: Intent?): IBinder? = null
|
||||
|
||||
companion object {
|
||||
private const val EXTRA_INSTALLER = "EXTRA_INSTALLER"
|
||||
|
||||
fun getIntent(
|
||||
context: Context,
|
||||
downloadId: Long,
|
||||
uri: Uri,
|
||||
installer: PreferenceValues.ExtensionInstaller
|
||||
): Intent {
|
||||
return Intent(context, ExtensionInstallService::class.java)
|
||||
.setDataAndType(uri, ExtensionInstaller.APK_MIME)
|
||||
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
|
||||
.putExtra(EXTRA_INSTALLER, installer)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,21 @@ import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.net.toUri
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.extension.installer.Installer
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@@ -47,6 +53,8 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
*/
|
||||
private val downloadsRelay = PublishRelay.create<Pair<Long, InstallStep>>()
|
||||
|
||||
private val installerPref = Injekt.get<PreferencesHelper>().extensionInstaller()
|
||||
|
||||
/**
|
||||
* Adds the given extension to the downloads queue and returns an observable containing its
|
||||
* step in the installation process.
|
||||
@@ -79,8 +87,6 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
.map { it.second }
|
||||
// Poll download status
|
||||
.mergeWith(pollStatus(id))
|
||||
// Force an error if the download takes more than 3 minutes
|
||||
.mergeWith(Observable.timer(3, TimeUnit.MINUTES).map { InstallStep.Error })
|
||||
// Stop when the application is installed or errors
|
||||
.takeUntil { it.isCompleted() }
|
||||
// Always notify on main thread
|
||||
@@ -126,12 +132,29 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
* @param uri The uri of the extension to install.
|
||||
*/
|
||||
fun installApk(downloadId: Long, uri: Uri) {
|
||||
val intent = Intent(context, ExtensionInstallActivity::class.java)
|
||||
.setDataAndType(uri, APK_MIME)
|
||||
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
when (val installer = installerPref.get()) {
|
||||
PreferenceValues.ExtensionInstaller.LEGACY -> {
|
||||
val intent = Intent(context, ExtensionInstallActivity::class.java)
|
||||
.setDataAndType(uri, APK_MIME)
|
||||
.putExtra(EXTRA_DOWNLOAD_ID, downloadId)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
|
||||
context.startActivity(intent)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
else -> {
|
||||
val intent = ExtensionInstallService.getIntent(context, downloadId, uri, installer)
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels extension install and remove from download manager and installer.
|
||||
*/
|
||||
fun cancelInstall(pkgName: String) {
|
||||
val downloadId = activeDownloads.remove(pkgName) ?: return
|
||||
downloadManager.remove(downloadId)
|
||||
Installer.cancelInstallQueue(context, downloadId)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,13 +170,12 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the result of the installation of an extension.
|
||||
* Sets the step of the installation of an extension.
|
||||
*
|
||||
* @param downloadId The id of the download.
|
||||
* @param result Whether the extension was installed or not.
|
||||
* @param step New install step.
|
||||
*/
|
||||
fun setInstallationResult(downloadId: Long, result: Boolean) {
|
||||
val step = if (result) InstallStep.Installed else InstallStep.Error
|
||||
fun updateInstallStep(downloadId: Long, step: InstallStep) {
|
||||
downloadsRelay.call(downloadId to step)
|
||||
}
|
||||
|
||||
@@ -216,9 +238,7 @@ internal class ExtensionInstaller(private val context: Context) {
|
||||
val uri = downloadManager.getUriForDownloadedFile(id)
|
||||
|
||||
// Set next installation step
|
||||
if (uri != null) {
|
||||
downloadsRelay.call(id to InstallStep.Installing)
|
||||
} else {
|
||||
if (uri == null) {
|
||||
Timber.e("Couldn't locate downloaded APK")
|
||||
downloadsRelay.call(id to InstallStep.Error)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user