From 85f5ff3c14d404d7247fe8abc395d5cbd79d0d2c Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 29 Jul 2019 00:26:18 -0700 Subject: [PATCH] Download Magisk Manager via new service --- .../main/java/com/topjohnwu/magisk/Const.kt | 3 +- .../magisk/model/download/DownloadService.kt | 26 ++++- .../magisk/model/download/ManagerUpgrade.kt | 67 +++++++++++++ .../model/download/NotificationService.kt | 2 +- .../model/download/RemoteFileService.kt | 8 +- .../magisk/model/entity/UpdateInfo.kt | 6 +- .../model/entity/internal/Configuration.kt | 9 ++ .../model/entity/internal/DownloadSubject.kt | 26 ++++- .../magisk/model/receiver/GeneralReceiver.kt | 14 ++- .../magisk/ui/settings/SettingsFragment.kt | 12 ++- .../topjohnwu/magisk/utils/DownloadApp.java | 99 ------------------- .../topjohnwu/magisk/view/Notifications.java | 7 +- .../view/dialogs/ManagerInstallDialog.kt | 13 ++- .../topjohnwu/magisk/utils/APKInstall.java | 6 +- 14 files changed, 170 insertions(+), 128 deletions(-) create mode 100644 app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt delete mode 100644 app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java diff --git a/app/src/main/java/com/topjohnwu/magisk/Const.kt b/app/src/main/java/com/topjohnwu/magisk/Const.kt index 27657780a..0088a63e7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/Const.kt +++ b/app/src/main/java/com/topjohnwu/magisk/Const.kt @@ -76,8 +76,7 @@ object Const { const val ETAG_KEY = "ETag" // intents const val OPEN_SECTION = "section" - const val INTENT_SET_NAME = "filename" - const val INTENT_SET_LINK = "link" + const val INTENT_SET_APP = "app_json" const val FLASH_ACTION = "action" const val FLASH_DATA = "additional_data" const val DISMISS_ID = "dismiss_id" diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt index 58a5d00ca..155bd3519 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/DownloadService.kt @@ -14,9 +14,9 @@ import com.topjohnwu.magisk.extensions.provide import com.topjohnwu.magisk.model.entity.internal.Configuration.* import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary import com.topjohnwu.magisk.model.entity.internal.DownloadSubject -import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk -import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.ui.flash.FlashActivity +import com.topjohnwu.magisk.utils.APKInstall import java.io.File import kotlin.random.Random.Default.nextInt @@ -33,6 +33,7 @@ open class DownloadService : RemoteFileService() { override fun onFinished(file: File, subject: DownloadSubject, id: Int) = when (subject) { is Magisk -> onFinishedInternal(file, subject, id) is Module -> onFinishedInternal(file, subject, id) + is Manager -> onFinishedInternal(file, subject, id) } private fun onFinishedInternal( @@ -55,6 +56,18 @@ open class DownloadService : RemoteFileService() { else -> Unit } + private fun onFinishedInternal( + file: File, + subject: Manager, + id: Int + ) { + remove(id) + when (subject.configuration) { + is APK.Upgrade -> APKInstall.install(this, file) + else -> Unit + } + } + // --- override fun NotificationCompat.Builder.addActions( @@ -63,6 +76,7 @@ open class DownloadService : RemoteFileService() { ) = when (subject) { is Magisk -> addActionsInternal(file, subject) is Module -> addActionsInternal(file, subject) + is Manager -> addActionsInternal(file, subject) } private fun NotificationCompat.Builder.addActionsInternal( @@ -87,6 +101,14 @@ open class DownloadService : RemoteFileService() { else -> this } + private fun NotificationCompat.Builder.addActionsInternal( + file: File, + subject: Manager + ) = when (subject.configuration) { + APK.Upgrade -> setContentIntent(APKInstall.installIntent(context, file)) + else -> this + } + @Suppress("ReplaceSingleLineLet") private fun NotificationCompat.Builder.setContentIntent(intent: Intent) = PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT) diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt new file mode 100644 index 000000000..26c3e50f9 --- /dev/null +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/ManagerUpgrade.kt @@ -0,0 +1,67 @@ +package com.topjohnwu.magisk.model.download + +import android.content.ComponentName +import com.topjohnwu.magisk.BuildConfig +import com.topjohnwu.magisk.ClassMap +import com.topjohnwu.magisk.Config +import com.topjohnwu.magisk.R +import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Restore +import com.topjohnwu.magisk.model.entity.internal.Configuration.APK.Upgrade +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject +import com.topjohnwu.magisk.ui.SplashActivity +import com.topjohnwu.magisk.utils.PatchAPK +import com.topjohnwu.magisk.utils.RootUtils +import com.topjohnwu.superuser.Shell +import dalvik.system.DexClassLoader +import timber.log.Timber +import java.io.File + +private fun RemoteFileService.patchPackage(apk: File, id: Int): File { + if (packageName != BuildConfig.APPLICATION_ID) { + update(id) { notification -> + notification.setProgress(0, 0, true) + .setProgress(0, 0, true) + .setContentTitle(getString(R.string.hide_manager_title)) + .setContentText("") + } + val patched = File(apk.parent, "patched.apk") + try { + // Try using the new APK to patch itself + val loader = DexClassLoader(apk.path, apk.parent, null, ClassLoader.getSystemClassLoader()) + loader.loadClass("a.a") + .getMethod("patchAPK", String::class.java, String::class.java, String::class.java) + .invoke(null, apk.path, patched.path, packageName) + } catch (e: Exception) { + Timber.e(e) + // Fallback to use the current implementation + PatchAPK.patch(apk.path, patched.path, packageName) + } + apk.delete() + return patched + } else { + return apk + } +} + +private fun RemoteFileService.restore(apk: File, id: Int): File { + update(id) { notification -> + notification.setProgress(0, 0, true) + .setProgress(0, 0, true) + .setContentTitle(getString(R.string.restore_img_msg)) + .setContentText("") + } + Config.export() + // Make it world readable + apk.setReadable(true, false) + if (Shell.su("pm install $apk").exec().isSuccess) + RootUtils.rmAndLaunch(packageName, + ComponentName(BuildConfig.APPLICATION_ID, + ClassMap.get>(SplashActivity::class.java).name)) + return apk +} + +fun RemoteFileService.handleAPK(apk: File, subject: DownloadSubject.Manager) + = when (subject.configuration) { + is Upgrade -> patchPackage(apk, subject.hashCode()) + is Restore -> restore(apk, subject.hashCode()) + } diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/NotificationService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/NotificationService.kt index 37285bf3e..41d8eede0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/NotificationService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/NotificationService.kt @@ -27,7 +27,7 @@ abstract class NotificationService : Service() { // -- - protected fun update( + fun update( id: Int, body: (NotificationCompat.Builder) -> Unit = {} ) { diff --git a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt index a845cafed..80e8126c1 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/download/RemoteFileService.kt @@ -11,8 +11,7 @@ import com.topjohnwu.magisk.extensions.firstMap import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.extensions.writeTo import com.topjohnwu.magisk.model.entity.internal.DownloadSubject -import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk -import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.* import com.topjohnwu.magisk.utils.ProgInputStream import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.superuser.ShellUtils @@ -80,6 +79,11 @@ abstract class RemoteFileService : NotificationService() { .map { stream.toModule(subject.file, it.byteStream()); subject.file } else -> Single.fromCallable { stream.writeTo(subject.file); subject.file } } + }.map { + when (subject) { + is Manager -> handleAPK(it, subject) + else -> it + } } // --- diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt index 52b1633bc..77e25b5e7 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/UpdateInfo.kt @@ -17,7 +17,6 @@ data class UninstallerJson( val link: String = "" ) -@Parcelize @JsonSerializable data class MagiskJson( val version: String = "", @@ -25,12 +24,13 @@ data class MagiskJson( val link: String = "", val note: String = "", @Json(name = "md5") val hash: String = "" -) : Parcelable +) +@Parcelize @JsonSerializable data class ManagerJson( val version: String = "", val versionCode: Int = -1, val link: String = "", val note: String = "" -) +) : Parcelable diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/Configuration.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/Configuration.kt index 40570d4b0..da6027944 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/Configuration.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/Configuration.kt @@ -16,6 +16,15 @@ sealed class Configuration : Parcelable { } + sealed class APK : Configuration() { + + @Parcelize + object Upgrade : APK() + + @Parcelize + object Restore : APK() + } + @Parcelize object Download : Configuration() diff --git a/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt b/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt index 3c8bb0cdc..293d1064c 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/entity/internal/DownloadSubject.kt @@ -7,6 +7,7 @@ import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.extensions.cachedFile import com.topjohnwu.magisk.extensions.get import com.topjohnwu.magisk.model.entity.MagiskJson +import com.topjohnwu.magisk.model.entity.ManagerJson import com.topjohnwu.magisk.model.entity.module.Repo import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.Parcelize @@ -20,8 +21,8 @@ sealed class DownloadSubject : Parcelable { @Parcelize data class Module( - val module: Repo, - val configuration: Configuration + val module: Repo, + val configuration: Configuration ) : DownloadSubject() { override val url: String get() = module.zipUrl @@ -31,6 +32,27 @@ sealed class DownloadSubject : Parcelable { } } + @Parcelize + data class Manager( + val configuration: Configuration.APK + ) : DownloadSubject() { + + @IgnoredOnParcel + val manager: ManagerJson = Info.remote.app + + override val title: String + get() = "MagiskManager-v${manager.version}(${manager.versionCode})" + + override val url: String + get() = manager.link + + @IgnoredOnParcel + override val file by lazy { + get().cachedFile("manager.apk") + } + + } + sealed class Magisk : DownloadSubject() { abstract val configuration: Configuration diff --git a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt index a631694a5..e789a3c1a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt +++ b/app/src/main/java/com/topjohnwu/magisk/model/receiver/GeneralReceiver.kt @@ -11,8 +11,11 @@ import com.topjohnwu.magisk.data.database.PolicyDao import com.topjohnwu.magisk.data.database.base.su import com.topjohnwu.magisk.extensions.inject import com.topjohnwu.magisk.extensions.reboot +import com.topjohnwu.magisk.model.download.DownloadService +import com.topjohnwu.magisk.model.entity.ManagerJson +import com.topjohnwu.magisk.model.entity.internal.Configuration +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.ui.surequest.SuRequestActivity -import com.topjohnwu.magisk.utils.DownloadApp import com.topjohnwu.magisk.utils.SuLogger import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Shortcuts @@ -73,9 +76,12 @@ open class GeneralReceiver : BroadcastReceiver() { } Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context) Const.Key.BROADCAST_MANAGER_UPDATE -> { - Info.remote = Info.remote.copy(app = Info.remote.app.copy( - link = intent.getStringExtra(Const.Key.INTENT_SET_LINK) ?: "")) - DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME)) + intent.getParcelableExtra(Const.Key.INTENT_SET_APP)?.let { + Info.remote = Info.remote.copy(app = it) + } + DownloadService(context) { + subject = DownloadSubject.Manager(Configuration.APK.Upgrade) + } } Const.Key.BROADCAST_REBOOT -> reboot() } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt index 178c822f9..78a87b5aa 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt @@ -21,9 +21,15 @@ import com.topjohnwu.magisk.Const import com.topjohnwu.magisk.R import com.topjohnwu.magisk.data.database.RepoDao import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding +import com.topjohnwu.magisk.model.download.DownloadService +import com.topjohnwu.magisk.model.entity.internal.Configuration +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.model.observer.Observer import com.topjohnwu.magisk.ui.base.BasePreferenceFragment -import com.topjohnwu.magisk.utils.* +import com.topjohnwu.magisk.utils.FingerprintHelper +import com.topjohnwu.magisk.utils.LocaleManager +import com.topjohnwu.magisk.utils.PatchAPK +import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog import com.topjohnwu.net.Networking import com.topjohnwu.superuser.Shell @@ -71,7 +77,9 @@ class SettingsFragment : BasePreferenceFragment() { } val restoreManager = findPreference("restore") restoreManager.setOnPreferenceClickListener { - DownloadApp.restore() + DownloadService(requireContext()) { + subject = DownloadSubject.Manager(Configuration.APK.Restore) + } true } findPreference("clear").setOnPreferenceClickListener { diff --git a/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java b/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java deleted file mode 100644 index c6547df18..000000000 --- a/app/src/main/java/com/topjohnwu/magisk/utils/DownloadApp.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.topjohnwu.magisk.utils; - -import android.content.ComponentName; - -import com.topjohnwu.magisk.App; -import com.topjohnwu.magisk.BuildConfig; -import com.topjohnwu.magisk.ClassMap; -import com.topjohnwu.magisk.Config; -import com.topjohnwu.magisk.Info; -import com.topjohnwu.magisk.R; -import com.topjohnwu.magisk.ui.SplashActivity; -import com.topjohnwu.magisk.view.ProgressNotification; -import com.topjohnwu.net.Networking; -import com.topjohnwu.net.ResponseListener; -import com.topjohnwu.superuser.Shell; - -import java.io.File; - -import dalvik.system.DexClassLoader; - -public class DownloadApp { - - public static void upgrade(String name) { - dlInstall(name, new PatchPackageName()); - } - - public static void restore() { - String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)", - Info.remote.getApp().getVersion(), Info.remote.getApp().getVersionCode()); - dlInstall(name, new RestoreManager()); - } - - private static void dlInstall(String name, ManagerDownloadListener listener) { - File apk = new File(App.self.getCacheDir(), "manager.apk"); - ProgressNotification progress = new ProgressNotification(name); - listener.progress = progress; - Networking.get(Info.remote.getApp().getLink()) - .setExecutor(App.THREAD_POOL) - .setDownloadProgressListener(progress) - .setErrorHandler((conn, e) -> progress.dlFail()) - .getAsFile(apk, listener); - } - - private abstract static class ManagerDownloadListener implements ResponseListener { - ProgressNotification progress; - } - - private static class PatchPackageName extends ManagerDownloadListener { - - @Override - public void onResponse(File apk) { - File patched = apk; - App app = App.self; - if (!app.getPackageName().equals(BuildConfig.APPLICATION_ID)) { - progress.getNotificationBuilder() - .setProgress(0, 0, true) - .setContentTitle(app.getString(R.string.hide_manager_title)) - .setContentText(""); - progress.update(); - patched = new File(apk.getParent(), "patched.apk"); - try { - // Try using the new APK to patch itself - ClassLoader loader = new DexClassLoader(apk.getPath(), - apk.getParent(), null, ClassLoader.getSystemClassLoader()); - loader.loadClass("a.a") - .getMethod("patchAPK", String.class, String.class, String.class) - .invoke(null, apk.getPath(), patched.getPath(), app.getPackageName()); - } catch (Exception e) { - e.printStackTrace(); - // Fallback to use the current implementation - PatchAPK.patch(apk.getPath(), patched.getPath(), app.getPackageName()); - } - } - APKInstall.install(app, patched); - progress.dismiss(); - } - } - - private static class RestoreManager extends ManagerDownloadListener { - - @Override - public void onResponse(File apk) { - App app = App.self; - progress.getNotificationBuilder() - .setProgress(0, 0, true) - .setContentTitle(app.getString(R.string.restore_img_msg)) - .setContentText(""); - progress.update(); - Config.export(); - // Make it world readable - apk.setReadable(true, false); - if (Shell.su("pm install " + apk).exec().isSuccess()) - RootUtils.rmAndLaunch(app.getPackageName(), - new ComponentName(BuildConfig.APPLICATION_ID, - ClassMap.get(SplashActivity.class).getName())); - progress.dismiss(); - } - } -} diff --git a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.java b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.java index 1faa7fe2a..dd7f6197a 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/Notifications.java +++ b/app/src/main/java/com/topjohnwu/magisk/view/Notifications.java @@ -18,7 +18,6 @@ import com.topjohnwu.magisk.Info; import com.topjohnwu.magisk.R; import com.topjohnwu.magisk.model.receiver.GeneralReceiver; import com.topjohnwu.magisk.ui.SplashActivity; -import com.topjohnwu.magisk.utils.Utils; public class Notifications { @@ -61,13 +60,11 @@ public class Notifications { public static void managerUpdate() { App app = App.self; - String name = Utils.INSTANCE.fmt("MagiskManager v%s(%d)", - Info.remote.getApp().getVersion(), Info.remote.getApp().getVersionCode()); Intent intent = new Intent(app, ClassMap.get(GeneralReceiver.class)); intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE); - intent.putExtra(Const.Key.INTENT_SET_LINK, Info.remote.getApp().getLink()); - intent.putExtra(Const.Key.INTENT_SET_NAME, name); + intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.getApp()); + PendingIntent pendingIntent = PendingIntent.getBroadcast(app, Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); diff --git a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt index 1c6612dba..cea430e32 100644 --- a/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt +++ b/app/src/main/java/com/topjohnwu/magisk/view/dialogs/ManagerInstallDialog.kt @@ -3,18 +3,21 @@ package com.topjohnwu.magisk.view.dialogs import android.app.Activity import com.topjohnwu.magisk.Info import com.topjohnwu.magisk.R -import com.topjohnwu.magisk.utils.DownloadApp +import com.topjohnwu.magisk.model.download.DownloadService +import com.topjohnwu.magisk.model.entity.internal.Configuration +import com.topjohnwu.magisk.model.entity.internal.DownloadSubject import com.topjohnwu.magisk.view.MarkDownWindow class ManagerInstallDialog(a: Activity) : CustomAlertDialog(a) { init { - val name = "MagiskManager v${Info.remote.app.version}" + - "(${Info.remote.app.versionCode})" + val subject = DownloadSubject.Manager(Configuration.APK.Upgrade) setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name))) - setMessage(a.getString(R.string.repo_install_msg, name)) + setMessage(a.getString(R.string.repo_install_msg, subject.title)) setCancelable(true) - setPositiveButton(R.string.install) { _, _ -> DownloadApp.upgrade(name) } + setPositiveButton(R.string.install) { _, _ -> + DownloadService(a) { this.subject = subject } + } if (Info.remote.app.note.isNotEmpty()) { setNeutralButton(R.string.app_changelog) { _, _ -> MarkDownWindow.show(a, null, Info.remote.app.note) } diff --git a/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java b/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java index 93e5a0b61..66f7567aa 100644 --- a/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java +++ b/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java @@ -9,6 +9,10 @@ import java.io.File; public class APKInstall { public static void install(Context c, File apk) { + c.startActivity(installIntent(c, apk)); + } + + public static Intent installIntent(Context c, File apk) { Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE); install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); @@ -18,6 +22,6 @@ public class APKInstall { apk.setReadable(true, false); install.setData(Uri.fromFile(apk)); } - c.startActivity(install); + return install; } }