diff --git a/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt b/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt index 81592631e..aa7dad6fa 100644 --- a/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt +++ b/app/src/main/java/com/topjohnwu/magisk/data/repository/MagiskRepository.kt @@ -1,17 +1,27 @@ package com.topjohnwu.magisk.data.repository import android.content.Context +import android.content.pm.PackageManager +import com.topjohnwu.magisk.App import com.topjohnwu.magisk.KConfig +import com.topjohnwu.magisk.data.database.base.su import com.topjohnwu.magisk.data.database.base.suRaw import com.topjohnwu.magisk.data.network.GithubRawApiServices +import com.topjohnwu.magisk.model.entity.HideAppInfo +import com.topjohnwu.magisk.model.entity.HideTarget import com.topjohnwu.magisk.model.entity.Version +import com.topjohnwu.magisk.utils.Utils +import com.topjohnwu.magisk.utils.inject +import com.topjohnwu.magisk.utils.toSingle import com.topjohnwu.magisk.utils.writeToFile +import com.topjohnwu.superuser.Shell import io.reactivex.Single import io.reactivex.functions.BiFunction class MagiskRepository( private val context: Context, - private val apiRaw: GithubRawApiServices + private val apiRaw: GithubRawApiServices, + private val packageManager: PackageManager ) { private val config = apiRaw.fetchConfig() @@ -57,6 +67,25 @@ class MagiskRepository( } ) + + fun fetchApps() = + Single.fromCallable { packageManager.getInstalledApplications(0) } + .flattenAsFlowable { it } + .filter { it.enabled && !blacklist.contains(it.packageName) } + .map { + val label = Utils.getAppLabel(it, packageManager) + val icon = it.loadIcon(packageManager) + HideAppInfo(it, label, icon) + } + .filter { it.processes.isNotEmpty() } + .toList() + + fun fetchHideTargets() = Shell.su("magiskhide --ls").toSingle() + .map { it.exec().out } + .flattenAsFlowable { it } + .map { HideTarget(it) } + .toList() + private fun fetchMagiskVersionName() = "magisk -v".suRaw() .map { it.first() } .map { it.substring(0 until it.indexOf(":")) } @@ -67,12 +96,28 @@ class MagiskRepository( .map { it.toIntOrNull() ?: -1 } .onErrorReturn { -1 } + fun toggleHide(isEnabled: Boolean, packageName: String, process: String) = + "magiskhide --%s %s %s".format(isEnabled.state, packageName, process).su().ignoreElement() + + private val Boolean.state get() = if (this) "add" else "rm" + companion object { const val FILE_MAGISK_ZIP = "magisk.zip" const val FILE_MAGISK_APK = "magisk.apk" const val FILE_UNINSTALLER_ZIP = "uninstaller.zip" const val FILE_SAFETY_NET_APK = "safetynet.apk" const val FILE_BOOTCTL_SH = "bootctl" + + private val blacklist = listOf( + let { val app: App by inject(); app }.packageName, + "android", + "com.android.chrome", + "com.chrome.beta", + "com.chrome.dev", + "com.chrome.canary", + "com.android.webview", + "com.google.android.webview" + ) } } \ No newline at end of file diff --git a/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt b/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt index 79349f63e..bccccf18f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt +++ b/app/src/main/java/com/topjohnwu/magisk/di/RepositoryModule.kt @@ -7,7 +7,7 @@ import org.koin.dsl.module val repositoryModule = module { - single { MagiskRepository(get(), get()) } + single { MagiskRepository(get(), get(), get()) } single { ModuleRepository(get(), get(), get(), get()) } single { LogRepository(get()) } } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt index 2e60d5d5a..c7c3085ca 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/hide/HideViewModel.kt @@ -1,32 +1,26 @@ package com.topjohnwu.magisk.ui.hide import android.content.pm.ApplicationInfo -import android.content.pm.PackageManager import com.skoumal.teanity.databinding.ComparableRvItem import com.skoumal.teanity.extensions.addOnPropertyChangedCallback import com.skoumal.teanity.extensions.subscribeK import com.skoumal.teanity.rxbus.RxBus import com.skoumal.teanity.util.DiffObservableList import com.skoumal.teanity.util.KObservableField -import com.topjohnwu.magisk.App import com.topjohnwu.magisk.BR -import com.topjohnwu.magisk.model.entity.HideAppInfo -import com.topjohnwu.magisk.model.entity.HideTarget +import com.topjohnwu.magisk.data.repository.MagiskRepository import com.topjohnwu.magisk.model.entity.recycler.HideProcessRvItem import com.topjohnwu.magisk.model.entity.recycler.HideRvItem import com.topjohnwu.magisk.model.entity.state.IndeterminateState import com.topjohnwu.magisk.model.events.HideProcessEvent import com.topjohnwu.magisk.ui.base.MagiskViewModel -import com.topjohnwu.magisk.utils.Utils import com.topjohnwu.magisk.utils.toSingle import com.topjohnwu.magisk.utils.update -import com.topjohnwu.superuser.Shell -import io.reactivex.Single import me.tatarka.bindingcollectionadapter2.OnItemBind import timber.log.Timber class HideViewModel( - private val packageManager: PackageManager, + private val magiskRepo: MagiskRepository, rxBus: RxBus ) : MagiskViewModel() { @@ -55,26 +49,19 @@ class HideViewModel( // fetching this for every item is nonsensical, so we add .cache() so the response is all // the same for every single mapped item, it only actually executes the whole thing the // first time around. - val hideTargets = Shell.su("magiskhide --ls").toSingle() - .map { it.exec().out } - .flattenAsFlowable { it } - .map { HideTarget(it) } - .toList() - .cache() + val hideTargets = magiskRepo.fetchHideTargets().cache() - Single.fromCallable { packageManager.getInstalledApplications(0) } + magiskRepo.fetchApps() .flattenAsFlowable { it } - .filter { it.enabled && !blacklist.contains(it.packageName) } - .map { - val label = Utils.getAppLabel(it, packageManager) - val icon = it.loadIcon(packageManager) - HideAppInfo(it, label, icon) - } - .filter { it.processes.isNotEmpty() } .map { HideRvItem(it, hideTargets.blockingGet()) } .toList() - .map { it.sortWith(compareBy( - {it.isHiddenState.value}, {it.item.info.name}, {it.packageName})); it } + .map { + it.sortedWith(compareBy( + { it.isHiddenState.value }, + { it.item.name.toLowerCase() }, + { it.packageName } + )) + } .doOnSuccess { allItems.update(it) } .flatMap { queryRaw() } .applyViewModel(this) @@ -103,26 +90,9 @@ class HideViewModel( .toList() .map { it to items.calculateDiff(it) } - private fun toggleItem(item: HideProcessRvItem) { - val state = if (item.isHidden.value) "add" else "rm" - "magiskhide --%s %s %s".format(state, item.packageName, item.process) - .let { Shell.su(it) } - .toSingle() - .map { it.submit() } - .subscribeK() - } - - companion object { - private val blacklist = listOf( - App.self.packageName, - "android", - "com.android.chrome", - "com.chrome.beta", - "com.chrome.dev", - "com.chrome.canary", - "com.android.webview", - "com.google.android.webview" - ) - } + private fun toggleItem(item: HideProcessRvItem) = magiskRepo + .toggleHide(item.isHidden.value, item.packageName, item.process) + .subscribeK() + .add() } \ No newline at end of file