forked from MarcoBuster/Magisk
126 lines
4.0 KiB
Kotlin
126 lines
4.0 KiB
Kotlin
package com.topjohnwu.magisk.ui.hide
|
|
|
|
import android.annotation.SuppressLint
|
|
import android.content.pm.ApplicationInfo
|
|
import android.content.pm.PackageManager
|
|
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
|
import android.os.Process
|
|
import androidx.databinding.Bindable
|
|
import androidx.lifecycle.viewModelScope
|
|
import com.topjohnwu.magisk.BR
|
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
|
import com.topjohnwu.magisk.arch.Queryable
|
|
import com.topjohnwu.magisk.arch.filterableListOf
|
|
import com.topjohnwu.magisk.arch.itemBindingOf
|
|
import com.topjohnwu.magisk.core.Config
|
|
import com.topjohnwu.magisk.ktx.get
|
|
import com.topjohnwu.magisk.ktx.packageName
|
|
import com.topjohnwu.magisk.utils.Utils
|
|
import com.topjohnwu.magisk.utils.set
|
|
import com.topjohnwu.superuser.Shell
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.withContext
|
|
|
|
class HideViewModel : BaseViewModel(), Queryable {
|
|
|
|
override val queryDelay = 1000L
|
|
|
|
@get:Bindable
|
|
var isShowSystem = Config.showSystemApp
|
|
set(value) = set(value, field, { field = it }, BR.showSystem) {
|
|
Config.showSystemApp = it
|
|
submitQuery()
|
|
}
|
|
|
|
@get:Bindable
|
|
var isShowOS = false
|
|
set(value) = set(value, field, { field = it }, BR.showOS) {
|
|
submitQuery()
|
|
}
|
|
|
|
@get:Bindable
|
|
var query = ""
|
|
set(value) = set(value, field, { field = it }, BR.query) {
|
|
submitQuery()
|
|
}
|
|
|
|
val items = filterableListOf<HideRvItem>()
|
|
val itemBinding = itemBindingOf<HideRvItem> {
|
|
it.bindExtra(BR.viewModel, this)
|
|
}
|
|
val itemInternalBinding = itemBindingOf<HideProcessRvItem> {
|
|
it.bindExtra(BR.viewModel, this)
|
|
}
|
|
|
|
@SuppressLint("InlinedApi")
|
|
override fun refresh() = viewModelScope.launch {
|
|
if (!Utils.showSuperUser()) {
|
|
state = State.LOADING_FAILED
|
|
return@launch
|
|
}
|
|
state = State.LOADING
|
|
val (apps, diff) = withContext(Dispatchers.Default) {
|
|
val pm = get<PackageManager>()
|
|
val hideList = Shell.su("magiskhide ls").exec().out.map { CmdlineHiddenItem(it) }
|
|
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES)
|
|
.asSequence()
|
|
.filterNot { blacklist.contains(it.packageName) }
|
|
.map { HideAppInfo(it, pm, hideList) }
|
|
.filter { it.processes.isNotEmpty() }
|
|
.filter { info -> info.enabled || info.processes.any { it.isHidden } }
|
|
.map { HideRvItem(it) }
|
|
.toList()
|
|
.sorted()
|
|
apps to items.calculateDiff(apps)
|
|
}
|
|
items.update(apps, diff)
|
|
submitQuery()
|
|
}
|
|
|
|
// ---
|
|
|
|
override fun query() {
|
|
items.filter {
|
|
fun showHidden() = it.itemsChecked != 0
|
|
|
|
fun filterSystem() = isShowSystem || it.info.flags and ApplicationInfo.FLAG_SYSTEM == 0
|
|
|
|
fun isApp(uid: Int) = run {
|
|
val appId: Int = uid % 100000
|
|
appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID
|
|
}
|
|
|
|
fun filterOS() = (isShowSystem && isShowOS) || isApp(it.info.uid)
|
|
|
|
fun filterQuery(): Boolean {
|
|
fun inName() = it.info.label.contains(query, true)
|
|
fun inPackage() = it.info.packageName.contains(query, true)
|
|
fun inProcesses() = it.processes.any { p -> p.process.name.contains(query, true) }
|
|
return inName() || inPackage() || inProcesses()
|
|
}
|
|
|
|
showHidden() || (filterSystem() && filterOS() && filterQuery())
|
|
}
|
|
state = State.LOADED
|
|
}
|
|
|
|
// ---
|
|
|
|
fun resetQuery() {
|
|
query = ""
|
|
}
|
|
|
|
companion object {
|
|
private val blacklist by lazy { listOf(
|
|
packageName,
|
|
"com.android.chrome",
|
|
"com.chrome.beta",
|
|
"com.chrome.dev",
|
|
"com.chrome.canary",
|
|
"com.android.webview",
|
|
"com.google.android.webview"
|
|
) }
|
|
}
|
|
}
|