mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 02:25:28 +00:00
parent
7e133b0cf4
commit
01efe7a4ea
@ -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
|
|||||||
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() {
|
|||||||
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
|
|||||||
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.*
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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
|
|||||||
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)
|
|
||||||
return
|
|
||||||
|
|
||||||
update(id) {
|
|
||||||
it.setProgress(0, 0, true)
|
|
||||||
.setProgress(0, 0, true)
|
|
||||||
.setContentTitle(getString(R.string.hide_manager_title))
|
|
||||||
.setContentText("")
|
|
||||||
}
|
|
||||||
val patched = File(apk.parent, "patched.apk")
|
val patched = File(apk.parent, "patched.apk")
|
||||||
PatchAPK.patch(apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
|
PatchAPK.patch(apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
|
||||||
apk.delete()
|
apk.delete()
|
||||||
patched.renameTo(apk)
|
patched.renameTo(apk)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun DownloadService.upgrade(apk: File, id: Int) {
|
private fun BaseDownloader.notifyHide(id: Int) {
|
||||||
|
update(id) {
|
||||||
|
it.setProgress(0, 0, true)
|
||||||
|
.setContentTitle(getString(R.string.hide_manager_title))
|
||||||
|
.setContentText("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
|||||||
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
|
|||||||
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 {
|
|||||||
|
|
||||||
@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 {
|
|||||||
|
|
||||||
@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 {
|
|||||||
|
|
||||||
@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(
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
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>() {
|
|||||||
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
|
|||||||
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
|
|||||||
|
|
||||||
// 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(
|
|||||||
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
|
|||||||
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>
|
|||||||
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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user