mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 11:05:59 +00:00
@@ -255,6 +255,9 @@ class MainActivity : FragmentActivity() {
|
|||||||
val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
val launcher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
||||||
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
}
|
}
|
||||||
|
registerPackageRemovedReceiver(this) {
|
||||||
|
vm.onPackageRemoved(it)
|
||||||
|
}
|
||||||
setContent {
|
setContent {
|
||||||
var appLockDialog by rememberSaveable { mutableStateOf(false) }
|
var appLockDialog by rememberSaveable { mutableStateOf(false) }
|
||||||
val theme by vm.theme.collectAsStateWithLifecycle()
|
val theme by vm.theme.collectAsStateWithLifecycle()
|
||||||
|
|||||||
@@ -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) =
|
fun getAppInfo(info: ApplicationInfo) =
|
||||||
AppInfo(info.packageName, info.loadLabel(PM).toString(), info.loadIcon(PM), info.flags)
|
AppInfo(info.packageName, info.loadLabel(PM).toString(), info.loadIcon(PM), info.flags)
|
||||||
fun getAppInfo(name: String): AppInfo {
|
fun getAppInfo(name: String): AppInfo {
|
||||||
@@ -361,9 +366,6 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
|||||||
context.unregisterReceiver(this)
|
context.unregisterReceiver(this)
|
||||||
if (statusExtra == PackageInstaller.STATUS_SUCCESS) {
|
if (statusExtra == PackageInstaller.STATUS_SUCCESS) {
|
||||||
onComplete(null)
|
onComplete(null)
|
||||||
installedPackages.update { pkg ->
|
|
||||||
pkg.filter { it.name != packageName }
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
onComplete(parsePackageInstallerMessage(context, intent))
|
onComplete(parsePackageInstallerMessage(context, intent))
|
||||||
}
|
}
|
||||||
@@ -464,14 +466,18 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
|||||||
DPM.isUninstallBlocked(DAR, name),
|
DPM.isUninstallBlocked(DAR, name),
|
||||||
if (VERSION.SDK_INT >= 30) name in DPM.getUserControlDisabledPackages(DAR) else false,
|
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) 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
|
// Application details
|
||||||
@RequiresApi(24)
|
@RequiresApi(24)
|
||||||
fun adSetPackageSuspended(name: String, status: Boolean) {
|
fun adSetPackageSuspended(name: String, status: Boolean) {
|
||||||
DPM.setPackagesSuspended(DAR, arrayOf(name), status)
|
try {
|
||||||
appStatus.update { it.copy(suspend = DPM.isPackageSuspended(DAR, name)) }
|
DPM.setPackagesSuspended(DAR, arrayOf(name), status)
|
||||||
|
appStatus.update { it.copy(suspend = DPM.isPackageSuspended(DAR, name)) }
|
||||||
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
fun adSetPackageHidden(name: String, status: Boolean) {
|
fun adSetPackageHidden(name: String, status: Boolean) {
|
||||||
DPM.setApplicationHidden(DAR, name, status)
|
DPM.setApplicationHidden(DAR, name, status)
|
||||||
@@ -522,21 +528,25 @@ class MyViewModel(application: Application): AndroidViewModel(application) {
|
|||||||
@RequiresApi(23)
|
@RequiresApi(23)
|
||||||
fun getAppRestrictions(name: String) {
|
fun getAppRestrictions(name: String) {
|
||||||
val rm = application.getSystemService(RestrictionsManager::class.java)
|
val rm = application.getSystemService(RestrictionsManager::class.java)
|
||||||
val bundle = DPM.getApplicationRestrictions(DAR, name)
|
try {
|
||||||
appRestrictions.value = rm.getManifestRestrictions(name)?.mapNotNull {
|
val bundle = DPM.getApplicationRestrictions(DAR, name)
|
||||||
transformRestrictionEntry(it)
|
appRestrictions.value = rm.getManifestRestrictions(name)?.mapNotNull {
|
||||||
}?.map {
|
transformRestrictionEntry(it)
|
||||||
if (bundle.containsKey(it.key)) {
|
}?.map {
|
||||||
when (it) {
|
if (bundle.containsKey(it.key)) {
|
||||||
is AppRestriction.BooleanItem -> it.value = bundle.getBoolean(it.key)
|
when (it) {
|
||||||
is AppRestriction.StringItem -> it.value = bundle.getString(it.key)
|
is AppRestriction.BooleanItem -> it.value = bundle.getBoolean(it.key)
|
||||||
is AppRestriction.IntItem -> it.value = bundle.getInt(it.key)
|
is AppRestriction.StringItem -> it.value = bundle.getString(it.key)
|
||||||
is AppRestriction.ChoiceItem -> it.value = bundle.getString(it.key)
|
is AppRestriction.IntItem -> it.value = bundle.getInt(it.key)
|
||||||
is AppRestriction.MultiSelectItem -> it.value = bundle.getStringArray(it.key)
|
is AppRestriction.ChoiceItem -> it.value = bundle.getString(it.key)
|
||||||
|
is AppRestriction.MultiSelectItem -> it.value = bundle.getStringArray(it.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
it
|
||||||
it
|
} ?: emptyList()
|
||||||
} ?: emptyList()
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(23)
|
@RequiresApi(23)
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.bintianqi.owndroid
|
package com.bintianqi.owndroid
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@@ -160,3 +163,17 @@ fun adaptiveInsets(): WindowInsets {
|
|||||||
val navbar = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)
|
val navbar = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)
|
||||||
return WindowInsets.ime.union(navbar).union(WindowInsets.displayCutout)
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import androidx.compose.foundation.clickable
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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.OutlinedTextField
|
||||||
import androidx.compose.material3.RadioButton
|
import androidx.compose.material3.RadioButton
|
||||||
import androidx.compose.material3.Scaffold
|
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.Surface
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -121,7 +123,6 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import sh.calvin.reorderable.ReorderableItem
|
import sh.calvin.reorderable.ReorderableItem
|
||||||
import sh.calvin.reorderable.rememberReorderableLazyListState
|
import sh.calvin.reorderable.rememberReorderableLazyListState
|
||||||
import kotlin.collections.indexOf
|
|
||||||
|
|
||||||
val String.isValidPackageName
|
val String.isValidPackageName
|
||||||
get() = Regex("""^(?:[a-zA-Z]\w*\.)+[a-zA-Z]\w*$""").matches(this)
|
get() = Regex("""^(?:[a-zA-Z]\w*\.)+[a-zA-Z]\w*$""").matches(this)
|
||||||
@@ -540,20 +541,23 @@ private fun UninstallAppDialog(
|
|||||||
confirmButton = {
|
confirmButton = {
|
||||||
TextButton(
|
TextButton(
|
||||||
{
|
{
|
||||||
uninstalling = true
|
if (errorMessage == null) {
|
||||||
onUninstall(packageName) {
|
uninstalling = true
|
||||||
uninstalling = false
|
onUninstall(packageName) {
|
||||||
if (it == null) onClose(true) else errorMessage = it
|
uninstalling = false
|
||||||
|
if (it == null) onClose(true) else errorMessage = it
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onClose(false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled = !uninstalling,
|
enabled = !uninstalling
|
||||||
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
|
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.confirm))
|
Text(stringResource(R.string.confirm))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dismissButton = {
|
dismissButton = {
|
||||||
TextButton({
|
if (errorMessage == null) TextButton({
|
||||||
onClose(false)
|
onClose(false)
|
||||||
}, enabled = !uninstalling) { Text(stringResource(R.string.cancel)) }
|
}, enabled = !uninstalling) { Text(stringResource(R.string.cancel)) }
|
||||||
},
|
},
|
||||||
@@ -1254,7 +1258,20 @@ fun ManagedConfigurationDialog(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
is AppRestriction.BooleanItem -> item {
|
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 ->
|
is AppRestriction.ChoiceItem -> itemsIndexed(restriction.entryValues) { index, value ->
|
||||||
val label = restriction.entries.getOrNull(index)
|
val label = restriction.entries.getOrNull(index)
|
||||||
|
|||||||
Reference in New Issue
Block a user