Better stub hiding experience
This commit is contained in:
parent
aaaaa3d044
commit
2e4dc91b96
@ -1,5 +1,6 @@
|
||||
package com.topjohnwu.magisk.core
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Xml
|
||||
@ -9,19 +10,16 @@ import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.core.magiskdb.SettingsDao
|
||||
import com.topjohnwu.magisk.core.magiskdb.StringDao
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.core.utils.defaultLocale
|
||||
import com.topjohnwu.magisk.core.utils.refreshLocale
|
||||
import com.topjohnwu.magisk.data.preference.PreferenceModel
|
||||
import com.topjohnwu.magisk.data.repository.DBConfig
|
||||
import com.topjohnwu.magisk.di.Protected
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.ktx.inject
|
||||
import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.io.SuFile
|
||||
import com.topjohnwu.superuser.io.SuFileInputStream
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
|
||||
object Config : PreferenceModel, DBConfig {
|
||||
|
||||
@ -29,6 +27,15 @@ object Config : PreferenceModel, DBConfig {
|
||||
override val settingsDao: SettingsDao by inject()
|
||||
override val context: Context by inject(Protected)
|
||||
|
||||
@get:SuppressLint("ApplySharedPref")
|
||||
val prefsFile: File get() {
|
||||
// Flush prefs to disk
|
||||
prefs.edit().apply {
|
||||
remove(Key.ASKED_HOME)
|
||||
}.commit()
|
||||
return File("${context.filesDir.parent}/shared_prefs", "${fileName}.xml")
|
||||
}
|
||||
|
||||
object Key {
|
||||
// db configs
|
||||
const val ROOT_ACCESS = "root_access"
|
||||
@ -119,7 +126,7 @@ object Config : PreferenceModel, DBConfig {
|
||||
var repoOrder by preference(Key.REPO_ORDER, Value.ORDER_DATE)
|
||||
|
||||
var suDefaultTimeout by preferenceStrInt(Key.SU_REQUEST_TIMEOUT, 10)
|
||||
var suAutoReponse by preferenceStrInt(Key.SU_AUTO_RESPONSE, Value.SU_PROMPT)
|
||||
var suAutoResponse by preferenceStrInt(Key.SU_AUTO_RESPONSE, Value.SU_PROMPT)
|
||||
var suNotification by preferenceStrInt(Key.SU_NOTIFICATION, Value.NOTIFICATION_TOAST)
|
||||
var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel)
|
||||
|
||||
@ -150,8 +157,12 @@ object Config : PreferenceModel, DBConfig {
|
||||
|
||||
private const val SU_FINGERPRINT = "su_fingerprint"
|
||||
|
||||
fun initialize() {
|
||||
prefs.edit { parsePrefs() }
|
||||
fun load(pkg: String) {
|
||||
try {
|
||||
context.contentResolver.openInputStream(Provider.PREFS_URI(pkg))?.use {
|
||||
prefs.edit { parsePrefs(it) }
|
||||
}
|
||||
} catch (e: IOException) {}
|
||||
|
||||
prefs.edit {
|
||||
// Settings migration
|
||||
@ -173,10 +184,8 @@ object Config : PreferenceModel, DBConfig {
|
||||
}
|
||||
}
|
||||
|
||||
private fun SharedPreferences.Editor.parsePrefs() {
|
||||
val config = SuFile.open("/data/adb", Const.MANAGER_CONFIGS)
|
||||
if (config.exists()) runCatching {
|
||||
val input = SuFileInputStream(config)
|
||||
private fun SharedPreferences.Editor.parsePrefs(input: InputStream) {
|
||||
runCatching {
|
||||
val parser = Xml.newPullParser()
|
||||
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
|
||||
parser.setInput(input, "UTF-8")
|
||||
@ -220,21 +229,6 @@ object Config : PreferenceModel, DBConfig {
|
||||
else -> parser.next()
|
||||
}
|
||||
}
|
||||
config.delete()
|
||||
}
|
||||
}
|
||||
|
||||
fun export() {
|
||||
// Flush prefs to disk
|
||||
prefs.edit().apply {
|
||||
remove(Key.ASKED_HOME)
|
||||
}.commit()
|
||||
val context = get<Context>(Protected)
|
||||
val xml = File(
|
||||
"${context.filesDir.parent}/shared_prefs",
|
||||
"${context.packageName}_preferences.xml"
|
||||
)
|
||||
Shell.su("cat $xml > /data/adb/${Const.MANAGER_CONFIGS}").exec()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,7 +46,6 @@ object Const {
|
||||
}
|
||||
|
||||
object Url {
|
||||
const val ZIP_URL = "https://github.com/Magisk-Modules-Repo/%s/archive/master.zip"
|
||||
const val PATREON_URL = "https://www.patreon.com/topjohnwu"
|
||||
const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk"
|
||||
|
||||
@ -58,11 +57,9 @@ object Const {
|
||||
}
|
||||
|
||||
object Key {
|
||||
// others
|
||||
const val LINK_KEY = "Link"
|
||||
const val ETAG_KEY = "ETag"
|
||||
// intents
|
||||
const val OPEN_SECTION = "section"
|
||||
const val HIDDEN_PKG = "hidden_pkg"
|
||||
}
|
||||
|
||||
object Value {
|
||||
|
@ -2,9 +2,13 @@ package com.topjohnwu.magisk.core
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ProviderInfo
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.ParcelFileDescriptor
|
||||
import android.os.ParcelFileDescriptor.MODE_READ_ONLY
|
||||
import com.topjohnwu.magisk.FileProvider
|
||||
import com.topjohnwu.magisk.core.su.SuCallbackHandler
|
||||
import java.io.File
|
||||
|
||||
open class Provider : FileProvider() {
|
||||
|
||||
@ -16,4 +20,20 @@ open class Provider : FileProvider() {
|
||||
SuCallbackHandler(context!!, method, extras)
|
||||
return Bundle.EMPTY
|
||||
}
|
||||
|
||||
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
|
||||
return when (uri.encodedPath ?: return null) {
|
||||
"/apk_file" -> ParcelFileDescriptor.open(File(context!!.packageCodePath), MODE_READ_ONLY)
|
||||
"/prefs_file" -> ParcelFileDescriptor.open(Config.prefsFile, MODE_READ_ONLY)
|
||||
else -> super.openFile(uri, mode)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun APK_URI(pkg: String) =
|
||||
Uri.Builder().scheme("content").authority("$pkg.provider").path("apk_file").build()
|
||||
|
||||
fun PREFS_URI(pkg: String) =
|
||||
Uri.Builder().scheme("content").authority("$pkg.provider").path("prefs_file").build()
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ package com.topjohnwu.magisk.core
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.data.network.RawServices
|
||||
import com.topjohnwu.magisk.data.repository.NetworkService
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.ui.MainActivity
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
@ -29,18 +29,18 @@ open class SplashActivity : Activity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRepackage() {
|
||||
val pkg = Config.suManager
|
||||
if (Config.suManager.isNotEmpty() && packageName == BuildConfig.APPLICATION_ID) {
|
||||
Config.suManager = ""
|
||||
Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
if (pkg == packageName) {
|
||||
private fun handleRepackage(pkg: String?) {
|
||||
if (packageName != APPLICATION_ID) {
|
||||
runCatching {
|
||||
// We are the manager, remove com.topjohnwu.magisk as it could be malware
|
||||
packageManager.getApplicationInfo(BuildConfig.APPLICATION_ID, 0)
|
||||
Shell.su("(pm uninstall ${BuildConfig.APPLICATION_ID})& >/dev/null 2>&1").exec()
|
||||
// Hidden, remove com.topjohnwu.magisk if exist as it could be malware
|
||||
packageManager.getApplicationInfo(APPLICATION_ID, 0)
|
||||
Shell.su("(pm uninstall $APPLICATION_ID)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
} else {
|
||||
if (Config.suManager.isNotEmpty())
|
||||
Config.suManager = ""
|
||||
pkg ?: return
|
||||
Shell.su("(pm uninstall $pkg)& >/dev/null 2>&1").exec()
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,14 +48,16 @@ open class SplashActivity : Activity() {
|
||||
// Pre-initialize root shell
|
||||
Shell.getShell()
|
||||
|
||||
Config.initialize()
|
||||
handleRepackage()
|
||||
val hiddenPackage = intent.getStringExtra(Const.Key.HIDDEN_PKG)
|
||||
|
||||
Config.load(hiddenPackage ?: APPLICATION_ID)
|
||||
handleRepackage(hiddenPackage)
|
||||
Notifications.setup(this)
|
||||
UpdateCheckService.schedule(this)
|
||||
Shortcuts.setupDynamic(this)
|
||||
|
||||
// Pre-fetch network stuffs
|
||||
get<RawServices>()
|
||||
// Pre-fetch network services
|
||||
get<NetworkService>()
|
||||
|
||||
DONE = true
|
||||
|
||||
|
@ -69,8 +69,8 @@ abstract class BaseDownloader : BaseService(), KoinComponent {
|
||||
// -- Download logic
|
||||
|
||||
private suspend fun Subject.startDownload() {
|
||||
val skip = this is Subject.Magisk && file.checkSum("MD5", magisk.md5)
|
||||
if (!skip) {
|
||||
val skipDl = this is Subject.Magisk && file.checkSum("MD5", magisk.md5)
|
||||
if (!skipDl) {
|
||||
val stream = service.fetchFile(url).toProgressStream(this)
|
||||
when (this) {
|
||||
is Subject.Module -> // Download and process on-the-fly
|
||||
|
@ -5,20 +5,16 @@ import androidx.core.net.toFile
|
||||
import com.topjohnwu.magisk.BuildConfig
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.download.Action.APK.Restore
|
||||
import com.topjohnwu.magisk.core.download.Action.APK.Upgrade
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.tasks.PatchAPK
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.ktx.relaunchApp
|
||||
import com.topjohnwu.magisk.ktx.writeTo
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.File
|
||||
|
||||
private fun Context.patch(apk: File) {
|
||||
val patched = File(apk.parent, "patched.apk")
|
||||
PatchAPK.patch(this, apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
|
||||
HideAPK.patch(this, apk.path, patched.path, packageName, applicationInfo.nonLocalizedLabel)
|
||||
apk.delete()
|
||||
patched.renameTo(apk)
|
||||
}
|
||||
@ -31,7 +27,7 @@ private fun BaseDownloader.notifyHide(id: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun BaseDownloader.upgrade(subject: Subject.Manager) {
|
||||
suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) {
|
||||
val apk = subject.file.toFile()
|
||||
val id = subject.notifyID()
|
||||
if (isRunningAsStub) {
|
||||
@ -53,20 +49,3 @@ private suspend fun BaseDownloader.upgrade(subject: Subject.Manager) {
|
||||
patch(apk)
|
||||
}
|
||||
}
|
||||
|
||||
private fun BaseDownloader.restore(apk: File, id: Int) {
|
||||
update(id) {
|
||||
it.setProgress(0, 0, true)
|
||||
.setProgress(0, 0, true)
|
||||
.setContentTitle(getString(R.string.restore_img_msg))
|
||||
.setContentText("")
|
||||
}
|
||||
Config.export()
|
||||
Shell.su("pm install $apk && pm uninstall $packageName").exec()
|
||||
}
|
||||
|
||||
suspend fun BaseDownloader.handleAPK(subject: Subject.Manager) =
|
||||
when (subject.action) {
|
||||
is Upgrade -> upgrade(subject)
|
||||
is Restore -> restore(subject.file.toFile(), subject.notifyID())
|
||||
}
|
||||
|
@ -40,16 +40,12 @@ sealed class Subject : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
class Manager(
|
||||
override val action: Action.APK,
|
||||
private val app: ManagerJson = Info.remote.app,
|
||||
val stub: StubJson = Info.remote.stub
|
||||
) : Subject() {
|
||||
|
||||
override val title: String
|
||||
get() = "MagiskManager-${app.version}(${app.versionCode})"
|
||||
|
||||
override val url: String
|
||||
get() = app.link
|
||||
override val action get() = Action.Download
|
||||
override val title: String get() = "MagiskManager-${app.version}(${app.versionCode})"
|
||||
override val url: String get() = app.link
|
||||
|
||||
@IgnoredOnParcel
|
||||
override val file by lazy {
|
||||
|
@ -36,7 +36,7 @@ class SuRequestHandler(
|
||||
if (policy.packageName == BuildConfig.APPLICATION_ID)
|
||||
return false
|
||||
|
||||
when (Config.suAutoReponse) {
|
||||
when (Config.suAutoResponse) {
|
||||
Config.Value.SU_AUTO_DENY -> {
|
||||
respond(SuPolicy.DENY, 0)
|
||||
return false
|
||||
|
@ -1,20 +1,20 @@
|
||||
package com.topjohnwu.magisk.core.tasks
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.BuildConfig.APPLICATION_ID
|
||||
import com.topjohnwu.magisk.DynAPK
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.*
|
||||
import com.topjohnwu.magisk.core.utils.AXML
|
||||
import com.topjohnwu.magisk.core.utils.Keygen
|
||||
import com.topjohnwu.magisk.data.repository.NetworkService
|
||||
import com.topjohnwu.magisk.ktx.get
|
||||
import com.topjohnwu.magisk.ktx.inject
|
||||
import com.topjohnwu.magisk.ktx.writeTo
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.signing.JarMap
|
||||
import com.topjohnwu.signing.SignApk
|
||||
import com.topjohnwu.superuser.Shell
|
||||
@ -28,18 +28,20 @@ import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
|
||||
object PatchAPK {
|
||||
object HideAPK {
|
||||
|
||||
private const val ALPHA = "abcdefghijklmnopqrstuvwxyz"
|
||||
private const val ALPHADOTS = "$ALPHA....."
|
||||
|
||||
private const val APP_ID = "com.topjohnwu.magisk"
|
||||
private const val APP_NAME = "Magisk Manager"
|
||||
|
||||
// Some arbitrary limit
|
||||
const val MAX_LABEL_LENGTH = 32
|
||||
|
||||
private fun genPackageName(): CharSequence {
|
||||
private val svc: NetworkService by inject()
|
||||
private val Context.APK_URI get() = Provider.APK_URI(packageName)
|
||||
private val Context.PREFS_URI get() = Provider.PREFS_URI(packageName)
|
||||
|
||||
private fun genPackageName(): String {
|
||||
val random = SecureRandom()
|
||||
val len = 5 + random.nextInt(15)
|
||||
val builder = StringBuilder(len)
|
||||
@ -59,20 +61,20 @@ object PatchAPK {
|
||||
val idx = random.nextInt(len - 1)
|
||||
builder[idx] = '.'
|
||||
}
|
||||
return builder
|
||||
return builder.toString()
|
||||
}
|
||||
|
||||
fun patch(
|
||||
context: Context,
|
||||
apk: String, out: String,
|
||||
pkg: CharSequence, label: CharSequence
|
||||
pkg: String, label: CharSequence
|
||||
): Boolean {
|
||||
try {
|
||||
val jar = JarMap.open(apk)
|
||||
val je = jar.getJarEntry(Const.ANDROID_MANIFEST)
|
||||
val xml = AXML(jar.getRawData(je))
|
||||
|
||||
if (!xml.findAndPatch(APP_ID to pkg.toString(), APP_NAME to label.toString()))
|
||||
if (!xml.findAndPatch(APPLICATION_ID to pkg, APP_NAME to label.toString()))
|
||||
return false
|
||||
|
||||
// Write apk changes
|
||||
@ -91,7 +93,6 @@ object PatchAPK {
|
||||
val dlStub = !isRunningAsStub && SDK_INT >= 28 && Const.Version.atLeast_20_2()
|
||||
val src = if (dlStub) {
|
||||
val stub = File(context.cacheDir, "stub.apk")
|
||||
val svc = get<NetworkService>()
|
||||
try {
|
||||
svc.fetchFile(Info.remote.stub.link).byteStream().use {
|
||||
it.writeTo(stub)
|
||||
@ -117,23 +118,73 @@ object PatchAPK {
|
||||
if (!Shell.su("adb_pm_install $repack").exec().isSuccess)
|
||||
return false
|
||||
|
||||
Config.suManager = pkg.toString()
|
||||
Config.export()
|
||||
Shell.su("pm uninstall $APP_ID").submit()
|
||||
context.apply {
|
||||
val intent = packageManager.getLaunchIntentForPackage(pkg) ?: return false
|
||||
Config.suManager = pkg
|
||||
grantUriPermission(pkg, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
grantUriPermission(pkg, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun hideManager(context: Context, label: String) {
|
||||
val progress = Notifications.progress(context, context.getString(R.string.hide_manager_title))
|
||||
Notifications.mgr.notify(Const.ID.HIDE_MANAGER_NOTIFICATION_ID, progress.build())
|
||||
@Suppress("DEPRECATION")
|
||||
fun hide(context: Context, label: String) {
|
||||
val dialog = ProgressDialog.show(context, context.getString(R.string.hide_manager_title), "", true)
|
||||
GlobalScope.launch {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
patchAndHide(context, label)
|
||||
}
|
||||
if (!result)
|
||||
if (!result) {
|
||||
Utils.toast(R.string.hide_manager_fail_toast, Toast.LENGTH_LONG)
|
||||
Notifications.mgr.cancel(Const.ID.HIDE_MANAGER_NOTIFICATION_ID)
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun downloadAndRestore(context: Context): Boolean {
|
||||
val apk = if (isRunningAsStub) {
|
||||
DynAPK.current(context)
|
||||
} else {
|
||||
File(context.cacheDir, "manager.apk").also { apk ->
|
||||
try {
|
||||
svc.fetchFile(Info.remote.app.link).byteStream().use {
|
||||
it.writeTo(apk)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Timber.e(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!Shell.su("adb_pm_install $apk").exec().isSuccess)
|
||||
return false
|
||||
|
||||
context.apply {
|
||||
val intent = packageManager.getLaunchIntentForPackage(APPLICATION_ID) ?: return false
|
||||
Config.suManager = ""
|
||||
grantUriPermission(APPLICATION_ID, APK_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
grantUriPermission(APPLICATION_ID, PREFS_URI, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
intent.putExtra(Const.Key.HIDDEN_PKG, packageName)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun restore(context: Context) {
|
||||
val dialog = ProgressDialog.show(context, context.getString(R.string.restore_img_msg), "", true)
|
||||
GlobalScope.launch {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
downloadAndRestore(context)
|
||||
}
|
||||
if (!result) {
|
||||
Utils.toast(R.string.restore_manager_fail_toast, Toast.LENGTH_LONG)
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,16 +11,14 @@ interface PreferenceModel {
|
||||
|
||||
val fileName: String
|
||||
get() = "${context.packageName}_preferences"
|
||||
val commitPrefs: Boolean
|
||||
get() = false
|
||||
|
||||
val prefs: SharedPreferences
|
||||
get() = context.getSharedPreferences(fileName, Context.MODE_PRIVATE)
|
||||
|
||||
fun preferenceStrInt(
|
||||
name: String,
|
||||
default: Int,
|
||||
writeDefault: Boolean = false,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = object: ReadWriteProperty<PreferenceModel, Int> {
|
||||
val base = StringProperty(name, default.toString(), commit)
|
||||
override fun getValue(thisRef: PreferenceModel, property: KProperty<*>): Int =
|
||||
@ -33,37 +31,37 @@ interface PreferenceModel {
|
||||
fun preference(
|
||||
name: String,
|
||||
default: Boolean,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = BooleanProperty(name, default, commit)
|
||||
|
||||
fun preference(
|
||||
name: String,
|
||||
default: Float,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = FloatProperty(name, default, commit)
|
||||
|
||||
fun preference(
|
||||
name: String,
|
||||
default: Int,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = IntProperty(name, default, commit)
|
||||
|
||||
fun preference(
|
||||
name: String,
|
||||
default: Long,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = LongProperty(name, default, commit)
|
||||
|
||||
fun preference(
|
||||
name: String,
|
||||
default: String,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = StringProperty(name, default, commit)
|
||||
|
||||
fun preference(
|
||||
name: String,
|
||||
default: Set<String>,
|
||||
commit: Boolean = commitPrefs
|
||||
commit: Boolean = false
|
||||
) = StringSetProperty(name, default, commit)
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package com.topjohnwu.magisk.events.dialog
|
||||
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
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.ktx.res
|
||||
@ -16,7 +15,7 @@ class ManagerInstallDialog : DialogEvent() {
|
||||
|
||||
override fun build(dialog: MagiskDialog) {
|
||||
with(dialog) {
|
||||
val subject = Subject.Manager(Action.APK.Upgrade)
|
||||
val subject = Subject.Manager()
|
||||
|
||||
applyTitle(R.string.repo_install_title.res(R.string.app_name.res()))
|
||||
applyMessage(R.string.repo_install_msg.res(subject.title))
|
||||
|
@ -11,7 +11,7 @@ import com.topjohnwu.magisk.core.Config
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
import com.topjohnwu.magisk.core.UpdateCheckService
|
||||
import com.topjohnwu.magisk.core.tasks.PatchAPK
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.core.utils.BiometricHelper
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.core.utils.availableLocales
|
||||
@ -90,7 +90,7 @@ object Hide : BaseSettingsItem.Input() {
|
||||
set(value) = set(value, field, { field = it }, BR.result, BR.error)
|
||||
|
||||
val maxLength
|
||||
get() = PatchAPK.MAX_LABEL_LENGTH
|
||||
get() = HideAPK.MAX_LABEL_LENGTH
|
||||
|
||||
@get:Bindable
|
||||
val isError
|
||||
@ -288,9 +288,9 @@ object AutomaticResponse : BaseSettingsItem.Selector() {
|
||||
override val entryRes = R.array.auto_response
|
||||
override val entryValRes = R.array.value_array
|
||||
|
||||
override var value = Config.suAutoReponse
|
||||
override var value = Config.suAutoResponse
|
||||
set(value) = setV(value, field, { field = it }) {
|
||||
Config.suAutoReponse = entryValues[it].toInt()
|
||||
Config.suAutoResponse = entryValues[it].toInt()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,11 +15,8 @@ import com.topjohnwu.magisk.arch.diffListOf
|
||||
import com.topjohnwu.magisk.arch.itemBindingOf
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.core.Info
|
||||
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.isRunningAsStub
|
||||
import com.topjohnwu.magisk.core.tasks.PatchAPK
|
||||
import com.topjohnwu.magisk.core.tasks.HideAPK
|
||||
import com.topjohnwu.magisk.data.database.RepoDao
|
||||
import com.topjohnwu.magisk.events.AddHomeIconEvent
|
||||
import com.topjohnwu.magisk.events.RecreateEvent
|
||||
@ -104,7 +101,7 @@ class SettingsViewModel(
|
||||
is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().publish()
|
||||
is ClearRepoCache -> clearRepoCache()
|
||||
is SystemlessHosts -> createHosts()
|
||||
is Restore -> restoreManager()
|
||||
is Restore -> HideAPK.restore(view.context)
|
||||
is AddShortcut -> AddHomeIconEvent().publish()
|
||||
else -> callback()
|
||||
}
|
||||
@ -112,7 +109,7 @@ class SettingsViewModel(
|
||||
override fun onItemChanged(view: View, item: BaseSettingsItem) = when (item) {
|
||||
is Language -> RecreateEvent().publish()
|
||||
is UpdateChannel -> openUrlIfNecessary(view)
|
||||
is Hide -> PatchAPK.hideManager(view.context, item.value)
|
||||
is Hide -> HideAPK.hide(view.context, item.value)
|
||||
else -> Unit
|
||||
}
|
||||
|
||||
@ -142,9 +139,4 @@ class SettingsViewModel(
|
||||
Utils.toast(R.string.settings_hosts_toast, Toast.LENGTH_SHORT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun restoreManager() {
|
||||
DownloadService.start(get(), Subject.Manager(Action.APK.Restore))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ 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.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
|
||||
@ -70,7 +69,7 @@ object Notifications {
|
||||
}
|
||||
|
||||
fun managerUpdate(context: Context) {
|
||||
val intent = DownloadService.pendingIntent(context, Subject.Manager(Action.APK.Upgrade))
|
||||
val intent = DownloadService.pendingIntent(context, Subject.Manager())
|
||||
|
||||
val builder = updateBuilder(context)
|
||||
.setContentTitle(context.getString(R.string.manager_update_title))
|
||||
|
@ -90,7 +90,7 @@ EOF
|
||||
}
|
||||
|
||||
adb_pm_install() {
|
||||
local tmp=/data/local/tmp/patched.apk
|
||||
local tmp=/data/local/tmp/temp.apk
|
||||
cp -f "$1" $tmp
|
||||
chmod 644 $tmp
|
||||
su 2000 -c pm install $tmp || pm install $tmp
|
||||
|
@ -217,7 +217,8 @@
|
||||
<string name="done">Done!</string>
|
||||
<string name="failure">Failed</string>
|
||||
<string name="hide_manager_title">Hiding Magisk Manager…</string>
|
||||
<string name="hide_manager_fail_toast">Hide Magisk Manager failed.</string>
|
||||
<string name="hide_manager_fail_toast">Hide Magisk Manager failed</string>
|
||||
<string name="restore_manager_fail_toast">Restoring Magisk Manager failed</string>
|
||||
<string name="open_link_failed_toast">No application found to open the link</string>
|
||||
<string name="complete_uninstall">Complete Uninstall</string>
|
||||
<string name="restore_img">Restore Images</string>
|
||||
|
Loading…
Reference in New Issue
Block a user