mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 19:17:38 +00:00
Rewrite deny list UI
This commit is contained in:
parent
16322ab30c
commit
9126cf0c73
@ -9,9 +9,6 @@ import android.content.Intent
|
|||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.pm.PackageManager.*
|
import android.content.pm.PackageManager.*
|
||||||
import android.content.pm.ServiceInfo
|
|
||||||
import android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS
|
|
||||||
import android.content.pm.ServiceInfo.FLAG_USE_APP_ZYGOTE
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
@ -58,11 +55,6 @@ import kotlinx.coroutines.launch
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.reflect.Array as JArray
|
import java.lang.reflect.Array as JArray
|
||||||
|
|
||||||
val ServiceInfo.isIsolated get() = (flags and FLAG_ISOLATED_PROCESS) != 0
|
|
||||||
|
|
||||||
@get:SuppressLint("InlinedApi")
|
|
||||||
val ServiceInfo.useAppZygote get() = (flags and FLAG_USE_APP_ZYGOTE) != 0
|
|
||||||
|
|
||||||
fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
fun Context.rawResource(id: Int) = resources.openRawResource(id)
|
||||||
|
|
||||||
fun Context.getBitmap(id: Int): Bitmap {
|
fun Context.getBitmap(id: Int): Bitmap {
|
||||||
|
@ -10,8 +10,6 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.os.Build.VERSION.SDK_INT
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import com.topjohnwu.magisk.core.utils.currentLocale
|
import com.topjohnwu.magisk.core.utils.currentLocale
|
||||||
import com.topjohnwu.magisk.ktx.getLabel
|
import com.topjohnwu.magisk.ktx.getLabel
|
||||||
import com.topjohnwu.magisk.ktx.isIsolated
|
|
||||||
import com.topjohnwu.magisk.ktx.useAppZygote
|
|
||||||
|
|
||||||
class CmdlineListItem(line: String) {
|
class CmdlineListItem(line: String) {
|
||||||
val packageName: String
|
val packageName: String
|
||||||
@ -27,72 +25,63 @@ class CmdlineListItem(line: String) {
|
|||||||
const val ISOLATED_MAGIC = "isolated"
|
const val ISOLATED_MAGIC = "isolated"
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
class AppProcessInfo(info: ApplicationInfo, pm: PackageManager, denyList: List<CmdlineListItem>)
|
class AppProcessInfo(val applicationInfo: ApplicationInfo, pm: PackageManager,
|
||||||
: ApplicationInfo(info), Comparable<AppProcessInfo> {
|
denyList: List<CmdlineListItem>) : Comparable<AppProcessInfo> {
|
||||||
|
|
||||||
val label = info.getLabel(pm)
|
private val denyList = denyList.filter {
|
||||||
val iconImage: Drawable = info.loadIcon(pm)
|
it.packageName == applicationInfo.packageName || it.packageName == ISOLATED_MAGIC
|
||||||
val processes = fetchProcesses(pm, denyList)
|
}
|
||||||
|
val label = applicationInfo.getLabel(pm)
|
||||||
|
val iconImage: Drawable = applicationInfo.loadIcon(pm)
|
||||||
|
val processes = fetchProcesses(pm)
|
||||||
|
|
||||||
override fun compareTo(other: AppProcessInfo) = comparator.compare(this, other)
|
override fun compareTo(other: AppProcessInfo) = comparator.compare(this, other)
|
||||||
|
|
||||||
private fun fetchProcesses(
|
private fun createProcess(name: String, pkg: String = applicationInfo.packageName) =
|
||||||
pm: PackageManager,
|
ProcessInfo(name, pkg, denyList.any { it.process == name && it.packageName == pkg })
|
||||||
denylist: List<CmdlineListItem>
|
|
||||||
): List<ProcessInfo> {
|
|
||||||
// Fetch full PackageInfo
|
|
||||||
val baseFlag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES
|
|
||||||
val packageInfo = try {
|
|
||||||
val request = GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
|
|
||||||
pm.getPackageInfo(packageName, baseFlag or request)
|
|
||||||
} catch (e: NameNotFoundException) {
|
|
||||||
// EdXposed hooked, issue#3276
|
|
||||||
return emptyList()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Exceed binder data transfer limit, fetch each component type separately
|
|
||||||
pm.getPackageInfo(packageName, baseFlag).apply {
|
|
||||||
runCatching { activities = pm.getPackageInfo(packageName, baseFlag or GET_ACTIVITIES).activities }
|
|
||||||
runCatching { services = pm.getPackageInfo(packageName, baseFlag or GET_SERVICES).services }
|
|
||||||
runCatching { receivers = pm.getPackageInfo(packageName, baseFlag or GET_RECEIVERS).receivers }
|
|
||||||
runCatching { providers = pm.getPackageInfo(packageName, baseFlag or GET_PROVIDERS).providers }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val enabledList = denylist.filter { it.packageName == packageName || it.packageName == ISOLATED_MAGIC }
|
private fun ComponentInfo.getProcName(): String = processName
|
||||||
fun createProcess(name: String, pkg: String = packageName): ProcessInfo {
|
?: applicationInfo.processName
|
||||||
return ProcessInfo(name, pkg, enabledList.any { it.process == name && it.packageName == pkg })
|
?: applicationInfo.packageName
|
||||||
}
|
|
||||||
|
|
||||||
var haveAppZygote = false
|
private fun Array<out ComponentInfo>.processes() = map { createProcess(it.getProcName()) }
|
||||||
fun Array<out ComponentInfo>.processes() = map { createProcess(it.processName) }
|
|
||||||
fun Array<ServiceInfo>.processes() = map {
|
private fun Array<ServiceInfo>.processes() = map {
|
||||||
if (it.isIsolated) {
|
if ((it.flags and ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
|
||||||
if (it.useAppZygote) {
|
if ((it.flags and ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {
|
||||||
haveAppZygote = true
|
val proc = applicationInfo.processName ?: applicationInfo.packageName
|
||||||
// Using app zygote, don't need to track the process
|
createProcess("${proc}_zygote")
|
||||||
null
|
|
||||||
} else {
|
|
||||||
val proc = if (SDK_INT >= 29) "${it.processName}:${it.name}" else it.processName
|
|
||||||
createProcess(proc, ISOLATED_MAGIC)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
createProcess(it.processName)
|
val proc = if (SDK_INT >= 29) "${it.getProcName()}:${it.name}" else it.getProcName()
|
||||||
|
createProcess(proc, ISOLATED_MAGIC)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
createProcess(it.getProcName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fetchProcesses(pm: PackageManager): List<ProcessInfo> {
|
||||||
|
val flag = MATCH_DISABLED_COMPONENTS or MATCH_UNINSTALLED_PACKAGES or
|
||||||
|
GET_ACTIVITIES or GET_SERVICES or GET_RECEIVERS or GET_PROVIDERS
|
||||||
|
val packageInfo = try {
|
||||||
|
pm.getPackageInfo(applicationInfo.packageName, flag)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Exceed binder data transfer limit, local parsing package
|
||||||
|
pm.getPackageArchiveInfo(applicationInfo.sourceDir, flag) ?: return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
return with(packageInfo) {
|
val list = LinkedHashSet<ProcessInfo>()
|
||||||
activities?.processes().orEmpty() +
|
list += packageInfo.activities?.processes().orEmpty()
|
||||||
services?.processes().orEmpty() +
|
list += packageInfo.services?.processes().orEmpty()
|
||||||
receivers?.processes().orEmpty() +
|
list += packageInfo.receivers?.processes().orEmpty()
|
||||||
providers?.processes().orEmpty() +
|
list += packageInfo.providers?.processes().orEmpty()
|
||||||
listOf(if (haveAppZygote) createProcess("${processName}_zygote") else null)
|
return list.sortedBy { it.name }
|
||||||
}.filterNotNull().distinct().sortedBy { it.name }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val comparator = compareBy<AppProcessInfo>(
|
private val comparator = compareBy<AppProcessInfo>(
|
||||||
{ it.label.lowercase(currentLocale) },
|
{ it.label.lowercase(currentLocale) },
|
||||||
{ it.packageName }
|
{ it.applicationInfo.packageName }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,7 @@ import android.view.Menu
|
|||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.view.isVisible
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.topjohnwu.magisk.R
|
import com.topjohnwu.magisk.R
|
||||||
import com.topjohnwu.magisk.arch.BaseUIFragment
|
import com.topjohnwu.magisk.arch.BaseUIFragment
|
||||||
@ -17,19 +16,13 @@ import com.topjohnwu.magisk.ktx.addSimpleItemDecoration
|
|||||||
import com.topjohnwu.magisk.ktx.addVerticalPadding
|
import com.topjohnwu.magisk.ktx.addVerticalPadding
|
||||||
import com.topjohnwu.magisk.ktx.fixEdgeEffect
|
import com.topjohnwu.magisk.ktx.fixEdgeEffect
|
||||||
import com.topjohnwu.magisk.ktx.hideKeyboard
|
import com.topjohnwu.magisk.ktx.hideKeyboard
|
||||||
import com.topjohnwu.magisk.utils.MotionRevealHelper
|
|
||||||
|
|
||||||
class DenyListFragment : BaseUIFragment<DenyListViewModel, FragmentDenyMd2Binding>() {
|
class DenyListFragment : BaseUIFragment<DenyListViewModel, FragmentDenyMd2Binding>() {
|
||||||
|
|
||||||
override val layoutRes = R.layout.fragment_deny_md2
|
override val layoutRes = R.layout.fragment_deny_md2
|
||||||
override val viewModel by viewModel<DenyListViewModel>()
|
override val viewModel by viewModel<DenyListViewModel>()
|
||||||
|
|
||||||
private var isFilterVisible
|
private lateinit var searchView: SearchView
|
||||||
get() = binding.processFilter.isVisible
|
|
||||||
set(value) {
|
|
||||||
if (!value) hideKeyboard()
|
|
||||||
MotionRevealHelper.withViews(binding.processFilter, binding.filterToggle, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
@ -40,12 +33,6 @@ class DenyListFragment : BaseUIFragment<DenyListViewModel, FragmentDenyMd2Bindin
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
binding.filterToggle.setOnClickListener {
|
|
||||||
isFilterVisible = true
|
|
||||||
}
|
|
||||||
binding.appFilterInclude.filterDone.setOnClickListener {
|
|
||||||
isFilterVisible = false
|
|
||||||
}
|
|
||||||
binding.appList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
binding.appList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
|
||||||
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
|
||||||
if (newState != RecyclerView.SCROLL_STATE_IDLE) hideKeyboard()
|
if (newState != RecyclerView.SCROLL_STATE_IDLE) hideKeyboard()
|
||||||
@ -66,36 +53,56 @@ class DenyListFragment : BaseUIFragment<DenyListViewModel, FragmentDenyMd2Bindin
|
|||||||
bottom = l_50,
|
bottom = l_50,
|
||||||
)
|
)
|
||||||
binding.appList.fixEdgeEffect()
|
binding.appList.fixEdgeEffect()
|
||||||
|
|
||||||
val lama = binding.appList.layoutManager ?: return
|
|
||||||
lama.isAutoMeasureEnabled = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPreBind(binding: FragmentDenyMd2Binding) = Unit
|
override fun onPreBind(binding: FragmentDenyMd2Binding) = Unit
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean {
|
override fun onBackPressed(): Boolean {
|
||||||
if (isFilterVisible) {
|
if (searchView.isIconfiedByDefault && !searchView.isIconified) {
|
||||||
isFilterVisible = false
|
searchView.isIconified = true
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return super.onBackPressed()
|
return super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater.inflate(R.menu.menu_hide_md2, menu)
|
inflater.inflate(R.menu.menu_deny_md2, menu)
|
||||||
|
searchView = menu.findItem(R.id.action_search).actionView as SearchView
|
||||||
|
searchView.queryHint = searchView.context.getString(R.string.hide_filter_hint)
|
||||||
|
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||||
|
override fun onQueryTextSubmit(query: String?): Boolean {
|
||||||
|
viewModel.query = query ?: ""
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onQueryTextChange(newText: String?): Boolean {
|
||||||
|
viewModel.query = newText ?: ""
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_focus_up -> binding.appList
|
R.id.action_show_system -> {
|
||||||
.takeIf { (it.layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition() ?: 0 > 10 }
|
val check = !item.isChecked
|
||||||
?.also { it.scrollToPosition(10) }
|
viewModel.isShowSystem = check
|
||||||
.let { binding.appList }
|
item.isChecked = check
|
||||||
.also { it.post { it.smoothScrollToPosition(0) } }
|
return true
|
||||||
|
}
|
||||||
|
R.id.action_show_OS -> {
|
||||||
|
val check = !item.isChecked
|
||||||
|
viewModel.isShowOS = check
|
||||||
|
item.isChecked = check
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||||
|
val showSystem = menu.findItem(R.id.action_show_system)
|
||||||
|
val showOS = menu.findItem(R.id.action_show_OS)
|
||||||
|
showOS.isEnabled = showSystem.isChecked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,42 +4,39 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
import android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
import androidx.databinding.Bindable
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.topjohnwu.magisk.BR
|
import com.topjohnwu.magisk.BR
|
||||||
import com.topjohnwu.magisk.arch.BaseViewModel
|
import com.topjohnwu.magisk.arch.BaseViewModel
|
||||||
import com.topjohnwu.magisk.arch.Queryable
|
import com.topjohnwu.magisk.arch.Queryable
|
||||||
import com.topjohnwu.magisk.core.Config
|
|
||||||
import com.topjohnwu.magisk.databinding.filterableListOf
|
import com.topjohnwu.magisk.databinding.filterableListOf
|
||||||
import com.topjohnwu.magisk.databinding.itemBindingOf
|
import com.topjohnwu.magisk.databinding.itemBindingOf
|
||||||
import com.topjohnwu.magisk.databinding.set
|
|
||||||
import com.topjohnwu.magisk.di.AppContext
|
import com.topjohnwu.magisk.di.AppContext
|
||||||
import com.topjohnwu.magisk.utils.Utils
|
import com.topjohnwu.magisk.utils.Utils
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
class DenyListViewModel : BaseViewModel(), Queryable {
|
class DenyListViewModel : BaseViewModel(), Queryable {
|
||||||
|
|
||||||
override val queryDelay = 1000L
|
override val queryDelay = 0L
|
||||||
|
|
||||||
@get:Bindable
|
var isShowSystem = false
|
||||||
var isShowSystem = Config.showSystemApp
|
set(value) {
|
||||||
set(value) = set(value, field, { field = it }, BR.showSystem) {
|
field = value
|
||||||
Config.showSystemApp = it
|
|
||||||
submitQuery()
|
submitQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:Bindable
|
|
||||||
var isShowOS = false
|
var isShowOS = false
|
||||||
set(value) = set(value, field, { field = it }, BR.showOS) {
|
set(value) {
|
||||||
|
field = value
|
||||||
submitQuery()
|
submitQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:Bindable
|
|
||||||
var query = ""
|
var query = ""
|
||||||
set(value) = set(value, field, { field = it }, BR.query) {
|
set(value) {
|
||||||
|
field = value
|
||||||
submitQuery()
|
submitQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,64 +57,43 @@ class DenyListViewModel : BaseViewModel(), Queryable {
|
|||||||
state = State.LOADING
|
state = State.LOADING
|
||||||
val (apps, diff) = withContext(Dispatchers.Default) {
|
val (apps, diff) = withContext(Dispatchers.Default) {
|
||||||
val pm = AppContext.packageManager
|
val pm = AppContext.packageManager
|
||||||
val hideList = Shell.su("magisk --denylist ls").exec().out.map { CmdlineListItem(it) }
|
val denyList = Shell.su("magisk --denylist ls").exec().out
|
||||||
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES)
|
.map { CmdlineListItem(it) }
|
||||||
.asSequence()
|
val apps = pm.getInstalledApplications(MATCH_UNINSTALLED_PACKAGES).parallelStream()
|
||||||
.filterNot { blacklist.contains(it.packageName) }
|
.filter { AppContext.packageName != it.packageName }
|
||||||
.map { AppProcessInfo(it, pm, hideList) }
|
.map { AppProcessInfo(it, pm, denyList) }
|
||||||
.filter { it.processes.isNotEmpty() }
|
.filter { it.processes.isNotEmpty() }
|
||||||
.filter { info -> info.enabled || info.processes.any { it.isEnabled } }
|
|
||||||
.map { DenyListRvItem(it) }
|
.map { DenyListRvItem(it) }
|
||||||
.toList()
|
|
||||||
.sorted()
|
.sorted()
|
||||||
|
.collect(Collectors.toList())
|
||||||
apps to items.calculateDiff(apps)
|
apps to items.calculateDiff(apps)
|
||||||
}
|
}
|
||||||
items.update(apps, diff)
|
items.update(apps, diff)
|
||||||
submitQuery()
|
submitQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
override fun query() {
|
override fun query() {
|
||||||
|
fun isApp(uid: Int) = run {
|
||||||
|
val appId: Int = uid % 100000
|
||||||
|
appId >= Process.FIRST_APPLICATION_UID && appId <= Process.LAST_APPLICATION_UID
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSystemApp(flag: Int) = flag and ApplicationInfo.FLAG_SYSTEM != 0
|
||||||
|
|
||||||
items.filter {
|
items.filter {
|
||||||
fun showHidden() = it.itemsChecked != 0
|
fun filterSystem() = isShowSystem || !isSystemApp(it.info.applicationInfo.flags)
|
||||||
|
|
||||||
fun filterSystem() = isShowSystem || it.info.flags and ApplicationInfo.FLAG_SYSTEM == 0
|
fun filterOS() = (isShowSystem && isShowOS) || isApp(it.info.applicationInfo.uid)
|
||||||
|
|
||||||
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 filterQuery(): Boolean {
|
||||||
fun inName() = it.info.label.contains(query, true)
|
fun inName() = it.info.label.contains(query, true)
|
||||||
fun inPackage() = it.info.packageName.contains(query, true)
|
fun inPackage() = it.info.applicationInfo.packageName.contains(query, true)
|
||||||
fun inProcesses() = it.processes.any { p -> p.process.name.contains(query, true) }
|
fun inProcesses() = it.processes.any { p -> p.process.name.contains(query, true) }
|
||||||
return inName() || inPackage() || inProcesses()
|
return inName() || inPackage() || inProcesses()
|
||||||
}
|
}
|
||||||
|
|
||||||
showHidden() || (filterSystem() && filterOS() && filterQuery())
|
filterSystem() && filterOS() && filterQuery()
|
||||||
}
|
}
|
||||||
state = State.LOADED
|
state = State.LOADED
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---
|
|
||||||
|
|
||||||
fun resetQuery() {
|
|
||||||
query = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val blacklist by lazy { listOf(
|
|
||||||
AppContext.packageName,
|
|
||||||
"com.android.chrome",
|
|
||||||
"com.chrome.beta",
|
|
||||||
"com.chrome.dev",
|
|
||||||
"com.chrome.canary",
|
|
||||||
"com.android.webview",
|
|
||||||
"com.google.android.webview"
|
|
||||||
) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,9 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="475.084"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="475.084">
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
<group
|
android:fillColor="?colorOnSurface"
|
||||||
android:pivotX="237.542"
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27c1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48l0.27,0.28v0.79l4.25,4.25c0.41,0.41 1.08,0.41 1.49,0 0.41,-0.41 0.41,-1.08 0,-1.49L15.5,14zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||||
android:pivotY="237.542"
|
|
||||||
android:scaleX="0.8"
|
|
||||||
android:scaleY="0.8">
|
|
||||||
<path
|
|
||||||
android:fillColor="?colorOnSurface"
|
|
||||||
android:pathData="M464.524,412.846l-97.929,-97.925c23.6,-34.068 35.406,-72.047 35.406,-113.917c0,-27.218 -5.284,-53.249 -15.852,-78.087c-10.561,-24.842 -24.838,-46.254 -42.825,-64.241c-17.987,-17.987 -39.396,-32.264 -64.233,-42.826C254.246,5.285 228.217,0.003 200.999,0.003c-27.216,0 -53.247,5.282 -78.085,15.847C98.072,26.412 76.66,40.689 58.673,58.676c-17.989,17.987 -32.264,39.403 -42.827,64.241C5.282,147.758 0,173.786 0,201.004c0,27.216 5.282,53.238 15.846,78.083c10.562,24.838 24.838,46.247 42.827,64.234c17.987,17.993 39.403,32.264 64.241,42.832c24.841,10.563 50.869,15.844 78.085,15.844c41.879,0 79.852,-11.807 113.922,-35.405l97.929,97.641c6.852,7.231 15.406,10.849 25.693,10.849c9.897,0 18.467,-3.617 25.694,-10.849c7.23,-7.23 10.848,-15.796 10.848,-25.693C475.088,428.458 471.567,419.889 464.524,412.846zM291.363,291.358c-25.029,25.033 -55.148,37.549 -90.364,37.549c-35.21,0 -65.329,-12.519 -90.36,-37.549c-25.031,-25.029 -37.546,-55.144 -37.546,-90.36c0,-35.21 12.518,-65.334 37.546,-90.36c25.026,-25.032 55.15,-37.546 90.36,-37.546c35.212,0 65.331,12.519 90.364,37.546c25.033,25.026 37.548,55.15 37.548,90.36C328.911,236.214 316.392,266.329 291.363,291.358z"
|
|
||||||
tools:fillColor="@android:color/black" />
|
|
||||||
</group>
|
|
||||||
</vector>
|
</vector>
|
||||||
|
@ -1,166 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<data>
|
|
||||||
|
|
||||||
<import type="com.topjohnwu.magisk.R" />
|
|
||||||
|
|
||||||
<variable
|
|
||||||
name="viewModel"
|
|
||||||
type="com.topjohnwu.magisk.ui.deny.DenyListViewModel" />
|
|
||||||
|
|
||||||
</data>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingStart="@dimen/l1"
|
|
||||||
android:paddingTop="@dimen/l1"
|
|
||||||
android:paddingEnd="@dimen/l1"
|
|
||||||
android:paddingBottom="@dimen/l1"
|
|
||||||
app:fitsSystemWindowsInsets="bottom"
|
|
||||||
tools:layout_gravity="bottom"
|
|
||||||
tools:paddingBottom="64dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/filter_title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/hide_filters"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
|
||||||
android:textColor="?colorPrimary"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/hide_filter_chip_group"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/l1"
|
|
||||||
app:chipSpacing="2dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/filter_title">
|
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
|
||||||
android:id="@+id/hide_filter_system_chip"
|
|
||||||
style="@style/Widget.MaterialComponents.Chip.Filter"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:checked="@={viewModel.showSystem}"
|
|
||||||
android:nextFocusRight="@id/hide_filter_chip_data"
|
|
||||||
android:nextFocusDown="@id/hide_filter_search_field"
|
|
||||||
android:text="@string/show_system_app"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
|
||||||
app:checkedIcon="@drawable/ic_check_md2"
|
|
||||||
app:chipBackgroundColor="?colorSurfaceVariant"
|
|
||||||
tools:checked="true" />
|
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
|
||||||
android:id="@+id/hide_filter_os_chip"
|
|
||||||
style="@style/Widget.MaterialComponents.Chip.Filter"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:checked="@={viewModel.showOS}"
|
|
||||||
android:nextFocusRight="@id/hide_filter_chip_data"
|
|
||||||
android:nextFocusDown="@id/hide_filter_search_field"
|
|
||||||
android:text="@string/show_os_app"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
|
||||||
app:checkedIcon="@drawable/ic_check_md2"
|
|
||||||
app:chipBackgroundColor="?colorSurfaceVariant"
|
|
||||||
tools:checked="true" />
|
|
||||||
|
|
||||||
<com.google.android.material.chip.Chip
|
|
||||||
android:id="@+id/hide_filter_chip_data"
|
|
||||||
style="@style/Widget.MaterialComponents.Chip.Entry"
|
|
||||||
gone="@{viewModel.query.empty}"
|
|
||||||
onCloseClicked="@{() -> viewModel.resetQuery()}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:checkable="false"
|
|
||||||
android:nextFocusRight="@id/filter_done"
|
|
||||||
android:nextFocusDown="@id/hide_filter_search_field"
|
|
||||||
android:text="@{viewModel.query}"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
|
||||||
app:chipBackgroundColor="?colorSurfaceVariant" />
|
|
||||||
|
|
||||||
</com.google.android.material.chip.ChipGroup>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/hide_filter_title_search"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/l1"
|
|
||||||
android:text="@string/hide_search"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption"
|
|
||||||
android:textColor="?colorPrimary"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/hide_filter_chip_group" />
|
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
|
||||||
android:id="@+id/hide_filter_search"
|
|
||||||
style="@style/WidgetFoundation.Card"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/l1"
|
|
||||||
android:layout_marginEnd="@dimen/l1"
|
|
||||||
android:layout_marginBottom="@dimen/l_50"
|
|
||||||
app:cardCornerRadius="18dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/filter_done"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/hide_filter_title_search">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
style="@style/WidgetFoundation.Icon"
|
|
||||||
android:layout_width="48dp"
|
|
||||||
android:layout_height="36dp"
|
|
||||||
android:layout_gravity="center_vertical|start"
|
|
||||||
android:padding="6dp"
|
|
||||||
app:srcCompat="@drawable/ic_search_md2"
|
|
||||||
app:tint="?colorDisabled" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/hide_filter_search_field"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="48dp"
|
|
||||||
android:background="@null"
|
|
||||||
android:gravity="start|center_vertical"
|
|
||||||
android:hint="@string/hide_filter_hint"
|
|
||||||
android:inputType="textUri"
|
|
||||||
android:minHeight="36dp"
|
|
||||||
android:nextFocusRight="@id/filter_done"
|
|
||||||
android:paddingStart="0dp"
|
|
||||||
android:paddingEnd="@dimen/l1"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:text="@={viewModel.query}"
|
|
||||||
android:textAppearance="@style/AppearanceFoundation.Body"
|
|
||||||
android:textColor="@color/color_text_transient"
|
|
||||||
android:textColorHint="?colorOnSurfaceVariant" />
|
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/filter_done"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:nextFocusLeft="@id/hide_filter_system_chip"
|
|
||||||
app:backgroundTint="?colorPrimary"
|
|
||||||
app:elevation="0dp"
|
|
||||||
app:fabSize="mini"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/hide_filter_search"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/hide_filter_search"
|
|
||||||
app:srcCompat="@drawable/ic_check_md2"
|
|
||||||
app:tint="?colorOnPrimary" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</layout>
|
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/app_list"
|
android:id="@+id/app_list"
|
||||||
invisibleUnless="@{viewModel.loaded || !viewModel.items.empty}"
|
invisibleUnless="@{viewModel.loaded}"
|
||||||
itemBinding="@{viewModel.itemBinding}"
|
itemBinding="@{viewModel.itemBinding}"
|
||||||
items="@{viewModel.items}"
|
items="@{viewModel.items}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -30,42 +30,8 @@
|
|||||||
tools:listitem="@layout/item_hide_md2"
|
tools:listitem="@layout/item_hide_md2"
|
||||||
tools:paddingTop="40dp" />
|
tools:paddingTop="40dp" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:id="@+id/filter_toggle"
|
|
||||||
invisibleUnless="@{viewModel.loaded || !viewModel.items.empty}"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_marginStart="@dimen/l1"
|
|
||||||
android:layout_marginEnd="@dimen/l1"
|
|
||||||
android:layout_marginBottom="@dimen/l1"
|
|
||||||
app:backgroundTint="?colorSurfaceSurfaceVariant"
|
|
||||||
app:layout_fitsSystemWindowsInsets="bottom"
|
|
||||||
app:srcCompat="@drawable/ic_search_md2"
|
|
||||||
app:tint="?colorPrimary"
|
|
||||||
tools:layout_marginBottom="64dp" />
|
|
||||||
|
|
||||||
<com.google.android.material.circularreveal.cardview.CircularRevealCardView
|
|
||||||
android:id="@+id/process_filter"
|
|
||||||
style="@style/WidgetFoundation.Card"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:visibility="invisible"
|
|
||||||
app:layout_fitsSystemWindowsInsets="bottom"
|
|
||||||
app:cardCornerRadius="0dp">
|
|
||||||
|
|
||||||
<include
|
|
||||||
android:id="@+id/app_filter_include"
|
|
||||||
layout="@layout/app_list_filter"
|
|
||||||
viewModel="@{viewModel}"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
</com.google.android.material.circularreveal.cardview.CircularRevealCardView>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
goneUnless="@{viewModel.loading && viewModel.items.empty}"
|
goneUnless="@{viewModel.loading}"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
android:id="@+id/hide_package"
|
android:id="@+id/hide_package"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{item.info.packageName}"
|
android:text="@{item.info.applicationInfo.packageName}"
|
||||||
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
|
android:textAppearance="@style/AppearanceFoundation.Caption.Variant"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="@+id/hide_name"
|
app:layout_constraintEnd_toEndOf="@+id/hide_name"
|
||||||
|
20
app/src/main/res/menu/menu_deny_md2.xml
Normal file
20
app/src/main/res/menu/menu_deny_md2.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_search"
|
||||||
|
android:icon="@drawable/ic_search_md2"
|
||||||
|
android:title="@string/hide_search"
|
||||||
|
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_show_system"
|
||||||
|
android:checkable="true"
|
||||||
|
android:title="@string/show_system_app"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_show_OS"
|
||||||
|
android:checkable="true"
|
||||||
|
android:title="@string/show_os_app"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
</menu>
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_focus_up"
|
|
||||||
android:icon="@drawable/ic_up_md2"
|
|
||||||
android:title="@string/hide_scroll_up"
|
|
||||||
app:showAsAction="ifRoom" />
|
|
||||||
</menu>
|
|
Loading…
x
Reference in New Issue
Block a user