Only allow hide/restore app if connected

This commit is contained in:
topjohnwu 2019-10-23 05:43:01 -04:00
parent d010cb7e42
commit 0b5fd3ee76
5 changed files with 93 additions and 105 deletions

View File

@ -1,7 +1,11 @@
package com.topjohnwu.magisk package com.topjohnwu.magisk
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.entity.UpdateInfo import com.topjohnwu.magisk.model.entity.UpdateInfo
import com.topjohnwu.magisk.utils.CachedValue import com.topjohnwu.magisk.utils.CachedValue
import com.topjohnwu.magisk.utils.KObservableField
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
@ -16,13 +20,27 @@ object Info {
var keepEnc = false var keepEnc = false
var recovery = false var recovery = false
val isConnected by lazy {
KObservableField(false).also { field ->
ReactiveNetwork.observeNetworkConnectivity(get())
.subscribeK {
field.value = it.available()
}
}
}
private fun loadState() = runCatching { private fun loadState() = runCatching {
val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0] val str = ShellUtils.fastCmd("magisk -v").split(":".toRegex())[0]
val code = ShellUtils.fastCmd("magisk -V").toInt() val code = ShellUtils.fastCmd("magisk -V").toInt()
val hide = Shell.su("magiskhide --status").exec().isSuccess val hide = Shell.su("magiskhide --status").exec().isSuccess
var mode = Int.MAX_VALUE var mode = -1
if (code >= Const.Version.CONNECT_MODE) if (code >= Const.Version.CONNECT_MODE) {
mode = Shell.su("magisk --connect-mode").exec().code mode = Shell.su("magisk --connect-mode").exec().code
if (mode == 0) {
// Manually trigger broadcast test
Shell.su("magisk --broadcast-test").exec()
}
}
Env(code, str, hide, mode) Env(code, str, hide, mode)
}.getOrElse { Env() } }.getOrElse { Env() }
@ -30,7 +48,7 @@ object Info {
val magiskVersionCode: Int = -1, val magiskVersionCode: Int = -1,
val magiskVersionString: String = "", val magiskVersionString: String = "",
hide: Boolean = false, hide: Boolean = false,
var connectionMode: Int = Int.MAX_VALUE var connectionMode: Int = -1
) { ) {
val magiskHide get() = Config.magiskHide val magiskHide get() = Config.magiskHide

View File

@ -1,10 +1,8 @@
package com.topjohnwu.magisk.base.viewmodel package com.topjohnwu.magisk.base.viewmodel
import android.app.Activity import android.app.Activity
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.topjohnwu.magisk.Info.isConnected as gIsConnected
import com.topjohnwu.magisk.extensions.doOnSubscribeUi import com.topjohnwu.magisk.extensions.doOnSubscribeUi
import com.topjohnwu.magisk.extensions.get
import com.topjohnwu.magisk.extensions.subscribeK
import com.topjohnwu.magisk.model.events.BackPressEvent import com.topjohnwu.magisk.model.events.BackPressEvent
import com.topjohnwu.magisk.model.events.PermissionEvent import com.topjohnwu.magisk.model.events.PermissionEvent
import com.topjohnwu.magisk.model.events.ViewActionEvent import com.topjohnwu.magisk.model.events.ViewActionEvent
@ -17,12 +15,10 @@ abstract class BaseViewModel(
initialState: State = State.LOADING initialState: State = State.LOADING
) : LoadingViewModel(initialState) { ) : LoadingViewModel(initialState) {
val isConnected = KObservableField(false) val isConnected = object : KObservableField<Boolean>(gIsConnected.value, gIsConnected) {
override fun get(): Boolean {
init { return gIsConnected.value
ReactiveNetwork.observeNetworkConnectivity(get()) }
.subscribeK { isConnected.value = it.available() }
.add()
} }
fun withView(action: Activity.() -> Unit) { fun withView(action: Activity.() -> Unit) {

View File

@ -24,7 +24,6 @@ import com.topjohnwu.magisk.model.download.DownloadService
import com.topjohnwu.magisk.model.entity.internal.Configuration import com.topjohnwu.magisk.model.entity.internal.Configuration
import com.topjohnwu.magisk.model.entity.internal.DownloadSubject 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.net.Networking
import com.topjohnwu.magisk.utils.* import com.topjohnwu.magisk.utils.*
import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog import com.topjohnwu.magisk.view.dialogs.FingerprintAuthDialog
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@ -54,6 +53,7 @@ class SettingsFragment : BasePreferenceFragment() {
preferenceManager.setStorageDeviceProtected() preferenceManager.setStorageDeviceProtected()
setPreferencesFromResource(R.xml.app_settings, rootKey) setPreferencesFromResource(R.xml.app_settings, rootKey)
// Get preferences
updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!! updateChannel = findPreference(Config.Key.UPDATE_CHANNEL)!!
rootConfig = findPreference(Config.Key.ROOT_ACCESS)!! rootConfig = findPreference(Config.Key.ROOT_ACCESS)!!
autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!! autoRes = findPreference(Config.Key.SU_AUTO_RESPONSE)!!
@ -67,19 +67,68 @@ class SettingsFragment : BasePreferenceFragment() {
val magiskCategory = findPreference<PreferenceCategory>("magisk")!! val magiskCategory = findPreference<PreferenceCategory>("magisk")!!
val suCategory = findPreference<PreferenceCategory>("superuser")!! val suCategory = findPreference<PreferenceCategory>("superuser")!!
val hideManager = findPreference<Preference>("hide")!! val hideManager = findPreference<Preference>("hide")!!
val restoreManager = findPreference<Preference>("restore")!!
// Remove/Disable entries
// Only show canary channels if user is already on canary channel
// or the user have already chosen canary channel
if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
// Remove dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Remove re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
suCategory.removePreference(reauth)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Const.USER_ID == 0 && Info.isConnected.value && Shell.rootAccess()) {
if (activity.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
hideManager.setOnPreferenceClickListener { hideManager.setOnPreferenceClickListener {
showManagerNameDialog { showManagerNameDialog {
PatchAPK.hideManager(requireContext(), it) PatchAPK.hideManager(requireContext(), it)
} }
true true
} }
val restoreManager = findPreference<Preference>("restore") } else {
restoreManager?.setOnPreferenceClickListener { generalCatagory.removePreference(hideManager)
restoreManager.setOnPreferenceClickListener {
DownloadService(requireContext()) { DownloadService(requireContext()) {
subject = DownloadSubject.Manager(Configuration.APK.Restore) subject = DownloadSubject.Manager(Configuration.APK.Restore)
} }
true true
} }
}
} else {
// Remove if not primary user, no connection, or no root
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
findPreference<Preference>("clear")?.setOnPreferenceClickListener { findPreference<Preference>("clear")?.setOnPreferenceClickListener {
Completable.fromAction { repoDB.clear() }.subscribeK { Completable.fromAction { repoDB.clear() }.subscribeK {
Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT) Utils.toast(R.string.repo_cache_cleared, Toast.LENGTH_SHORT)
@ -123,58 +172,7 @@ class SettingsFragment : BasePreferenceFragment() {
setLocalePreference(findPreference(Config.Key.LOCALE)!!) setLocalePreference(findPreference(Config.Key.LOCALE)!!)
/* We only show canary channels if user is already on canary channel
* or the user have already chosen canary channel */
if (!Utils.isCanary && Config.updateChannel < Config.Value.CANARY_CHANNEL) {
// Remove the last 2 entries
val entries = updateChannel.entries
updateChannel.entries = entries.copyOf(entries.size - 2)
}
setSummary() setSummary()
// Disable dangerous settings in secondary user
if (Const.USER_ID > 0) {
suCategory.removePreference(multiuserConfig)
}
// Disable re-authentication option on Android O, it will not work
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
reauth.isEnabled = false
reauth.isChecked = false
reauth.setSummary(R.string.android_o_not_support)
}
// Disable fingerprint option if not possible
if (!FingerprintHelper.canUseFingerprint()) {
fingerprint.isEnabled = false
fingerprint.isChecked = false
fingerprint.setSummary(R.string.disable_fingerprint)
}
if (Shell.rootAccess() && Const.USER_ID == 0) {
if (activity.packageName == BuildConfig.APPLICATION_ID) {
generalCatagory.removePreference(restoreManager)
} else {
if (!Networking.checkNetworkStatus(requireContext())) {
generalCatagory.removePreference(restoreManager)
}
generalCatagory.removePreference(hideManager)
}
} else {
generalCatagory.removePreference(restoreManager)
generalCatagory.removePreference(hideManager)
}
if (!Utils.showSuperUser()) {
preferenceScreen.removePreference(suCategory)
}
if (!Shell.rootAccess()) {
preferenceScreen.removePreference(magiskCategory)
generalCatagory.removePreference(hideManager)
}
} }
override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {

View File

@ -9,15 +9,11 @@ import java.io.Serializable
* You can define if wrapped type is Nullable or not. * You can define if wrapped type is Nullable or not.
* You can use kotlin get/set syntax for value * You can use kotlin get/set syntax for value
*/ */
class KObservableField<T> : ObservableField<T>, Serializable { open class KObservableField<T> : ObservableField<T>, Serializable {
var value: T var value: T
set(value) { get() = get()
if (field != value) { set(value) { set(value) }
field = value
notifyChange()
}
}
constructor(init: T) { constructor(init: T) {
value = init value = init
@ -27,23 +23,8 @@ class KObservableField<T> : ObservableField<T>, Serializable {
value = init value = init
} }
@Deprecated( @Suppress("UNCHECKED_CAST")
message = "Needed for data binding, use KObservableField.value syntax from code",
replaceWith = ReplaceWith("value")
)
override fun get(): T { override fun get(): T {
return value return super.get() as T
}
@Deprecated(
message = "Needed for data binding, use KObservableField.value = ... syntax from code",
replaceWith = ReplaceWith("value = newValue")
)
override fun set(newValue: T) {
value = newValue
}
override fun toString(): String {
return "KObservableField(value=$value)"
} }
} }

View File

@ -39,11 +39,6 @@ class RootInit : Shell.Initializer() {
Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean() Info.keepEnc = ShellUtils.fastCmd("echo \$KEEPFORCEENCRYPT").toBoolean()
Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean() Info.recovery = ShellUtils.fastCmd("echo \$RECOVERYMODE").toBoolean()
if (Info.env.connectionMode == 0) {
// Manually trigger broadcast test
Shell.su("magisk --broadcast-test").exec()
}
return true return true
} }
} }