Fix bugs of application functions (#205, #206, #207)

This commit is contained in:
BinTianqi
2025-11-26 22:20:26 +08:00
parent ed6908a5cd
commit 001d013b0c
4 changed files with 78 additions and 31 deletions

View File

@@ -255,6 +255,9 @@ class MainActivity : FragmentActivity() {
val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
registerPackageRemovedReceiver(this) {
vm.onPackageRemoved(it)
}
setContent {
var appLockDialog by rememberSaveable { mutableStateOf(false) }
val theme by vm.theme.collectAsStateWithLifecycle()

View File

@@ -200,6 +200,11 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
}
}
}
fun onPackageRemoved(name: String) {
installedPackages.update { list ->
list.filter { it.name != name }
}
}
fun getAppInfo(info: ApplicationInfo) =
AppInfo(info.packageName, info.loadLabel(PM).toString(), info.loadIcon(PM), info.flags)
fun getAppInfo(name: String): AppInfo {
@@ -361,9 +366,6 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
context.unregisterReceiver(this)
if (statusExtra == PackageInstaller.STATUS_SUCCESS) {
onComplete(null)
installedPackages.update { pkg ->
pkg.filter { it.name != packageName }
}
} else {
onComplete(parsePackageInstallerMessage(context, intent))
}
@@ -464,14 +466,18 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
DPM.isUninstallBlocked(DAR, name),
if (VERSION.SDK_INT >= 30) name in DPM.getUserControlDisabledPackages(DAR) else false,
if (VERSION.SDK_INT >= 28) name in DPM.getMeteredDataDisabledPackages(DAR) else false,
if (VERSION.SDK_INT >= 28) DPM.getKeepUninstalledPackages(DAR)?.contains(name) == true else false
if (VERSION.SDK_INT >= 28 && Privilege.status.value.device)
DPM.getKeepUninstalledPackages(DAR)?.contains(name) == true
else false
)
}
// Application details
@RequiresApi(24)
fun adSetPackageSuspended(name: String, status: Boolean) {
try {
DPM.setPackagesSuspended(DAR, arrayOf(name), status)
appStatus.update { it.copy(suspend = DPM.isPackageSuspended(DAR, name)) }
} catch (_: Exception) {}
}
fun adSetPackageHidden(name: String, status: Boolean) {
DPM.setApplicationHidden(DAR, name, status)
@@ -522,6 +528,7 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
@RequiresApi(23)
fun getAppRestrictions(name: String) {
val rm = application.getSystemService(RestrictionsManager::class.java)
try {
val bundle = DPM.getApplicationRestrictions(DAR, name)
appRestrictions.value = rm.getManifestRestrictions(name)?.mapNotNull {
transformRestrictionEntry(it)
@@ -537,6 +544,9 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
}
it
} ?: emptyList()
} catch (e: Exception) {
e.printStackTrace()
}
}
@RequiresApi(23)

View File

@@ -1,9 +1,12 @@
package com.bintianqi.owndroid
import android.content.BroadcastReceiver
import android.content.ClipData
import android.content.ClipboardManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInfo
import android.net.Uri
import android.os.Build
@@ -160,3 +163,17 @@ fun adaptiveInsets(): WindowInsets {
val navbar = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)
return WindowInsets.ime.union(navbar).union(WindowInsets.displayCutout)
}
fun registerPackageRemovedReceiver(
ctx: Context, callback: (String) -> Unit
) {
val br = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
callback(intent.data!!.schemeSpecificPart)
}
}
val filter = IntentFilter()
filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED)
filter.addDataScheme("package")
ctx.registerReceiver(br, filter)
}

View File

@@ -14,7 +14,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -63,6 +62,9 @@ import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
@@ -121,7 +123,6 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.serialization.Serializable
import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState
import kotlin.collections.indexOf
val String.isValidPackageName
get() = Regex("""^(?:[a-zA-Z]\w*\.)+[a-zA-Z]\w*$""").matches(this)
@@ -540,20 +541,23 @@ private fun UninstallAppDialog(
confirmButton = {
TextButton(
{
if (errorMessage == null) {
uninstalling = true
onUninstall(packageName) {
uninstalling = false
if (it == null) onClose(true) else errorMessage = it
}
} else {
onClose(false)
}
},
enabled = !uninstalling,
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
enabled = !uninstalling
) {
Text(stringResource(R.string.confirm))
}
},
dismissButton = {
TextButton({
if (errorMessage == null) TextButton({
onClose(false)
}, enabled = !uninstalling) { Text(stringResource(R.string.cancel)) }
},
@@ -1254,7 +1258,20 @@ fun ManagedConfigurationDialog(
)
}
is AppRestriction.BooleanItem -> item {
Switch(inputState, { inputState = it })
SingleChoiceSegmentedButtonRow(Modifier.fillMaxWidth()) {
SegmentedButton(
inputState, { inputState = true },
SegmentedButtonDefaults.itemShape(0, 2)
) {
Text("true")
}
SegmentedButton(
!inputState, { inputState = false },
SegmentedButtonDefaults.itemShape(1, 2)
) {
Text("false")
}
}
}
is AppRestriction.ChoiceItem -> itemsIndexed(restriction.entryValues) { index, value ->
val label = restriction.entries.getOrNull(index)