Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions app/src/main/java/me/bmax/apatch/ui/component/SearchBar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ fun SearchAppBar(
onBackClick: (() -> Unit)? = null,
onConfirm: (() -> Unit)? = null,
dropdownContent: @Composable (() -> Unit)? = null,
leadingActions: @Composable (() -> Unit)? = null,
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusRequester = remember { FocusRequester() }
Expand Down Expand Up @@ -144,10 +145,15 @@ fun SearchAppBar(
AnimatedVisibility(
visible = !onSearch
) {
IconButton(
onClick = { onSearch = true },
content = { Icon(Icons.Filled.Search, null) }
)
androidx.compose.foundation.layout.Row(
verticalAlignment = Alignment.CenterVertically
) {
leadingActions?.invoke()
IconButton(
onClick = { onSearch = true },
content = { Icon(Icons.Filled.Search, null) }
)
}
}

dropdownContent?.invoke()
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/java/me/bmax/apatch/ui/screen/SuperUser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.PlaylistAddCheck
import androidx.compose.material.icons.filled.Security
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
Expand All @@ -28,6 +30,7 @@ import androidx.compose.material3.ListItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
Expand Down Expand Up @@ -66,6 +69,31 @@ import me.bmax.apatch.util.PkgConfig
fun SuperUserScreen() {
val viewModel = viewModel<SuperUserViewModel>()
val scope = rememberCoroutineScope()
var showBatchExcludeDialog by remember { mutableStateOf(false) }

if (showBatchExcludeDialog) {
AlertDialog(
onDismissRequest = { showBatchExcludeDialog = false },
title = { Text(stringResource(R.string.su_batch_exclude_title)) },
text = { Text(stringResource(R.string.su_batch_exclude_content)) },
confirmButton = {
TextButton(onClick = {
viewModel.excludeAll()
showBatchExcludeDialog = false
}) {
Text(stringResource(R.string.su_exclude_btn))
}
},
dismissButton = {
TextButton(onClick = {
viewModel.reverseExcludeAll()
showBatchExcludeDialog = false
}) {
Text(stringResource(R.string.su_exclude_reverse_btn))
}
}
)
}

LaunchedEffect(Unit) {
if (viewModel.appList.isEmpty()) {
Expand All @@ -80,6 +108,11 @@ fun SuperUserScreen() {
searchText = viewModel.search,
onSearchTextChange = { viewModel.search = it },
onClearClick = { viewModel.search = "" },
leadingActions = {
IconButton(onClick = { showBatchExcludeDialog = true }) {
Icon(Icons.Filled.PlaylistAddCheck, null)
}
},
dropdownContent = {
var showDropdown by remember { mutableStateOf(false) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
import me.bmax.apatch.APApplication
import me.bmax.apatch.IAPRootService
import me.bmax.apatch.Natives
import me.bmax.apatch.apApp
Expand Down Expand Up @@ -98,6 +99,49 @@ class SuperUserViewModel : ViewModel() {
task?.let { it1 -> shell.execTask(it1) }
}

fun excludeAll() {
val modifiedConfigs = mutableListOf<PkgConfig.Config>()
val currentApps = apps

currentApps.forEach { app ->
if (app.config.allow == 0 && app.config.exclude == 0) {
app.config.exclude = 1
app.config.profile.scontext = APApplication.DEFAULT_SCONTEXT
Natives.setUidExclude(app.uid, 1)
modifiedConfigs.add(app.config)
}
}

if (modifiedConfigs.isNotEmpty()) {
PkgConfig.batchChangeConfigs(modifiedConfigs)
// Force UI update
apps = ArrayList(currentApps)
}
}

fun reverseExcludeAll() {
val modifiedConfigs = mutableListOf<PkgConfig.Config>()
val currentApps = apps

currentApps.forEach { app ->
if (app.config.allow == 0) {
val newExclude = if (app.config.exclude == 1) 0 else 1
app.config.exclude = newExclude
if (newExclude == 1) {
app.config.profile.scontext = APApplication.DEFAULT_SCONTEXT
}
Natives.setUidExclude(app.uid, newExclude)
modifiedConfigs.add(app.config)
}
}

if (modifiedConfigs.isNotEmpty()) {
PkgConfig.batchChangeConfigs(modifiedConfigs)
// Force UI update
apps = ArrayList(currentApps)
}
}

private fun stopRootService() {
val intent = Intent(apApp, RootServices::class.java)
RootServices.stop(intent)
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/me/bmax/apatch/util/PkgConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,28 @@ object PkgConfig {
}
}
}

fun batchChangeConfigs(newConfigs: List<Config>) {
thread {
synchronized(PkgConfig.javaClass) {
Natives.su()
val configs = readConfigs()

newConfigs.forEach { config ->
val uid = config.profile.uid
// Root App should not be excluded
if (config.allow == 1) {
config.exclude = 0
}

if (config.isDefault() && configs[uid] != null) {
configs.remove(uid)
} else {
configs[uid] = config
}
}
writeConfigs(configs)
}
}
}
}
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@
<string name="su_show_system_apps">Show system apps</string>
<string name="su_hide_system_apps">Hide system apps</string>
<string name="su_refresh">Refresh</string>
<string name="su_batch_exclude_title">Batch Exclude</string>
<string name="su_batch_exclude_content">Exclude injection for all non-ROOT apps, please select an action</string>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact it's all modifications, but not scoped to injection imo.

<string name="su_exclude_btn">Exclude</string>
<string name="su_exclude_reverse_btn">Reverse</string>

<string name="apm">APModule</string>
<string name="apm_not_installed">AndroidPatch not installed</string>
Expand Down
Loading