Commit 01efe7a4 authored by topjohnwu's avatar topjohnwu

100% functional manager self upgrade

Fix #2929
parent 7e133b0c
...@@ -64,14 +64,6 @@ object Const { ...@@ -64,14 +64,6 @@ 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 OPEN_SETTINGS = "settings"
const val INTENT_SET_APP = "app_json"
const val FLASH_INSTALLER = "installer"
const val FLASH_ACTION = "action"
const val FLASH_DATA = "additional_data"
const val DISMISS_ID = "dismiss_id"
const val BROADCAST_MANAGER_UPDATE = "manager_update"
const val BROADCAST_REBOOT = "reboot"
} }
object Value { object Value {
......
...@@ -3,13 +3,8 @@ package com.topjohnwu.magisk.core ...@@ -3,13 +3,8 @@ package com.topjohnwu.magisk.core
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.Intent import android.content.Intent
import com.topjohnwu.magisk.core.base.BaseReceiver import com.topjohnwu.magisk.core.base.BaseReceiver
import com.topjohnwu.magisk.core.download.Action
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.magiskdb.PolicyDao import com.topjohnwu.magisk.core.magiskdb.PolicyDao
import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.core.su.SuCallbackHandler import com.topjohnwu.magisk.core.su.SuCallbackHandler
import com.topjohnwu.magisk.ktx.reboot
import com.topjohnwu.magisk.view.Shortcuts import com.topjohnwu.magisk.view.Shortcuts
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
...@@ -46,15 +41,6 @@ open class GeneralReceiver : BaseReceiver() { ...@@ -46,15 +41,6 @@ open class GeneralReceiver : BaseReceiver() {
Shell.su("magiskhide --rm $pkg").submit() Shell.su("magiskhide --rm $pkg").submit()
} }
Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context) Intent.ACTION_LOCALE_CHANGED -> Shortcuts.setupDynamic(context)
Const.Key.BROADCAST_MANAGER_UPDATE -> {
intent.getParcelableExtra<ManagerJson>(Const.Key.INTENT_SET_APP)?.let {
Info.remote = Info.remote.copy(app = it)
}
DownloadService(context) {
subject = Subject.Manager(Action.APK.Upgrade)
}
}
Const.Key.BROADCAST_REBOOT -> reboot()
} }
} }
} }
...@@ -13,7 +13,6 @@ import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream ...@@ -13,7 +13,6 @@ import com.topjohnwu.magisk.core.utils.MediaStoreUtils.outputStream
import com.topjohnwu.magisk.core.utils.ProgressInputStream import com.topjohnwu.magisk.core.utils.ProgressInputStream
import com.topjohnwu.magisk.data.network.GithubRawServices import com.topjohnwu.magisk.data.network.GithubRawServices
import com.topjohnwu.magisk.ktx.withStreams import com.topjohnwu.magisk.ktx.withStreams
import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.view.Notifications import com.topjohnwu.magisk.view.Notifications
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
...@@ -29,7 +28,7 @@ import java.util.* ...@@ -29,7 +28,7 @@ import java.util.*
import kotlin.collections.HashMap import kotlin.collections.HashMap
import kotlin.random.Random.Default.nextInt import kotlin.random.Random.Default.nextInt
abstract class BaseDownloadService : BaseService(), KoinComponent { abstract class BaseDownloader : BaseService(), KoinComponent {
private val hasNotifications get() = notifications.isNotEmpty() private val hasNotifications get() = notifications.isNotEmpty()
private val notifications = Collections.synchronizedMap(HashMap<Int, Notification.Builder>()) private val notifications = Collections.synchronizedMap(HashMap<Int, Notification.Builder>())
...@@ -41,8 +40,8 @@ abstract class BaseDownloadService : BaseService(), KoinComponent { ...@@ -41,8 +40,8 @@ abstract class BaseDownloadService : BaseService(), KoinComponent {
override fun onBind(intent: Intent?): IBinder? = null override fun onBind(intent: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
intent?.getParcelableExtra<Subject>(ARG_URL)?.let { subject -> intent.getParcelableExtra<Subject>(ACTION_KEY)?.let { subject ->
update(subject.notifyID()) update(subject.notifyID())
coroutineScope.launch { coroutineScope.launch {
try { try {
...@@ -76,8 +75,11 @@ abstract class BaseDownloadService : BaseService(), KoinComponent { ...@@ -76,8 +75,11 @@ abstract class BaseDownloadService : BaseService(), KoinComponent {
when (this) { when (this) {
is Subject.Module -> // Download and process on-the-fly is Subject.Module -> // Download and process on-the-fly
stream.toModule(file, service.fetchInstaller().byteStream()) stream.toModule(file, service.fetchInstaller().byteStream())
else -> else -> {
withStreams(stream, file.outputStream()) { it, out -> it.copyTo(out) } withStreams(stream, file.outputStream()) { it, out -> it.copyTo(out) }
if (this is Subject.Manager)
handleAPK(this)
}
} }
} }
val newId = notifyFinish(this) val newId = notifyFinish(this)
...@@ -124,6 +126,7 @@ abstract class BaseDownloadService : BaseService(), KoinComponent { ...@@ -124,6 +126,7 @@ abstract class BaseDownloadService : BaseService(), KoinComponent {
private fun notifyFinish(subject: Subject) = lastNotify(subject.notifyID()) { private fun notifyFinish(subject: Subject) = lastNotify(subject.notifyID()) {
broadcast(1f, subject) broadcast(1f, subject)
it.setIntent(subject) it.setIntent(subject)
.setContentTitle(subject.title)
.setContentText(getString(R.string.download_complete)) .setContentText(getString(R.string.download_complete))
.setSmallIcon(android.R.drawable.stat_sys_download_done) .setSmallIcon(android.R.drawable.stat_sys_download_done)
.setProgress(0, 0, false) .setProgress(0, 0, false)
...@@ -152,16 +155,15 @@ abstract class BaseDownloadService : BaseService(), KoinComponent { ...@@ -152,16 +155,15 @@ abstract class BaseDownloadService : BaseService(), KoinComponent {
return newId return newId
} }
private fun remove(id: Int) = notifications.remove(id)?.also { protected fun remove(id: Int) = notifications.remove(id)
updateForeground() ?.also { updateForeground(); cancel(id) }
cancel(id) ?: { cancel(id); null }()
}
private fun notify(id: Int, notification: Notification) { private fun notify(id: Int, notification: Notification) {
Notifications.mgr.notify(id, notification) Notifications.mgr.notify(id, notification)
} }
protected fun cancel(id: Int) { private fun cancel(id: Int) {
Notifications.mgr.cancel(id) Notifications.mgr.cancel(id)
} }
...@@ -178,13 +180,12 @@ abstract class BaseDownloadService : BaseService(), KoinComponent { ...@@ -178,13 +180,12 @@ abstract class BaseDownloadService : BaseService(), KoinComponent {
protected abstract suspend fun onFinish(subject: Subject, id: Int) protected abstract suspend fun onFinish(subject: Subject, id: Int)
protected abstract fun Notification.Builder.setIntent(subject: Subject) protected abstract fun Notification.Builder.setIntent(subject: Subject): Notification.Builder
: Notification.Builder
// --- // ---
companion object : KoinComponent { companion object : KoinComponent {
const val ARG_URL = "arg_url" const val ACTION_KEY = "download_action"
private val progressBroadcast = MutableLiveData<Pair<Float, Subject>>() private val progressBroadcast = MutableLiveData<Pair<Float, Subject>>()
......
...@@ -17,7 +17,7 @@ import com.topjohnwu.magisk.utils.APKInstall ...@@ -17,7 +17,7 @@ import com.topjohnwu.magisk.utils.APKInstall
import kotlin.random.Random.Default.nextInt import kotlin.random.Random.Default.nextInt
@SuppressLint("Registered") @SuppressLint("Registered")
open class DownloadService : BaseDownloadService() { open class DownloadService : BaseDownloader() {
private val context get() = this private val context get() = this
...@@ -30,7 +30,7 @@ open class DownloadService : BaseDownloadService() { ...@@ -30,7 +30,7 @@ open class DownloadService : BaseDownloadService() {
private suspend fun Magisk.onFinish(id: Int) = when (val action = action) { private suspend fun Magisk.onFinish(id: Int) = when (val action = action) {
Uninstall -> FlashFragment.uninstall(file, id) Uninstall -> FlashFragment.uninstall(file, id)
EnvFix -> { EnvFix -> {
cancel(id) remove(id)
EnvFixTask(file).exec() EnvFixTask(file).exec()
Unit Unit
} }
...@@ -44,9 +44,9 @@ open class DownloadService : BaseDownloadService() { ...@@ -44,9 +44,9 @@ open class DownloadService : BaseDownloadService() {
else -> Unit else -> Unit
} }
private suspend fun Manager.onFinish(id: Int) { private fun Manager.onFinish(id: Int) {
handleAPK(this) remove(id)
cancel(id) APKInstall.install(context, file.toFile())
} }
// --- Customize finish notification // --- Customize finish notification
...@@ -85,24 +85,29 @@ open class DownloadService : BaseDownloadService() { ...@@ -85,24 +85,29 @@ open class DownloadService : BaseDownloadService() {
// --- // ---
class Builder {
lateinit var subject: Subject
}
companion object { companion object {
inline operator fun invoke(context: Context, argBuilder: Builder.() -> Unit) { private fun intent(context: Context, subject: Subject) =
val app = context.applicationContext context.intent<DownloadService>().putExtra(ACTION_KEY, subject)
val builder = Builder().apply(argBuilder)
val intent = app.intent<DownloadService>().putExtra(ARG_URL, builder.subject)
if (Build.VERSION.SDK_INT >= 26) { fun pendingIntent(context: Context, subject: Subject): PendingIntent {
app.startForegroundService(intent) return if (Build.VERSION.SDK_INT >= 26) {
PendingIntent.getForegroundService(context, nextInt(),
intent(context, subject), PendingIntent.FLAG_UPDATE_CURRENT)
} else { } else {
app.startService(intent) PendingIntent.getService(context, nextInt(),
intent(context, subject), PendingIntent.FLAG_UPDATE_CURRENT)
} }
} }
operator fun invoke(context: Context, subject: Subject) {
val app = context.applicationContext
if (Build.VERSION.SDK_INT >= 26) {
app.startForegroundService(intent(app, subject))
} else {
app.startService(intent(app, subject))
}
}
} }
} }
package com.topjohnwu.magisk.core.download package com.topjohnwu.magisk.core.download
import android.content.Context
import androidx.core.net.toFile import androidx.core.net.toFile
import com.topjohnwu.magisk.BuildConfig import com.topjohnwu.magisk.BuildConfig
import com.topjohnwu.magisk.DynAPK import com.topjohnwu.magisk.DynAPK
...@@ -12,49 +13,48 @@ import com.topjohnwu.magisk.core.isRunningAsStub ...@@ -12,49 +13,48 @@ import com.topjohnwu.magisk.core.isRunningAsStub
import com.topjohnwu.magisk.core.utils.PatchAPK import com.topjohnwu.magisk.core.utils.PatchAPK
import com.topjohnwu.magisk.ktx.relaunchApp import com.topjohnwu.magisk.ktx.relaunchApp
import com.topjohnwu.magisk.ktx.writeTo import com.topjohnwu.magisk.ktx.writeTo
import com.topjohnwu.magisk.utils.APKInstall
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import java.io.File import java.io.File
private fun DownloadService.patch(apk: File, id: Int) { private fun Context.patch(apk: File) {
if (packageName == BuildConfig.APPLICATION_ID) val patched = File(apk.parent, "patched.apk")
return PatchAPK.patch(apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
apk.delete()
patched.renameTo(apk)
}
private fun BaseDownloader.notifyHide(id: Int) {
update(id) { update(id) {
it.setProgress(0, 0, true) it.setProgress(0, 0, true)
.setProgress(0, 0, true)
.setContentTitle(getString(R.string.hide_manager_title)) .setContentTitle(getString(R.string.hide_manager_title))
.setContentText("") .setContentText("")
} }
val patched = File(apk.parent, "patched.apk")
PatchAPK.patch(apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
apk.delete()
patched.renameTo(apk)
} }
private suspend fun DownloadService.upgrade(apk: File, id: Int) { private suspend fun BaseDownloader.upgrade(subject: Subject.Manager) {
val apk = subject.file.toFile()
val id = subject.notifyID()
if (isRunningAsStub) { if (isRunningAsStub) {
// Move to upgrade location // Move to upgrade location
apk.copyTo(DynAPK.update(this), overwrite = true) apk.copyTo(DynAPK.update(this), overwrite = true)
apk.delete() apk.delete()
if (Info.stubChk.version < Info.remote.stub.versionCode) { if (Info.stubChk.version < subject.stub.versionCode) {
// We also want to upgrade stub notifyHide(id)
service.fetchFile(Info.remote.stub.link).byteStream().use { // Also upgrade stub
it.writeTo(apk) service.fetchFile(subject.stub.link).byteStream().use { it.writeTo(apk) }
} patch(apk)
patch(apk, id)
} else { } else {
// Simply relaunch the app // Simply relaunch the app
stopSelf() stopSelf()
relaunchApp(this) relaunchApp(this)
} }
} else { } else if (packageName != BuildConfig.APPLICATION_ID) {
patch(apk, id) notifyHide(id)
patch(apk)
} }
APKInstall.install(this, apk)
} }
private fun DownloadService.restore(apk: File, id: Int) { private fun BaseDownloader.restore(apk: File, id: Int) {
update(id) { update(id) {
it.setProgress(0, 0, true) it.setProgress(0, 0, true)
.setProgress(0, 0, true) .setProgress(0, 0, true)
...@@ -65,8 +65,8 @@ private fun DownloadService.restore(apk: File, id: Int) { ...@@ -65,8 +65,8 @@ private fun DownloadService.restore(apk: File, id: Int) {
Shell.su("pm install $apk && pm uninstall $packageName").exec() Shell.su("pm install $apk && pm uninstall $packageName").exec()
} }
suspend fun DownloadService.handleAPK(subject: Subject.Manager) = suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) =
when (subject.action) { when (subject.action) {
is Upgrade -> upgrade(subject.file.toFile(), subject.notifyID()) is Upgrade -> upgrade(subject)
is Restore -> restore(subject.file.toFile(), subject.notifyID()) is Restore -> restore(subject.file.toFile(), subject.notifyID())
} }
...@@ -7,13 +7,16 @@ import androidx.core.net.toUri ...@@ -7,13 +7,16 @@ import androidx.core.net.toUri
import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.Info
import com.topjohnwu.magisk.core.model.MagiskJson import com.topjohnwu.magisk.core.model.MagiskJson
import com.topjohnwu.magisk.core.model.ManagerJson import com.topjohnwu.magisk.core.model.ManagerJson
import com.topjohnwu.magisk.core.model.StubJson
import com.topjohnwu.magisk.core.model.module.Repo import com.topjohnwu.magisk.core.model.module.Repo
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import com.topjohnwu.magisk.ktx.cachedFile import com.topjohnwu.magisk.ktx.cachedFile
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
import kotlinx.android.parcel.IgnoredOnParcel import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
private fun cachedFile(name: String) = get<Context>().cachedFile(name).apply { delete() }.toUri()
sealed class Subject : Parcelable { sealed class Subject : Parcelable {
abstract val url: String abstract val url: String
...@@ -37,21 +40,20 @@ sealed class Subject : Parcelable { ...@@ -37,21 +40,20 @@ sealed class Subject : Parcelable {
@Parcelize @Parcelize
class Manager( class Manager(
override val action: Action.APK override val action: Action.APK,
private val app: ManagerJson = Info.remote.app,
val stub: StubJson = Info.remote.stub
) : Subject() { ) : Subject() {
@IgnoredOnParcel
val manager: ManagerJson = Info.remote.app
override val title: String override val title: String
get() = "MagiskManager-${manager.version}(${manager.versionCode})" get() = "MagiskManager-${app.version}(${app.versionCode})"
override val url: String override val url: String
get() = manager.link get() = app.link
@IgnoredOnParcel @IgnoredOnParcel
override val file by lazy { override val file by lazy {
get<Context>().cachedFile("manager.apk").toUri() cachedFile("manager.apk")
} }
} }
...@@ -69,7 +71,7 @@ sealed class Subject : Parcelable { ...@@ -69,7 +71,7 @@ sealed class Subject : Parcelable {
@IgnoredOnParcel @IgnoredOnParcel
override val file by lazy { override val file by lazy {
get<Context>().cachedFile("magisk.zip").toUri() cachedFile("magisk.zip")
} }
} }
...@@ -81,7 +83,7 @@ sealed class Subject : Parcelable { ...@@ -81,7 +83,7 @@ sealed class Subject : Parcelable {
@IgnoredOnParcel @IgnoredOnParcel
override val file by lazy { override val file by lazy {
get<Context>().cachedFile(title).toUri() cachedFile(title)
} }
} }
......
...@@ -35,8 +35,9 @@ data class ManagerJson( ...@@ -35,8 +35,9 @@ data class ManagerJson(
val note: String = "" val note: String = ""
) : Parcelable ) : Parcelable
@Parcelize
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class StubJson( data class StubJson(
val versionCode: Int = -1, val versionCode: Int = -1,
val link: String = "" val link: String = ""
) ) : Parcelable
...@@ -31,7 +31,7 @@ class EnvFixDialog : DialogEvent() { ...@@ -31,7 +31,7 @@ class EnvFixDialog : DialogEvent() {
lbm.unregisterReceiver(this) lbm.unregisterReceiver(this)
} }
}, IntentFilter(DISMISS)) }, IntentFilter(DISMISS))
DownloadService(dialog.context) { subject = Magisk(EnvFix) } DownloadService(dialog.context, Magisk(EnvFix))
} }
} }
.applyButton(MagiskDialog.ButtonType.NEGATIVE) { .applyButton(MagiskDialog.ButtonType.NEGATIVE) {
......
...@@ -25,7 +25,7 @@ class ManagerInstallDialog : DialogEvent() { ...@@ -25,7 +25,7 @@ class ManagerInstallDialog : DialogEvent() {
applyButton(MagiskDialog.ButtonType.POSITIVE) { applyButton(MagiskDialog.ButtonType.POSITIVE) {
titleRes = R.string.install titleRes = R.string.install
onClick { DownloadService(context) { this.subject = subject } } onClick { DownloadService(context, subject) }
} }
if (Info.remote.app.note.isEmpty()) return if (Info.remote.app.note.isEmpty()) return
......
...@@ -12,9 +12,10 @@ class ModuleInstallDialog(private val item: Repo) : DialogEvent() { ...@@ -12,9 +12,10 @@ class ModuleInstallDialog(private val item: Repo) : DialogEvent() {
override fun build(dialog: MagiskDialog) { override fun build(dialog: MagiskDialog) {
with(dialog) { with(dialog) {
fun download(install: Boolean) = DownloadService(context) { fun download(install: Boolean) {
val config = if (install) Action.Flash.Primary else Action.Download val config = if (install) Action.Flash.Primary else Action.Download
subject = Subject.Module(item, config) val subject = Subject.Module(item, config)
DownloadService(context, subject)
} }
applyTitle(context.getString(R.string.repo_install_title, item.name)) applyTitle(context.getString(R.string.repo_install_title, item.name))
......
...@@ -47,9 +47,7 @@ class UninstallDialog : DialogEvent() { ...@@ -47,9 +47,7 @@ class UninstallDialog : DialogEvent() {
} }
private fun completeUninstall() { private fun completeUninstall() {
DownloadService(dialog.context) { DownloadService(dialog.context, Subject.Magisk(Action.Uninstall))
subject = Subject.Magisk(Action.Uninstall)
}
} }
} }
...@@ -4,7 +4,7 @@ import android.os.Bundle ...@@ -4,7 +4,7 @@ import android.os.Bundle
import android.view.* import android.view.*
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.core.download.BaseDownloadService import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding import com.topjohnwu.magisk.databinding.FragmentHomeMd2Binding
import com.topjohnwu.magisk.events.RebootEvent import com.topjohnwu.magisk.events.RebootEvent
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
...@@ -19,7 +19,7 @@ class HomeFragment : BaseUIFragment<HomeViewModel, FragmentHomeMd2Binding>() { ...@@ -19,7 +19,7 @@ class HomeFragment : BaseUIFragment<HomeViewModel, FragmentHomeMd2Binding>() {
super.onStart() super.onStart()
activity.title = resources.getString(R.string.section_home) activity.title = resources.getString(R.string.section_home)
setHasOptionsMenu(true) setHasOptionsMenu(true)
BaseDownloadService.observeProgress(this, viewModel::onProgressUpdate) BaseDownloader.observeProgress(this, viewModel::onProgressUpdate)
} }
override fun onCreateView( override fun onCreateView(
......
...@@ -4,7 +4,7 @@ import android.content.Intent ...@@ -4,7 +4,7 @@ import android.content.Intent
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.core.download.BaseDownloadService import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding import com.topjohnwu.magisk.databinding.FragmentInstallMd2Binding
import com.topjohnwu.magisk.events.RequestFileEvent import com.topjohnwu.magisk.events.RequestFileEvent
import com.topjohnwu.magisk.ktx.coroutineScope import com.topjohnwu.magisk.ktx.coroutineScope
...@@ -26,7 +26,7 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi ...@@ -26,7 +26,7 @@ class InstallFragment : BaseUIFragment<InstallViewModel, FragmentInstallMd2Bindi
// Allow markwon to run in viewmodel scope // Allow markwon to run in viewmodel scope
binding.releaseNotes.coroutineScope = viewModel.viewModelScope binding.releaseNotes.coroutineScope = viewModel.viewModelScope
BaseDownloadService.observeProgress(this, viewModel::onProgressUpdate) BaseDownloader.observeProgress(this, viewModel::onProgressUpdate)
} }
} }
...@@ -78,17 +78,16 @@ class InstallViewModel( ...@@ -78,17 +78,16 @@ class InstallViewModel(
step = nextStep step = nextStep
} }
fun install() = DownloadService(get()) { fun install() =
subject = Subject.Magisk(resolveConfiguration()) DownloadService(get(), Subject.Magisk(resolveAction())).also { state = State.LOADING }
}.also { state = State.LOADING }
// --- // ---
private fun resolveConfiguration() = when (method) { private fun resolveAction() = when (method) {
R.id.method_download -> Action.Download R.id.method_download -> Action.Download
R.id.method_patch -> Action.Patch(data!!) R.id.method_patch -> Action.Patch(data!!)
R.id.method_direct -> Action.Flash.Primary R.id.method_direct -> Action.Flash.Primary
R.id.method_inactive_slot -> Action.Flash.Secondary R.id.method_inactive_slot -> Action.Flash.Secondary
else -> throw IllegalArgumentException("Unknown value") else -> error("Unknown value")
} }
} }
...@@ -12,7 +12,7 @@ import com.topjohnwu.magisk.R ...@@ -12,7 +12,7 @@ import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.arch.BaseUIFragment import com.topjohnwu.magisk.arch.BaseUIFragment
import com.topjohnwu.magisk.arch.ReselectionTarget import com.topjohnwu.magisk.arch.ReselectionTarget
import com.topjohnwu.magisk.arch.ViewEvent import com.topjohnwu.magisk.arch.ViewEvent
import com.topjohnwu.magisk.core.download.BaseDownloadService import com.topjohnwu.magisk.core.download.BaseDownloader
import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding import com.topjohnwu.magisk.databinding.FragmentModuleMd2Binding
import com.topjohnwu.magisk.events.InstallExternalModuleEvent import com.topjohnwu.magisk.events.InstallExternalModuleEvent
import com.topjohnwu.magisk.ktx.hideKeyboard import com.topjohnwu.magisk.ktx.hideKeyboard
...@@ -51,7 +51,7 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding> ...@@ -51,7 +51,7 @@ class ModuleFragment : BaseUIFragment<ModuleViewModel, FragmentModuleMd2Binding>
super.onStart() super.onStart()
setHasOptionsMenu(true) setHasOptionsMenu(true)
activity.title = resources.getString(R.string.modules) activity.title = resources.getString(R.string.modules)
BaseDownloadService.observeProgress(this, viewModel::onProgressUpdate) BaseDownloader.observeProgress(this, viewModel::onProgressUpdate)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
......
...@@ -145,9 +145,7 @@ class SettingsViewModel( ...@@ -145,9 +145,7 @@ class SettingsViewModel(
} }
private fun restoreManager() { private fun restoreManager() {
DownloadService(get()) { DownloadService(get(), Subject.Manager(Action.APK.Restore))
subject = Subject.Manager(Action.APK.Restore)
}
} }
} }
...@@ -10,9 +10,15 @@ import androidx.core.app.TaskStackBuilder ...@@ -10,9 +10,15 @@ import androidx.core.app.TaskStackBuilder
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.graphics.drawable.toIcon import androidx.core.graphics.drawable.toIcon
import com.topjohnwu.magisk.R import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.core.* import com.topjohnwu.magisk.core.Const
import com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL import com.topjohnwu.magisk.core.Const.ID.PROGRESS_NOTIFICATION_CHANNEL
import com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL import com.topjohnwu.magisk.core.Const.ID.UPDATE_NOTIFICATION_CHANNEL
import com.topjohnwu.magisk.core.SplashActivity
import com.topjohnwu.magisk.core.cmp
import com.topjohnwu.magisk.core.download.Action
import com.topjohnwu.magisk.core.download.DownloadService
import com.topjohnwu.magisk.core.download.Subject
import com.topjohnwu.magisk.core.intent
import com.topjohnwu.magisk.ktx.get import com.topjohnwu.magisk.ktx.get
import com.topjohnwu.magisk.ktx.getBitmap import com.topjohnwu.magisk.ktx.getBitmap
...@@ -52,12 +58,9 @@ object Notifications { ...@@ -52,12 +58,9 @@ object Notifications {
stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName)) stackBuilder.addParentStack(SplashActivity::class.java.cmp(context.packageName))
stackBuilder.addNextIntent(intent) stackBuilder.addNextIntent(intent)
val pendingIntent = stackBuilder.getPendingIntent( val pendingIntent = stackBuilder.getPendingIntent(
Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, Const.ID.MAGISK_UPDATE_NOTIFICATION_ID, PendingIntent.FLAG_UPDATE_CURRENT)
PendingIntent.FLAG_UPDATE_CURRENT)
val builder = updateBuilder( val builder = updateBuilder(context)
context
)
.setContentTitle(context.getString(R.string.magisk_update_title)) .setContentTitle(context.getString(R.string.magisk_update_title))
.setContentText(context.getString(R.string.manager_download_install)) .setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true) .setAutoCancel(true)
...@@ -67,20 +70,13 @@ object Notifications { ...@@ -67,20 +70,13 @@ object Notifications {
} }
fun managerUpdate(context: Context) { fun managerUpdate(context: Context) {
val intent = context.intent<GeneralReceiver>() val intent = DownloadService.pendingIntent(context, Subject.Manager(Action.APK.Upgrade))
.setAction(Const.Key.BROADCAST_MANAGER_UPDATE)
.putExtra(Const.Key.INTENT_SET_APP, Info.remote.app)
val pendingIntent = PendingIntent.getBroadcast(context, val builder = updateBuilder(context)
Const.ID.APK_UPDATE_NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val builder = updateBuilder(
context
)
.setContentTitle(context.getString(R.string.manager_update_title)) .setContentTitle(context.getString(R.string.manager_update_title))
.setContentText(context.getString(R.string.manager_download_install)) .setContentText(context.getString(R.string.manager_download_install))
.setAutoCancel(true) .setAutoCancel(true)
.setContentIntent(pendingIntent) .setContentIntent(intent)
mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build()) mgr.notify(Const.ID.APK_UPDATE_NOTIFICATION_ID, builder.build())
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment