mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-25 09:27:47 +00:00
Download Magisk Manager via new service
This commit is contained in:
parent
3d81f167ea
commit
85f5ff3c14
@ -76,8 +76,7 @@ object Const {
|
|||||||
const val ETAG_KEY = "ETag"
|
const val ETAG_KEY = "ETag"
|
||||||
// intents
|
// intents
|
||||||
const val OPEN_SECTION = "section"
|
const val OPEN_SECTION = "section"
|
||||||
const val INTENT_SET_NAME = "filename"
|
const val INTENT_SET_APP = "app_json"
|
||||||
const val INTENT_SET_LINK = "link"
|
|
||||||
const val FLASH_ACTION = "action"
|
const val FLASH_ACTION = "action"
|
||||||
const val FLASH_DATA = "additional_data"
|
const val FLASH_DATA = "additional_data"
|
||||||
const val DISMISS_ID = "dismiss_id"
|
const val DISMISS_ID = "dismiss_id"
|
||||||
|
@ -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.*
|
||||||
import com.topjohnwu.magisk.model.entity.internal.Configuration.Flash.Secondary
|
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
|
||||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Magisk
|
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.*
|
||||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module
|
|
||||||
import com.topjohnwu.magisk.ui.flash.FlashActivity
|
import com.topjohnwu.magisk.ui.flash.FlashActivity
|
||||||
|
import com.topjohnwu.magisk.utils.APKInstall
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.random.Random.Default.nextInt
|
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) {
|
override fun onFinished(file: File, subject: DownloadSubject, id: Int) = when (subject) {
|
||||||
is Magisk -> onFinishedInternal(file, subject, id)
|
is Magisk -> onFinishedInternal(file, subject, id)
|
||||||
is Module -> onFinishedInternal(file, subject, id)
|
is Module -> onFinishedInternal(file, subject, id)
|
||||||
|
is Manager -> onFinishedInternal(file, subject, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onFinishedInternal(
|
private fun onFinishedInternal(
|
||||||
@ -55,6 +56,18 @@ open class DownloadService : RemoteFileService() {
|
|||||||
else -> Unit
|
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(
|
override fun NotificationCompat.Builder.addActions(
|
||||||
@ -63,6 +76,7 @@ open class DownloadService : RemoteFileService() {
|
|||||||
) = when (subject) {
|
) = when (subject) {
|
||||||
is Magisk -> addActionsInternal(file, subject)
|
is Magisk -> addActionsInternal(file, subject)
|
||||||
is Module -> addActionsInternal(file, subject)
|
is Module -> addActionsInternal(file, subject)
|
||||||
|
is Manager -> addActionsInternal(file, subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun NotificationCompat.Builder.addActionsInternal(
|
private fun NotificationCompat.Builder.addActionsInternal(
|
||||||
@ -87,6 +101,14 @@ open class DownloadService : RemoteFileService() {
|
|||||||
else -> this
|
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")
|
@Suppress("ReplaceSingleLineLet")
|
||||||
private fun NotificationCompat.Builder.setContentIntent(intent: Intent) =
|
private fun NotificationCompat.Builder.setContentIntent(intent: Intent) =
|
||||||
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
PendingIntent.getActivity(context, nextInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
||||||
|
@ -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<Class<*>>(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())
|
||||||
|
}
|
@ -27,7 +27,7 @@ abstract class NotificationService : Service() {
|
|||||||
|
|
||||||
// --
|
// --
|
||||||
|
|
||||||
protected fun update(
|
fun update(
|
||||||
id: Int,
|
id: Int,
|
||||||
body: (NotificationCompat.Builder) -> Unit = {}
|
body: (NotificationCompat.Builder) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
@ -11,8 +11,7 @@ import com.topjohnwu.magisk.extensions.firstMap
|
|||||||
import com.topjohnwu.magisk.extensions.get
|
import com.topjohnwu.magisk.extensions.get
|
||||||
import com.topjohnwu.magisk.extensions.writeTo
|
import com.topjohnwu.magisk.extensions.writeTo
|
||||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject
|
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.*
|
||||||
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject.Module
|
|
||||||
import com.topjohnwu.magisk.utils.ProgInputStream
|
import com.topjohnwu.magisk.utils.ProgInputStream
|
||||||
import com.topjohnwu.magisk.view.Notifications
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
import com.topjohnwu.superuser.ShellUtils
|
import com.topjohnwu.superuser.ShellUtils
|
||||||
@ -80,6 +79,11 @@ abstract class RemoteFileService : NotificationService() {
|
|||||||
.map { stream.toModule(subject.file, it.byteStream()); subject.file }
|
.map { stream.toModule(subject.file, it.byteStream()); subject.file }
|
||||||
else -> Single.fromCallable { stream.writeTo(subject.file); subject.file }
|
else -> Single.fromCallable { stream.writeTo(subject.file); subject.file }
|
||||||
}
|
}
|
||||||
|
}.map {
|
||||||
|
when (subject) {
|
||||||
|
is Manager -> handleAPK(it, subject)
|
||||||
|
else -> it
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
@ -17,7 +17,6 @@ data class UninstallerJson(
|
|||||||
val link: String = ""
|
val link: String = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
@JsonSerializable
|
@JsonSerializable
|
||||||
data class MagiskJson(
|
data class MagiskJson(
|
||||||
val version: String = "",
|
val version: String = "",
|
||||||
@ -25,12 +24,13 @@ data class MagiskJson(
|
|||||||
val link: String = "",
|
val link: String = "",
|
||||||
val note: String = "",
|
val note: String = "",
|
||||||
@Json(name = "md5") val hash: String = ""
|
@Json(name = "md5") val hash: String = ""
|
||||||
) : Parcelable
|
)
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
@JsonSerializable
|
@JsonSerializable
|
||||||
data class ManagerJson(
|
data class ManagerJson(
|
||||||
val version: String = "",
|
val version: String = "",
|
||||||
val versionCode: Int = -1,
|
val versionCode: Int = -1,
|
||||||
val link: String = "",
|
val link: String = "",
|
||||||
val note: String = ""
|
val note: String = ""
|
||||||
)
|
) : Parcelable
|
||||||
|
@ -16,6 +16,15 @@ sealed class Configuration : Parcelable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class APK : Configuration() {
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
object Upgrade : APK()
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
object Restore : APK()
|
||||||
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
object Download : Configuration()
|
object Download : Configuration()
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import com.topjohnwu.magisk.Info
|
|||||||
import com.topjohnwu.magisk.extensions.cachedFile
|
import com.topjohnwu.magisk.extensions.cachedFile
|
||||||
import com.topjohnwu.magisk.extensions.get
|
import com.topjohnwu.magisk.extensions.get
|
||||||
import com.topjohnwu.magisk.model.entity.MagiskJson
|
import com.topjohnwu.magisk.model.entity.MagiskJson
|
||||||
|
import com.topjohnwu.magisk.model.entity.ManagerJson
|
||||||
import com.topjohnwu.magisk.model.entity.module.Repo
|
import com.topjohnwu.magisk.model.entity.module.Repo
|
||||||
import kotlinx.android.parcel.IgnoredOnParcel
|
import kotlinx.android.parcel.IgnoredOnParcel
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
@ -20,8 +21,8 @@ sealed class DownloadSubject : Parcelable {
|
|||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class Module(
|
data class Module(
|
||||||
val module: Repo,
|
val module: Repo,
|
||||||
val configuration: Configuration
|
val configuration: Configuration
|
||||||
) : DownloadSubject() {
|
) : DownloadSubject() {
|
||||||
override val url: String get() = module.zipUrl
|
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<Context>().cachedFile("manager.apk")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sealed class Magisk : DownloadSubject() {
|
sealed class Magisk : DownloadSubject() {
|
||||||
|
|
||||||
abstract val configuration: Configuration
|
abstract val configuration: Configuration
|
||||||
|
@ -11,8 +11,11 @@ import com.topjohnwu.magisk.data.database.PolicyDao
|
|||||||
import com.topjohnwu.magisk.data.database.base.su
|
import com.topjohnwu.magisk.data.database.base.su
|
||||||
import com.topjohnwu.magisk.extensions.inject
|
import com.topjohnwu.magisk.extensions.inject
|
||||||
import com.topjohnwu.magisk.extensions.reboot
|
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.ui.surequest.SuRequestActivity
|
||||||
import com.topjohnwu.magisk.utils.DownloadApp
|
|
||||||
import com.topjohnwu.magisk.utils.SuLogger
|
import com.topjohnwu.magisk.utils.SuLogger
|
||||||
import com.topjohnwu.magisk.view.Notifications
|
import com.topjohnwu.magisk.view.Notifications
|
||||||
import com.topjohnwu.magisk.view.Shortcuts
|
import com.topjohnwu.magisk.view.Shortcuts
|
||||||
@ -73,9 +76,12 @@ open class GeneralReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context)
|
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setup(context)
|
||||||
Const.Key.BROADCAST_MANAGER_UPDATE -> {
|
Const.Key.BROADCAST_MANAGER_UPDATE -> {
|
||||||
Info.remote = Info.remote.copy(app = Info.remote.app.copy(
|
intent.getParcelableExtra<ManagerJson>(Const.Key.INTENT_SET_APP)?.let {
|
||||||
link = intent.getStringExtra(Const.Key.INTENT_SET_LINK) ?: ""))
|
Info.remote = Info.remote.copy(app = it)
|
||||||
DownloadApp.upgrade(intent.getStringExtra(Const.Key.INTENT_SET_NAME))
|
}
|
||||||
|
DownloadService(context) {
|
||||||
|
subject = DownloadSubject.Manager(Configuration.APK.Upgrade)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Const.Key.BROADCAST_REBOOT -> reboot()
|
Const.Key.BROADCAST_REBOOT -> reboot()
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,15 @@ import com.topjohnwu.magisk.Const
|
|||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.data.database.RepoDao
|
import com.topjohnwu.magisk.data.database.RepoDao
|
||||||
import com.topjohnwu.magisk.databinding.CustomDownloadDialogBinding
|
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.model.observer.Observer
|
||||||
import com.topjohnwu.magisk.ui.base.BasePreferenceFragment
|
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.magisk.view.dialogs.FingerprintAuthDialog
|
||||||
import com.topjohnwu.net.Networking
|
import com.topjohnwu.net.Networking
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
@ -71,7 +77,9 @@ class SettingsFragment : BasePreferenceFragment() {
|
|||||||
}
|
}
|
||||||
val restoreManager = findPreference("restore")
|
val restoreManager = findPreference("restore")
|
||||||
restoreManager.setOnPreferenceClickListener {
|
restoreManager.setOnPreferenceClickListener {
|
||||||
DownloadApp.restore()
|
DownloadService(requireContext()) {
|
||||||
|
subject = DownloadSubject.Manager(Configuration.APK.Restore)
|
||||||
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
findPreference("clear").setOnPreferenceClickListener {
|
findPreference("clear").setOnPreferenceClickListener {
|
||||||
|
@ -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<File> {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,7 +18,6 @@ import com.topjohnwu.magisk.Info;
|
|||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.model.receiver.GeneralReceiver;
|
import com.topjohnwu.magisk.model.receiver.GeneralReceiver;
|
||||||
import com.topjohnwu.magisk.ui.SplashActivity;
|
import com.topjohnwu.magisk.ui.SplashActivity;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
|
||||||
|
|
||||||
public class Notifications {
|
public class Notifications {
|
||||||
|
|
||||||
@ -61,13 +60,11 @@ public class Notifications {
|
|||||||
|
|
||||||
public static void managerUpdate() {
|
public static void managerUpdate() {
|
||||||
App app = App.self;
|
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 intent = new Intent(app, ClassMap.get(GeneralReceiver.class));
|
||||||
intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE);
|
intent.setAction(Const.Key.BROADCAST_MANAGER_UPDATE);
|
||||||
intent.putExtra(Const.Key.INTENT_SET_LINK, Info.remote.getApp().getLink());
|
intent.putExtra(Const.Key.INTENT_SET_APP, Info.remote.getApp());
|
||||||
intent.putExtra(Const.Key.INTENT_SET_NAME, name);
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
|
PendingIntent pendingIntent = PendingIntent.getBroadcast(app,
|
||||||
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
|
@ -3,18 +3,21 @@ package com.topjohnwu.magisk.view.dialogs
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import com.topjohnwu.magisk.Info
|
import com.topjohnwu.magisk.Info
|
||||||
import com.topjohnwu.magisk.R
|
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
|
import com.topjohnwu.magisk.view.MarkDownWindow
|
||||||
|
|
||||||
class ManagerInstallDialog(a: Activity) : CustomAlertDialog(a) {
|
class ManagerInstallDialog(a: Activity) : CustomAlertDialog(a) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val name = "MagiskManager v${Info.remote.app.version}" +
|
val subject = DownloadSubject.Manager(Configuration.APK.Upgrade)
|
||||||
"(${Info.remote.app.versionCode})"
|
|
||||||
setTitle(a.getString(R.string.repo_install_title, a.getString(R.string.app_name)))
|
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)
|
setCancelable(true)
|
||||||
setPositiveButton(R.string.install) { _, _ -> DownloadApp.upgrade(name) }
|
setPositiveButton(R.string.install) { _, _ ->
|
||||||
|
DownloadService(a) { this.subject = subject }
|
||||||
|
}
|
||||||
if (Info.remote.app.note.isNotEmpty()) {
|
if (Info.remote.app.note.isNotEmpty()) {
|
||||||
setNeutralButton(R.string.app_changelog) { _, _ ->
|
setNeutralButton(R.string.app_changelog) { _, _ ->
|
||||||
MarkDownWindow.show(a, null, Info.remote.app.note) }
|
MarkDownWindow.show(a, null, Info.remote.app.note) }
|
||||||
|
@ -9,6 +9,10 @@ import java.io.File;
|
|||||||
|
|
||||||
public class APKInstall {
|
public class APKInstall {
|
||||||
public static void install(Context c, File apk) {
|
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);
|
Intent install = new Intent(Intent.ACTION_INSTALL_PACKAGE);
|
||||||
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
@ -18,6 +22,6 @@ public class APKInstall {
|
|||||||
apk.setReadable(true, false);
|
apk.setReadable(true, false);
|
||||||
install.setData(Uri.fromFile(apk));
|
install.setData(Uri.fromFile(apk));
|
||||||
}
|
}
|
||||||
c.startActivity(install);
|
return install;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user