Optimize code

New Privilege object, which follows Application lifecycle.
Add Privilege.DPM and Privilege.DAR variable, instead of creating DPM and DAR instance every time.
This commit is contained in:
BinTianqi
2025-08-29 20:58:39 +08:00
parent 10ac570818
commit 6f54bf576f
22 changed files with 496 additions and 687 deletions

View File

@@ -24,6 +24,7 @@
android:enableOnBackInvokedCallback="true"
android:testOnly="false"
android:manageSpaceActivity=".ManageSpaceActivity"
android:name=".MyApplication"
tools:targetApi="35">
<activity
android:name=".MainActivity"

View File

@@ -5,19 +5,14 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import com.bintianqi.owndroid.dpm.getDPM
import com.bintianqi.owndroid.dpm.getReceiver
class ApiReceiver: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val requestKey = intent.getStringExtra("key")
var log = "OwnDroid API request received. action: ${intent.action}\nkey: $requestKey"
val sp = SharedPrefs(context)
if(!sp.isApiEnabled) return
val key = sp.apiKey
if(!SP.isApiEnabled) return
val key = SP.apiKey
if(!key.isNullOrEmpty() && key == requestKey) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
val app = intent.getStringExtra("package")
val permission = intent.getStringExtra("permission")
val restriction = intent.getStringExtra("restriction")
@@ -26,32 +21,32 @@ class ApiReceiver: BroadcastReceiver() {
try {
@SuppressWarnings("NewApi")
val ok = when(intent.action?.removePrefix("com.bintianqi.owndroid.action.")) {
"HIDE" -> dpm.setApplicationHidden(receiver, app, true)
"UNHIDE" -> dpm.setApplicationHidden(receiver, app, false)
"SUSPEND" -> dpm.setPackagesSuspended(receiver, arrayOf(app), true).isEmpty()
"UNSUSPEND" -> dpm.setPackagesSuspended(receiver, arrayOf(app), false).isEmpty()
"ADD_USER_RESTRICTION" -> { dpm.addUserRestriction(receiver, restriction); true }
"CLEAR_USER_RESTRICTION" -> { dpm.clearUserRestriction(receiver, restriction); true }
"HIDE" -> Privilege.DPM.setApplicationHidden(Privilege.DAR, app, true)
"UNHIDE" -> Privilege.DPM.setApplicationHidden(Privilege.DAR, app, false)
"SUSPEND" -> Privilege.DPM.setPackagesSuspended(Privilege.DAR, arrayOf(app), true).isEmpty()
"UNSUSPEND" -> Privilege.DPM.setPackagesSuspended(Privilege.DAR, arrayOf(app), false).isEmpty()
"ADD_USER_RESTRICTION" -> { Privilege.DPM.addUserRestriction(Privilege.DAR, restriction); true }
"CLEAR_USER_RESTRICTION" -> { Privilege.DPM.clearUserRestriction(Privilege.DAR, restriction); true }
"SET_PERMISSION_DEFAULT" -> {
dpm.setPermissionGrantState(
receiver, app!!, permission!!,
Privilege.DPM.setPermissionGrantState(
Privilege.DAR, app!!, permission!!,
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT
)
}
"SET_PERMISSION_GRANTED" -> {
dpm.setPermissionGrantState(
receiver, app!!, permission!!,
Privilege.DPM.setPermissionGrantState(
Privilege.DAR, app!!, permission!!,
DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
)
}
"SET_PERMISSION_DENIED" -> {
dpm.setPermissionGrantState(
receiver, app!!, permission!!,
Privilege.DPM.setPermissionGrantState(
Privilege.DAR, app!!, permission!!,
DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
)
}
"LOCK" -> { dpm.lockNow(); true }
"REBOOT" -> { dpm.reboot(receiver); true }
"LOCK" -> { Privilege.DPM.lockNow(); true }
"REBOOT" -> { Privilege.DPM.reboot(Privilege.DAR); true }
else -> {
log += "\nInvalid action"
false

View File

@@ -125,7 +125,6 @@ private fun AppInstaller(
result: Intent? = null,
onResultDialogClose: () -> Unit = {}
) {
val context = LocalContext.current
var appLockDialog by rememberSaveable { mutableStateOf(false) }
val coroutine = rememberCoroutineScope()
Scaffold(
@@ -142,7 +141,7 @@ private fun AppInstaller(
else Icon(Icons.Default.PlayArrow, null)
},
onClick = {
if(SharedPrefs(context).lockPasswordHash.isNullOrEmpty()) onStartInstall() else appLockDialog = true
if(SP.lockPasswordHash.isNullOrEmpty()) onStartInstall() else appLockDialog = true
},
expanded = !installing
)

View File

@@ -44,11 +44,10 @@ import androidx.compose.ui.window.DialogProperties
fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismiss, DialogProperties(true, false)) {
val context = LocalContext.current
val fm = LocalFocusManager.current
val sp = SharedPrefs(context)
var input by remember { mutableStateOf("") }
var isError by remember { mutableStateOf(false) }
fun unlock() {
if(input.hash() == sp.lockPasswordHash) {
if(input.hash() == SP.lockPasswordHash) {
fm.clearFocus()
onSucceed()
} else {
@@ -56,7 +55,7 @@ fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismi
}
}
LaunchedEffect(Unit) {
if (Build.VERSION.SDK_INT >= 28 && sp.biometricsUnlock) startBiometricsUnlock(context, onSucceed)
if (Build.VERSION.SDK_INT >= 28 && SP.biometricsUnlock) startBiometricsUnlock(context, onSucceed)
}
BackHandler(onBack = onDismiss)
Card(Modifier.pointerInput(Unit) { detectTapGestures(onTap = { fm.clearFocus() }) }, shape = RoundedCornerShape(16.dp)) {
@@ -70,7 +69,7 @@ fun AppLockDialog(onSucceed: () -> Unit, onDismiss: () -> Unit) = Dialog(onDismi
),
keyboardActions = KeyboardActions({ fm.clearFocus() }, { unlock() })
)
if(Build.VERSION.SDK_INT >= 28 && sp.biometricsUnlock) {
if(Build.VERSION.SDK_INT >= 28 && SP.biometricsUnlock) {
FilledTonalIconButton({ startBiometricsUnlock(context, onSucceed) }, Modifier.padding(start = 4.dp)) {
Icon(painterResource(R.drawable.fingerprint_fill0), null)
}

View File

@@ -11,14 +11,8 @@ import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Checkbox
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.LaunchedEffect
@@ -27,7 +21,6 @@ import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
@@ -51,14 +44,14 @@ const val DHIZUKU_CLIENTS_FILE = "dhizuku_clients.json"
class MyDhizukuProvider(): DhizukuProvider() {
override fun onCreateService(client: IDhizukuClient): DhizukuService? {
Log.d(TAG, "Creating MyDhizukuService")
return if (SharedPrefs(context!!).dhizukuServer) MyDhizukuService(context!!, MyAdminComponent, client) else null
return if (SP.dhizukuServer) MyDhizukuService(context!!, MyAdminComponent, client) else null
}
}
class MyDhizukuService(context: Context, admin: ComponentName, client: IDhizukuClient) :
DhizukuService(context, admin, client) {
override fun checkCallingPermission(func: String?, callingUid: Int, callingPid: Int): Boolean {
if (!SharedPrefs(mContext).dhizukuServer) return false
if (!SP.dhizukuServer) return false
val pm = mContext.packageManager
val packageInfo = pm.getPackageInfo(
pm.getNameForUid(callingUid) ?: return false,
@@ -87,7 +80,7 @@ class DhizukuActivity : ComponentActivity() {
@OptIn(ExperimentalStdlibApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!SharedPrefs(this).dhizukuServer) {
if (!SP.dhizukuServer) {
finish()
return
}
@@ -145,7 +138,7 @@ class DhizukuActivity : ComponentActivity() {
}
}
TextButton({
if (SharedPrefs(this).lockPasswordHash.isNullOrEmpty()) {
if (SP.lockPasswordHash.isNullOrEmpty()) {
close(true)
} else {
appLockDialog = true

View File

@@ -54,7 +54,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
@@ -235,17 +234,10 @@ import com.bintianqi.owndroid.dpm.WorkModes
import com.bintianqi.owndroid.dpm.WorkModesScreen
import com.bintianqi.owndroid.dpm.WorkProfile
import com.bintianqi.owndroid.dpm.WorkProfileScreen
import com.bintianqi.owndroid.dpm.checkPrivilege
import com.bintianqi.owndroid.dpm.dhizukuErrorStatus
import com.bintianqi.owndroid.dpm.getDPM
import com.bintianqi.owndroid.dpm.getReceiver
import com.bintianqi.owndroid.dpm.setDefaultAffiliationID
import com.bintianqi.owndroid.ui.Animations
import com.bintianqi.owndroid.ui.theme.OwnDroidTheme
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable
import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.util.Locale
@ExperimentalMaterial3Api
@@ -254,12 +246,9 @@ class MainActivity : FragmentActivity() {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
val context = applicationContext
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
val locale = context.resources?.configuration?.locale
zhCN = locale == Locale.SIMPLIFIED_CHINESE || locale == Locale.CHINESE || locale == Locale.CHINA
val vm by viewModels<MyViewModel>()
checkPrivilege(this)
lifecycleScope.launch { delay(5000); setDefaultAffiliationID(context) }
setContent {
var appLockDialog by rememberSaveable { mutableStateOf(false) }
val theme by vm.theme.collectAsStateWithLifecycle()
@@ -274,7 +263,6 @@ class MainActivity : FragmentActivity() {
override fun onResume() {
super.onResume()
checkPrivilege(this)
}
}
@@ -284,14 +272,12 @@ class MainActivity : FragmentActivity() {
fun Home(vm: MyViewModel, onLock: () -> Unit) {
val navController = rememberNavController()
val context = LocalContext.current
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val lifecycleOwner = LocalLifecycleOwner.current
fun navigateUp() { navController.navigateUp() }
fun navigate(destination: Any) { navController.navigate(destination) }
LaunchedEffect(Unit) {
val privilege = myPrivilege.value
if(!privilege.device && !privilege.profile) {
if(!Privilege.status.value.activated) {
navController.navigate(WorkModes(false)) {
popUpTo<Home> { inclusive = true }
}
@@ -385,7 +371,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
AppChooserScreen(it.toRoute(), { dest ->
if(dest == null) navigateUp() else navigate(ApplicationDetails(dest))
}, {
SharedPrefs(context).applicationsListView = false
SP.applicationsListView = false
navController.navigate(ApplicationsFeatures) {
popUpTo(Home)
}
@@ -393,7 +379,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
}
composable<ApplicationsFeatures> {
ApplicationsFeaturesScreen(::navigateUp, ::navigate) {
SharedPrefs(context).applicationsListView = true
SP.applicationsListView = true
navController.navigate(ApplicationsList(true)) {
popUpTo(Home)
}
@@ -451,7 +437,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
composable<SettingsOptions> { SettingsOptionsScreen(::navigateUp) }
composable<Appearance> {
val theme by vm.theme.collectAsStateWithLifecycle()
AppearanceScreen(::navigateUp, theme) { vm.theme.value = it }
AppearanceScreen(::navigateUp, theme, vm::changeTheme)
}
composable<AppLockSettings> { AppLockSettingsScreen(::navigateUp) }
composable<ApiSettings> { ApiSettings(::navigateUp) }
@@ -459,11 +445,10 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
composable<About> { AboutScreen(::navigateUp) }
}
DisposableEffect(lifecycleOwner) {
val sp = SharedPrefs(context)
val observer = LifecycleEventObserver { _, event ->
if (
(event == Lifecycle.Event.ON_CREATE && !sp.lockPasswordHash.isNullOrEmpty()) ||
(event == Lifecycle.Event.ON_RESUME && sp.lockWhenLeaving)
(event == Lifecycle.Event.ON_CREATE && !SP.lockPasswordHash.isNullOrEmpty()) ||
(event == Lifecycle.Event.ON_RESUME && SP.lockWhenLeaving)
) {
onLock()
}
@@ -474,18 +459,16 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
}
}
LaunchedEffect(Unit) {
val dpm = context.getDPM()
val sp = SharedPrefs(context)
val profileNotActivated = !sp.managedProfileActivated && myPrivilege.value.work
val profileNotActivated = !SP.managedProfileActivated && Privilege.status.value.work
if(profileNotActivated) {
dpm.setProfileEnabled(receiver)
sp.managedProfileActivated = true
Privilege.DPM.setProfileEnabled(Privilege.DAR)
SP.managedProfileActivated = true
context.popToast(R.string.work_profile_activated)
}
}
DhizukuErrorDialog {
dhizukuErrorStatus.value = 0
updatePrivilege(context)
Privilege.updateStatus()
navController.navigate(WorkModes(false)) {
popUpTo<Home> { inclusive = true }
launchSingleTop = true
@@ -498,8 +481,7 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun HomeScreen(onNavigate: (Any) -> Unit) {
val context = LocalContext.current
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
Modifier.nestedScroll(sb.nestedScrollConnection),
@@ -527,7 +509,7 @@ private fun HomeScreen(onNavigate: (Any) -> Unit) {
}
if(privilege.device || privilege.profile) {
HomePageItem(R.string.applications, R.drawable.apps_fill0) {
onNavigate(if(SharedPrefs(context).applicationsListView) ApplicationsList(true) else ApplicationsFeatures)
onNavigate(if(SP.applicationsListView) ApplicationsList(true) else ApplicationsFeatures)
}
if(VERSION.SDK_INT >= 24) {
HomePageItem(R.string.user_restriction, R.drawable.person_off) { onNavigate(UserRestriction) }
@@ -567,9 +549,8 @@ fun HomePageItem(name: Int, imgVector: Int, onClick: () -> Unit) {
private fun DhizukuErrorDialog(onClose: () -> Unit) {
val status by dhizukuErrorStatus.collectAsState()
if (status != 0) {
val sp = SharedPrefs(LocalContext.current)
LaunchedEffect(Unit) {
sp.dhizuku = false
SP.dhizuku = false
}
AlertDialog(
onDismissRequest = {},
@@ -580,14 +561,13 @@ private fun DhizukuErrorDialog(onClose: () -> Unit) {
},
title = { Text(stringResource(R.string.dhizuku)) },
text = {
var text = stringResource(
val text = stringResource(
when(status){
1 -> R.string.failed_to_init_dhizuku
2 -> R.string.dhizuku_permission_not_granted
else -> R.string.failed_to_init_dhizuku
}
)
if(sp.dhizuku) text += "\n" + stringResource(R.string.dhizuku_mode_disabled)
Text(text)
},
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)

View File

@@ -27,7 +27,7 @@ class ManageSpaceActivity: FragmentActivity() {
setContent {
val theme by vm.theme.collectAsStateWithLifecycle()
OwnDroidTheme(theme) {
var appLockDialog by remember { mutableStateOf(!SharedPrefs(this).lockPasswordHash.isNullOrEmpty()) }
var appLockDialog by remember { mutableStateOf(!SP.lockPasswordHash.isNullOrEmpty()) }
if(appLockDialog) {
AppLockDialog({ appLockDialog = false }, ::finish)
} else {

View File

@@ -0,0 +1,18 @@
package com.bintianqi.owndroid
import android.app.Application
import android.os.Build.VERSION
import org.lsposed.hiddenapibypass.HiddenApiBypass
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
if (VERSION.SDK_INT >= 28) HiddenApiBypass.setHiddenApiExemptions("")
SP = SharedPrefs(applicationContext)
Privilege.initialize(applicationContext)
Privilege.updateStatus()
}
}
lateinit var SP: SharedPrefs
private set

View File

@@ -2,23 +2,15 @@ package com.bintianqi.owndroid
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
class MyViewModel(application: Application): AndroidViewModel(application) {
val theme = MutableStateFlow(ThemeSettings())
init {
val sp = SharedPrefs(application)
theme.value = ThemeSettings(sp.materialYou, sp.darkTheme, sp.blackTheme)
viewModelScope.launch {
theme.collect {
sp.materialYou = it.materialYou
sp.darkTheme = it.darkTheme
sp.blackTheme = it.blackTheme
}
}
val theme = MutableStateFlow(ThemeSettings(SP.materialYou, SP.darkTheme, SP.blackTheme))
fun changeTheme(newTheme: ThemeSettings) {
theme.value = newTheme
SP.materialYou = newTheme.materialYou
SP.darkTheme = newTheme.darkTheme
SP.blackTheme = newTheme.blackTheme
}
}

View File

@@ -1,39 +1,64 @@
package com.bintianqi.owndroid
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.os.Binder
import android.os.Build
import com.bintianqi.owndroid.dpm.getDPM
import com.bintianqi.owndroid.dpm.getReceiver
import com.bintianqi.owndroid.dpm.isDeviceOwner
import com.bintianqi.owndroid.dpm.isProfileOwner
import com.bintianqi.owndroid.dpm.binderWrapperDevicePolicyManager
import com.bintianqi.owndroid.dpm.dhizukuErrorStatus
import com.rosan.dhizuku.api.Dhizuku
import kotlinx.coroutines.flow.MutableStateFlow
class Privilege(
val device: Boolean = false, // Device owner
val profile: Boolean = false, // Profile owner
val dhizuku: Boolean = false,
val work: Boolean = false, // Work profile
val org: Boolean = false, // Organization-owned work profile
val affiliated: Boolean = false
) {
val primary = Binder.getCallingUid() / 100000 == 0 // Primary user
object Privilege {
fun initialize(context: Context) {
if (SP.dhizuku) {
Dhizuku.init(context)
val hasPermission = try {
Dhizuku.isPermissionGranted()
} catch(_: Exception) {
false
}
if (hasPermission) {
val dhizukuDpm = binderWrapperDevicePolicyManager(context)
if (dhizukuDpm != null) {
DPM = dhizukuDpm
DAR = Dhizuku.getOwnerComponent()
return
}
}
dhizukuErrorStatus.value = 2
}
DPM = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
DAR = MyAdminComponent
}
lateinit var DPM: DevicePolicyManager
private set
lateinit var DAR: ComponentName
private set
data class Status(
val device: Boolean = false,
val profile: Boolean = false,
val dhizuku: Boolean = false,
val work: Boolean = false,
val org: Boolean = false,
val affiliated: Boolean = false
) {
val activated = device || profile
val primary = Binder.getCallingUid() / 100000 == 0 // Primary user
}
val status = MutableStateFlow(Status())
fun updateStatus() {
val profile = DPM.isProfileOwnerApp(DAR.packageName)
val work = profile && Build.VERSION.SDK_INT >= 24 && DPM.isManagedProfile(DAR)
status.value = Status(
device = DPM.isDeviceOwnerApp(DAR.packageName),
profile = profile,
dhizuku = SP.dhizuku,
work = work,
org = work && Build.VERSION.SDK_INT >= 30 && DPM.isOrganizationOwnedDeviceWithManagedProfile,
affiliated = Build.VERSION.SDK_INT >= 28 && DPM.isAffiliatedUser
)
}
}
val myPrivilege = MutableStateFlow(Privilege())
fun updatePrivilege(context: Context) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
val profile = context.isProfileOwner
val work = profile && Build.VERSION.SDK_INT >= 24 && dpm.isManagedProfile(receiver)
myPrivilege.value = Privilege(
device = context.isDeviceOwner,
profile = profile,
dhizuku = SharedPrefs(context).dhizuku,
work = work,
org = work && Build.VERSION.SDK_INT >= 30 && dpm.isOrganizationOwnedDeviceWithManagedProfile,
affiliated = Build.VERSION.SDK_INT >= 28 && dpm.isAffiliatedUser
)
}

View File

@@ -7,7 +7,6 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build.VERSION
import android.os.PersistableBundle
import android.os.UserHandle
import android.os.UserManager
import androidx.core.app.NotificationCompat
@@ -35,13 +34,13 @@ class Receiver : DeviceAdminReceiver() {
override fun onEnabled(context: Context, intent: Intent) {
super.onEnabled(context, intent)
updatePrivilege(context)
Privilege.updateStatus()
handlePrivilegeChange(context)
}
override fun onDisabled(context: Context, intent: Intent) {
super.onDisabled(context, intent)
updatePrivilege(context)
Privilege.updateStatus()
handlePrivilegeChange(context)
}
@@ -74,11 +73,6 @@ class Receiver : DeviceAdminReceiver() {
}
}
override fun onTransferOwnershipComplete(context: Context, bundle: PersistableBundle?) {
super.onTransferOwnershipComplete(context, bundle)
SharedPrefs(context).dhizuku = false
}
override fun onLockTaskModeEntering(context: Context, intent: Intent, pkg: String) {
super.onLockTaskModeEntering(context, intent, pkg)
if(!NotificationUtils.checkPermission(context)) return

View File

@@ -78,7 +78,7 @@ import kotlin.system.exitProcess
@Composable
fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val context = LocalContext.current
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val exportLogsLauncher = rememberLauncherForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) {
if(it != null) exportLogs(context, it)
}
@@ -145,17 +145,16 @@ fun SettingsScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable
fun SettingsOptionsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val sp = SharedPrefs(context)
MyScaffold(R.string.options, onNavigateUp, 0.dp) {
SwitchItem(
R.string.show_dangerous_features, icon = R.drawable.warning_fill0,
getState = { sp.displayDangerousFeatures },
onCheckedChange = { sp.displayDangerousFeatures = it }
getState = { SP.displayDangerousFeatures },
onCheckedChange = { SP.displayDangerousFeatures = it }
)
SwitchItem(
R.string.shortcuts, icon = R.drawable.open_in_new,
getState = { sp.shortcuts }, onCheckedChange = {
sp.shortcuts = it
getState = { SP.shortcuts }, onCheckedChange = {
SP.shortcuts = it
ShortcutManagerCompat.removeAllDynamicShortcuts(context)
createShortcuts(context)
}
@@ -230,13 +229,12 @@ fun AppearanceScreen(onNavigateUp: () -> Unit, currentTheme: ThemeSettings, onTh
@Composable
fun AppLockSettingsScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.app_lock, onNavigateUp, 0.dp) {
val fm = LocalFocusManager.current
val sp = SharedPrefs(LocalContext.current)
var password by remember { mutableStateOf("") }
var confirmPassword by remember { mutableStateOf("") }
var allowBiometrics by remember { mutableStateOf(sp.biometricsUnlock) }
var lockWhenLeaving by remember { mutableStateOf(sp.lockWhenLeaving) }
var allowBiometrics by remember { mutableStateOf(SP.biometricsUnlock) }
var lockWhenLeaving by remember { mutableStateOf(SP.lockWhenLeaving) }
val fr = FocusRequester()
val alreadySet = !sp.lockPasswordHash.isNullOrEmpty()
val alreadySet = !SP.lockPasswordHash.isNullOrEmpty()
val isInputLegal = password.length !in 1..3 && (alreadySet || (password.isNotEmpty() && password.isNotBlank()))
Column(Modifier.widthIn(max = 300.dp).align(Alignment.CenterHorizontally)) {
OutlinedTextField(
@@ -263,9 +261,9 @@ fun AppLockSettingsScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.app_lo
Button(
onClick = {
fm.clearFocus()
if(password.isNotEmpty()) sp.lockPasswordHash = password.hash()
sp.biometricsUnlock = allowBiometrics
sp.lockWhenLeaving = lockWhenLeaving
if(password.isNotEmpty()) SP.lockPasswordHash = password.hash()
SP.biometricsUnlock = allowBiometrics
SP.lockWhenLeaving = lockWhenLeaving
onNavigateUp()
},
modifier = Modifier.fillMaxWidth(),
@@ -276,9 +274,9 @@ fun AppLockSettingsScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.app_lo
if(alreadySet) FilledTonalButton(
onClick = {
fm.clearFocus()
sp.lockPasswordHash = ""
sp.biometricsUnlock = false
sp.lockWhenLeaving = false
SP.lockPasswordHash = ""
SP.biometricsUnlock = false
SP.lockWhenLeaving = false
onNavigateUp()
},
modifier = Modifier.fillMaxWidth()
@@ -293,13 +291,12 @@ fun AppLockSettingsScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.app_lo
@Composable
fun ApiSettings(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val sp = SharedPrefs(context)
MyScaffold(R.string.api, onNavigateUp) {
var enabled by remember { mutableStateOf(sp.isApiEnabled) }
var enabled by remember { mutableStateOf(SP.isApiEnabled) }
SwitchItem(R.string.enable, state = enabled, onCheckedChange = {
enabled = it
sp.isApiEnabled = it
if(!it) sp.sharedPrefs.edit { remove("api.key") }
SP.isApiEnabled = it
if(!it) SP.sharedPrefs.edit { remove("api.key") }
}, padding = false)
if(enabled) {
var key by remember { mutableStateOf("") }
@@ -321,14 +318,14 @@ fun ApiSettings(onNavigateUp: () -> Unit) {
Button(
modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp),
onClick = {
sp.apiKey = key
SP.apiKey = key
context.showOperationResultToast(true)
},
enabled = key.isNotEmpty()
) {
Text(stringResource(R.string.apply))
}
if(sp.apiKey != null) Notes(R.string.api_key_exist)
if(SP.apiKey != null) Notes(R.string.api_key_exist)
}
}
}

View File

@@ -7,25 +7,21 @@ import android.os.Bundle
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.bintianqi.owndroid.dpm.getDPM
import com.bintianqi.owndroid.dpm.getReceiver
class ShortcutsReceiverActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
val action = intent.action?.removePrefix("com.bintianqi.owndroid.action.")
if (action != null && SharedPrefs(this).shortcuts) {
val dpm = getDPM()
val receiver = getReceiver()
if (action != null && SP.shortcuts) {
when (action) {
"LOCK" -> dpm.lockNow()
"LOCK" -> Privilege.DPM.lockNow()
"DISABLE_CAMERA" -> {
dpm.setCameraDisabled(receiver, !dpm.getCameraDisabled(receiver))
Privilege.DPM.setCameraDisabled(Privilege.DAR, !Privilege.DPM.getCameraDisabled(Privilege.DAR))
createShortcuts(this)
}
"MUTE" -> {
dpm.setMasterVolumeMuted(receiver, !dpm.isMasterVolumeMuted(receiver))
Privilege.DPM.setMasterVolumeMuted(Privilege.DAR, !Privilege.DPM.isMasterVolumeMuted(Privilege.DAR))
createShortcuts(this)
}
}
@@ -37,13 +33,11 @@ class ShortcutsReceiverActivity : Activity() {
}
fun createShortcuts(context: Context) {
if (!SharedPrefs(context).shortcuts) return
if (!SP.shortcuts) return
val action = "com.bintianqi.owndroid.action"
val baseIntent = Intent(context, ShortcutsReceiverActivity::class.java)
val dpm = context.getDPM()
val receiver = context.getReceiver()
val cameraDisabled = dpm.getCameraDisabled(receiver)
val muted = dpm.isMasterVolumeMuted(receiver)
val cameraDisabled = Privilege.DPM.getCameraDisabled(Privilege.DAR)
val muted = Privilege.DPM.isMasterVolumeMuted(Privilege.DAR)
val list = listOf(
ShortcutInfoCompat.Builder(context, "LOCK")
.setIcon(IconCompat.createWithResource(context, R.drawable.screen_lock_portrait_fill0))

View File

@@ -86,10 +86,10 @@ import com.bintianqi.owndroid.AppInstallerActivity
import com.bintianqi.owndroid.AppInstallerViewModel
import com.bintianqi.owndroid.ChoosePackageContract
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.getInstalledAppsFlags
import com.bintianqi.owndroid.installedApps
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.ErrorDialog
import com.bintianqi.owndroid.ui.FullWidthRadioButtonItem
@@ -191,7 +191,7 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
.verticalScroll(rememberScrollState())
.padding(bottom = 80.dp)
) {
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
if(VERSION.SDK_INT >= 24) FunctionItem(R.string.suspend, icon = R.drawable.block_fill0) { onNavigate(Suspend) }
FunctionItem(R.string.hide, icon = R.drawable.visibility_off_fill0) { onNavigate(Hide) }
FunctionItem(R.string.block_uninstall, icon = R.drawable.delete_forever_fill0) { onNavigate(BlockUninstall) }
@@ -246,10 +246,8 @@ fun ApplicationsFeaturesScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Un
fun ApplicationDetailsScreen(param: ApplicationDetails, onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val packageName = param.packageName
val context = LocalContext.current
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val pm = context.packageManager
val dpm = context.getDPM()
val receiver = context.getReceiver()
var dialog by remember { mutableIntStateOf(0) } // 1: clear storage, 2: uninstall
val info = pm.getApplicationInfo(packageName, getInstalledAppsFlags)
MySmallTitleScaffold(R.string.place_holder, onNavigateUp, 0.dp) {
@@ -261,43 +259,43 @@ fun ApplicationDetailsScreen(param: ApplicationDetails, onNavigateUp: () -> Unit
FunctionItem(R.string.permissions, icon = R.drawable.shield_fill0) { onNavigate(PermissionsManager(packageName)) }
if(VERSION.SDK_INT >= 24) SwitchItem(
R.string.suspend, icon = R.drawable.block_fill0,
getState = { dpm.isPackageSuspended(receiver, packageName) },
onCheckedChange = { dpm.setPackagesSuspended(receiver, arrayOf(packageName), it) }
getState = { Privilege.DPM.isPackageSuspended(Privilege.DAR, packageName) },
onCheckedChange = { Privilege.DPM.setPackagesSuspended(Privilege.DAR, arrayOf(packageName), it) }
)
SwitchItem(
R.string.hide, icon = R.drawable.visibility_off_fill0,
getState = { dpm.isApplicationHidden(receiver, packageName) },
onCheckedChange = { dpm.setApplicationHidden(receiver, packageName, it) }
getState = { Privilege.DPM.isApplicationHidden(Privilege.DAR, packageName) },
onCheckedChange = { Privilege.DPM.setApplicationHidden(Privilege.DAR, packageName, it) }
)
SwitchItem(
R.string.block_uninstall, icon = R.drawable.delete_forever_fill0,
getState = { dpm.isUninstallBlocked(receiver, packageName) },
onCheckedChange = { dpm.setUninstallBlocked(receiver, packageName, it) }
getState = { Privilege.DPM.isUninstallBlocked(Privilege.DAR, packageName) },
onCheckedChange = { Privilege.DPM.setUninstallBlocked(Privilege.DAR, packageName, it) }
)
if(VERSION.SDK_INT >= 30) SwitchItem(
R.string.disable_user_control, icon = R.drawable.do_not_touch_fill0,
getState = { packageName in dpm.getUserControlDisabledPackages(receiver) },
getState = { packageName in Privilege.DPM.getUserControlDisabledPackages(Privilege.DAR) },
onCheckedChange = { state ->
dpm.setUserControlDisabledPackages(receiver,
dpm.getUserControlDisabledPackages(receiver).let { if(state) it.plus(packageName) else it.minus(packageName) }
Privilege.DPM.setUserControlDisabledPackages(Privilege.DAR,
Privilege.DPM.getUserControlDisabledPackages(Privilege.DAR).let { if(state) it.plus(packageName) else it.minus(packageName) }
)
}
)
if(VERSION.SDK_INT >= 28) SwitchItem(
R.string.disable_metered_data, icon = R.drawable.money_off_fill0,
getState = { packageName in dpm.getMeteredDataDisabledPackages(receiver) },
getState = { packageName in Privilege.DPM.getMeteredDataDisabledPackages(Privilege.DAR) },
onCheckedChange = { state ->
dpm.setMeteredDataDisabledPackages(receiver,
dpm.getMeteredDataDisabledPackages(receiver).let { if(state) it.plus(packageName) else it.minus(packageName) }
Privilege.DPM.setMeteredDataDisabledPackages(Privilege.DAR,
Privilege.DPM.getMeteredDataDisabledPackages(Privilege.DAR).let { if(state) it.plus(packageName) else it.minus(packageName) }
)
}
)
if(privilege.device && VERSION.SDK_INT >= 28) SwitchItem(
R.string.keep_after_uninstall, icon = R.drawable.delete_fill0,
getState = { dpm.getKeepUninstalledPackages(receiver)?.contains(packageName) == true },
getState = { Privilege.DPM.getKeepUninstalledPackages(Privilege.DAR)?.contains(packageName) == true },
onCheckedChange = { state ->
dpm.setKeepUninstalledPackages(receiver,
dpm.getKeepUninstalledPackages(receiver)?.let { if(state) it.plus(packageName) else it.minus(packageName) } ?: listOf(packageName)
Privilege.DPM.setKeepUninstalledPackages(Privilege.DAR,
Privilege.DPM.getKeepUninstalledPackages(Privilege.DAR)?.let { if(state) it.plus(packageName) else it.minus(packageName) } ?: listOf(packageName)
)
}
)
@@ -314,14 +312,14 @@ fun ApplicationDetailsScreen(param: ApplicationDetails, onNavigateUp: () -> Unit
@Composable
fun SuspendScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var packageName by remember { mutableStateOf("") }
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
pm.getInstalledApplications(getInstalledAppsFlags).filter { dpm.isPackageSuspended(receiver, it.packageName) }.forEach {
pm.getInstalledApplications(getInstalledAppsFlags).filter {
Privilege.DPM.isPackageSuspended(Privilege.DAR, it.packageName)
}.forEach {
packages += it.retrieveAppInfo(pm)
}
}
@@ -329,7 +327,7 @@ fun SuspendScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.suspend, onNavigateUp) {
items(packages, { it.name }) {
ApplicationItem(it) {
dpm.setPackagesSuspended(receiver, arrayOf(it.name), false)
Privilege.DPM.setPackagesSuspended(Privilege.DAR, arrayOf(it.name), false)
refresh()
}
}
@@ -338,7 +336,7 @@ fun SuspendScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(vertical = 8.dp)) { packageName = it }
Button(
{
if(dpm.setPackagesSuspended(receiver, arrayOf(packageName), true).isEmpty()) packageName = ""
if(Privilege.DPM.setPackagesSuspended(Privilege.DAR, arrayOf(packageName), true).isEmpty()) packageName = ""
else context.showOperationResultToast(false)
refresh()
},
@@ -358,14 +356,12 @@ fun SuspendScreen(onNavigateUp: () -> Unit) {
@Composable
fun HideScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var packageName by remember { mutableStateOf("") }
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
pm.getInstalledApplications(getInstalledAppsFlags).filter { dpm.isApplicationHidden(receiver, it.packageName) }.forEach {
pm.getInstalledApplications(getInstalledAppsFlags).filter { Privilege.DPM.isApplicationHidden(Privilege.DAR, it.packageName) }.forEach {
packages += it.retrieveAppInfo(pm)
}
}
@@ -373,7 +369,7 @@ fun HideScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.hide, onNavigateUp) {
items(packages, { it.name }) {
ApplicationItem(it) {
dpm.setApplicationHidden(receiver, it.name, false)
Privilege.DPM.setApplicationHidden(Privilege.DAR, it.name, false)
refresh()
}
}
@@ -382,7 +378,7 @@ fun HideScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(vertical = 8.dp)) { packageName = it }
Button(
{
if(dpm.setApplicationHidden(receiver, packageName, true)) packageName = ""
if(Privilege.DPM.setApplicationHidden(Privilege.DAR, packageName, true)) packageName = ""
else context.showOperationResultToast(false)
refresh()
},
@@ -401,14 +397,12 @@ fun HideScreen(onNavigateUp: () -> Unit) {
@Composable
fun BlockUninstallScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var packageName by remember { mutableStateOf("") }
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
pm.getInstalledApplications(getInstalledAppsFlags).filter { dpm.isUninstallBlocked(receiver, it.packageName) }.forEach {
pm.getInstalledApplications(getInstalledAppsFlags).filter { Privilege.DPM.isUninstallBlocked(Privilege.DAR, it.packageName) }.forEach {
packages += it.retrieveAppInfo(pm)
}
}
@@ -416,7 +410,7 @@ fun BlockUninstallScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.block_uninstall, onNavigateUp) {
items(packages, { it.name }) {
ApplicationItem(it) {
dpm.setUninstallBlocked(receiver, it.name, false)
Privilege.DPM.setUninstallBlocked(Privilege.DAR, it.name, false)
refresh()
}
}
@@ -425,7 +419,7 @@ fun BlockUninstallScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(vertical = 8.dp)) { packageName = it }
Button(
{
dpm.setUninstallBlocked(receiver, packageName, true)
Privilege.DPM.setUninstallBlocked(Privilege.DAR, packageName, true)
packageName = ""
refresh()
},
@@ -445,13 +439,11 @@ fun BlockUninstallScreen(onNavigateUp: () -> Unit) {
@Composable
fun DisableUserControlScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
dpm.getUserControlDisabledPackages(receiver).forEach {
Privilege.DPM.getUserControlDisabledPackages(Privilege.DAR).forEach {
packages += pm.retrieveAppInfo(it)
}
}
@@ -459,7 +451,7 @@ fun DisableUserControlScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.disable_user_control, onNavigateUp) {
items(packages, { it.name }) { info ->
ApplicationItem(info) {
dpm.setUserControlDisabledPackages(receiver, packages.minus(info).map { it.name })
Privilege.DPM.setUserControlDisabledPackages(Privilege.DAR, packages.minus(info).map { it.name })
refresh()
}
}
@@ -468,7 +460,7 @@ fun DisableUserControlScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(vertical = 8.dp, horizontal = HorizontalPadding)) { packageName = it }
Button(
{
dpm.setUserControlDisabledPackages(receiver, packages.map { it.name } + packageName)
Privilege.DPM.setUserControlDisabledPackages(Privilege.DAR, packages.map { it.name } + packageName)
refresh()
},
Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding).padding(bottom = 8.dp),
@@ -487,15 +479,13 @@ fun DisableUserControlScreen(onNavigateUp: () -> Unit) {
fun PermissionsManagerScreen(onNavigateUp: () -> Unit, param: PermissionsManager) {
val packageNameParam = param.packageName
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var packageName by remember { mutableStateOf(packageNameParam ?: "") }
var selectedPermission by remember { mutableStateOf<PermissionItem?>(null) }
val statusMap = remember { mutableStateMapOf<String, Int>() }
LaunchedEffect(packageName) {
if(packageName.isValidPackageName) {
permissionList().forEach { statusMap[it.permission] = dpm.getPermissionGrantState(receiver, packageName, it.permission) }
permissionList().forEach { statusMap[it.permission] = Privilege.DPM.getPermissionGrantState(Privilege.DAR, packageName, it.permission) }
} else {
statusMap.clear()
}
@@ -536,9 +526,9 @@ fun PermissionsManagerScreen(onNavigateUp: () -> Unit, param: PermissionsManager
}
if(selectedPermission != null) {
fun changeState(state: Int) {
val result = dpm.setPermissionGrantState(receiver, packageName, selectedPermission!!.permission, state)
val result = Privilege.DPM.setPermissionGrantState(Privilege.DAR, packageName, selectedPermission!!.permission, state)
if (!result) context.showOperationResultToast(false)
statusMap[selectedPermission!!.permission] = dpm.getPermissionGrantState(receiver, packageName, selectedPermission!!.permission)
statusMap[selectedPermission!!.permission] = Privilege.DPM.getPermissionGrantState(Privilege.DAR, packageName, selectedPermission!!.permission)
selectedPermission = null
}
@Composable
@@ -582,14 +572,12 @@ fun PermissionsManagerScreen(onNavigateUp: () -> Unit, param: PermissionsManager
@Composable
fun DisableMeteredDataScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var packageName by remember { mutableStateOf("") }
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
dpm.getMeteredDataDisabledPackages(receiver).forEach {
Privilege.DPM.getMeteredDataDisabledPackages(Privilege.DAR).forEach {
packages += pm.retrieveAppInfo(it)
}
}
@@ -597,7 +585,7 @@ fun DisableMeteredDataScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.disable_metered_data, onNavigateUp) {
items(packages, { it.name }) { info ->
ApplicationItem(info) {
dpm.setMeteredDataDisabledPackages(receiver, packages.minus(info).map { it.name })
Privilege.DPM.setMeteredDataDisabledPackages(Privilege.DAR, packages.minus(info).map { it.name })
refresh()
}
}
@@ -605,7 +593,7 @@ fun DisableMeteredDataScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(HorizontalPadding, 8.dp)) { packageName = it }
Button(
{
if(dpm.setMeteredDataDisabledPackages(receiver, packages.map { it.name } + packageName).isEmpty()) {
if(Privilege.DPM.setMeteredDataDisabledPackages(Privilege.DAR, packages.map { it.name } + packageName).isEmpty()) {
packageName = ""
} else {
context.showOperationResultToast(false)
@@ -655,8 +643,8 @@ private fun ClearAppStorageDialog(packageName: String, onClose: () -> Unit) {
TextButton(
{
clearing = true
context.getDPM().clearApplicationUserData(
context.getReceiver(), packageName, Executors.newSingleThreadExecutor()
Privilege.DPM.clearApplicationUserData(
Privilege.DAR, packageName, Executors.newSingleThreadExecutor()
) { _, it ->
Looper.prepare()
context.showOperationResultToast(it)
@@ -734,13 +722,11 @@ private fun UninstallAppDialog(packageName: String, onClose: () -> Unit) {
@Composable
fun KeepUninstalledPackagesScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
dpm.getKeepUninstalledPackages(receiver)?.forEach {
Privilege.DPM.getKeepUninstalledPackages(Privilege.DAR)?.forEach {
packages += pm.retrieveAppInfo(it)
}
}
@@ -748,7 +734,7 @@ fun KeepUninstalledPackagesScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.keep_uninstalled_packages, onNavigateUp) {
items(packages, { it.name }) { info ->
ApplicationItem(info) {
dpm.setKeepUninstalledPackages(receiver, packages.minus(info).map { it.name })
Privilege.DPM.setKeepUninstalledPackages(Privilege.DAR, packages.minus(info).map { it.name })
refresh()
}
}
@@ -757,7 +743,7 @@ fun KeepUninstalledPackagesScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(HorizontalPadding, 8.dp)) { packageName = it }
Button(
{
dpm.setKeepUninstalledPackages(receiver, packages.map { it.name } + packageName)
Privilege.DPM.setKeepUninstalledPackages(Privilege.DAR, packages.map { it.name } + packageName)
packageName = ""
},
Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding).padding(bottom = 8.dp),
@@ -782,7 +768,7 @@ fun InstallExistingAppScreen(onNavigateUp: () -> Unit) {
Button(
{
context.showOperationResultToast(
context.getDPM().installExistingPackage(context.getReceiver(), packageName)
Privilege.DPM.installExistingPackage(Privilege.DAR, packageName)
)
},
Modifier.fillMaxWidth(),
@@ -800,13 +786,11 @@ fun InstallExistingAppScreen(onNavigateUp: () -> Unit) {
@Composable
fun CrossProfilePackagesScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
dpm.getCrossProfilePackages(receiver).forEach {
Privilege.DPM.getCrossProfilePackages(Privilege.DAR).forEach {
packages += pm.retrieveAppInfo(it)
}
}
@@ -814,7 +798,7 @@ fun CrossProfilePackagesScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.cross_profile_apps, onNavigateUp) {
items(packages, { it.name }) { info ->
ApplicationItem(info) {
dpm.setCrossProfilePackages(receiver, packages.minus(info).map { it.name }.toSet())
Privilege.DPM.setCrossProfilePackages(Privilege.DAR, packages.minus(info).map { it.name }.toSet())
refresh()
}
}
@@ -823,7 +807,7 @@ fun CrossProfilePackagesScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(vertical = 8.dp)) { packageName = it }
Button(
{
dpm.setCrossProfilePackages(receiver, packages.map { it.name }.toSet() + packageName)
Privilege.DPM.setCrossProfilePackages(Privilege.DAR, packages.map { it.name }.toSet() + packageName)
packageName = ""
refresh()
},
@@ -841,13 +825,11 @@ fun CrossProfilePackagesScreen(onNavigateUp: () -> Unit) {
@Composable
fun CrossProfileWidgetProvidersScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val pm = context.packageManager
packages.clear()
dpm.getCrossProfileWidgetProviders(receiver).forEach {
Privilege.DPM.getCrossProfileWidgetProviders(Privilege.DAR).forEach {
packages += pm.retrieveAppInfo(it)
}
}
@@ -855,7 +837,7 @@ fun CrossProfileWidgetProvidersScreen(onNavigateUp: () -> Unit) {
MyLazyScaffold(R.string.cross_profile_widget, onNavigateUp) {
items(packages, { it.name }) {
ApplicationItem(it) {
dpm.removeCrossProfileWidgetProvider(receiver, it.name)
Privilege.DPM.removeCrossProfileWidgetProvider(Privilege.DAR, it.name)
refresh()
}
}
@@ -864,7 +846,7 @@ fun CrossProfileWidgetProvidersScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(vertical = 8.dp, horizontal = HorizontalPadding)) { packageName = it }
Button(
{
dpm.addCrossProfileWidgetProvider(receiver, packageName)
Privilege.DPM.addCrossProfileWidgetProvider(Privilege.DAR, packageName)
packageName = ""
refresh()
},
@@ -884,11 +866,10 @@ fun CrossProfileWidgetProvidersScreen(onNavigateUp: () -> Unit) {
fun CredentialManagerPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val pm = context.packageManager
val dpm = context.getDPM()
var policyType by remember{ mutableIntStateOf(-1) }
val packages = remember { mutableStateListOf<AppInfo>() }
fun refresh() {
val policy = dpm.credentialManagerPolicy
val policy = Privilege.DPM.credentialManagerPolicy
policyType = policy?.policyType ?: -1
packages.clear()
policy?.packageNames?.forEach {
@@ -928,9 +909,9 @@ fun CredentialManagerPolicyScreen(onNavigateUp: () -> Unit) {
{
try {
if(policyType != -1 && packages.isNotEmpty()) {
dpm.credentialManagerPolicy = PackagePolicy(policyType, packages.map { it.name }.toSet())
Privilege.DPM.credentialManagerPolicy = PackagePolicy(policyType, packages.map { it.name }.toSet())
} else {
dpm.credentialManagerPolicy = null
Privilege.DPM.credentialManagerPolicy = null
}
context.showOperationResultToast(true)
} catch(_: IllegalArgumentException) {
@@ -954,13 +935,11 @@ fun CredentialManagerPolicyScreen(onNavigateUp: () -> Unit) {
fun PermittedAccessibilityServicesScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val pm = context.packageManager
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateListOf<AppInfo>() }
var allowAll by remember { mutableStateOf(true) }
fun refresh() {
packages.clear()
val list = dpm.getPermittedAccessibilityServices(receiver)
val list = Privilege.DPM.getPermittedAccessibilityServices(Privilege.DAR)
allowAll = list == null
list?.forEach {
packages += pm.retrieveAppInfo(it)
@@ -989,7 +968,7 @@ fun PermittedAccessibilityServicesScreen(onNavigateUp: () -> Unit) {
}
Button(
{
val result = dpm.setPermittedAccessibilityServices(receiver, if(allowAll) null else packages.map { it.name })
val result = Privilege.DPM.setPermittedAccessibilityServices(Privilege.DAR, if(allowAll) null else packages.map { it.name })
context.showOperationResultToast(result)
refresh()
},
@@ -1008,13 +987,11 @@ fun PermittedAccessibilityServicesScreen(onNavigateUp: () -> Unit) {
fun PermittedInputMethodsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val pm = context.packageManager
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateListOf<AppInfo>() }
var allowAll by remember { mutableStateOf(true) }
fun refresh() {
packages.clear()
val list = dpm.getPermittedInputMethods(receiver)
val list = Privilege.DPM.getPermittedInputMethods(Privilege.DAR)
allowAll = list == null
list?.forEach {
packages += pm.retrieveAppInfo(it)
@@ -1043,7 +1020,7 @@ fun PermittedInputMethodsScreen(onNavigateUp: () -> Unit) {
}
Button(
{
val result = dpm.setPermittedInputMethods(receiver, if(allowAll) null else packages.map { it.name })
val result = Privilege.DPM.setPermittedInputMethods(Privilege.DAR, if(allowAll) null else packages.map { it.name })
context.showOperationResultToast(result)
refresh()
},
@@ -1067,7 +1044,7 @@ fun EnableSystemAppScreen(onNavigateUp: () -> Unit) {
PackageNameTextField(packageName, Modifier.padding(bottom = 8.dp)) { packageName = it }
Button(
{
context.getDPM().enableSystemApp(context.getReceiver(), packageName)
Privilege.DPM.enableSystemApp(Privilege.DAR, packageName)
packageName = ""
context.showOperationResultToast(true)
},
@@ -1094,7 +1071,7 @@ fun SetDefaultDialerScreen(onNavigateUp: () -> Unit) {
Button(
{
try {
context.getDPM().setDefaultDialerApplication(packageName)
Privilege.DPM.setDefaultDialerApplication(packageName)
context.showOperationResultToast(true)
} catch(e: Exception) {
errorMessage = e.message

View File

@@ -7,7 +7,6 @@ import android.app.admin.DevicePolicyManager
import android.app.admin.DnsEvent
import android.app.admin.IDevicePolicyManager
import android.app.admin.SecurityLog
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.IPackageInstaller
@@ -18,12 +17,10 @@ import androidx.annotation.DrawableRes
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.core.content.pm.ShortcutManagerCompat
import com.bintianqi.owndroid.MyAdminComponent
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SharedPrefs
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.createShortcuts
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.updatePrivilege
import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuBinderWrapper
import kotlinx.coroutines.flow.MutableStateFlow
@@ -37,24 +34,6 @@ import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import java.io.OutputStream
val Context.isDeviceOwner: Boolean
get() {
val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
return dpm.isDeviceOwnerApp(
if(SharedPrefs(this).dhizuku) {
Dhizuku.getOwnerPackageName()
} else {
"com.bintianqi.owndroid"
}
)
}
val Context.isProfileOwner: Boolean
get() {
val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
return dpm.isProfileOwnerApp("com.bintianqi.owndroid")
}
@SuppressLint("PrivateApi")
fun binderWrapperDevicePolicyManager(appContext: Context): DevicePolicyManager? {
try {
@@ -69,7 +48,8 @@ fun binderWrapperDevicePolicyManager(appContext: Context): DevicePolicyManager?
val newInterface = IDevicePolicyManager.Stub.asInterface(newBinder)
field[manager] = newInterface
return manager
} catch (_: Exception) {
} catch (e: Exception) {
e.printStackTrace()
dhizukuErrorStatus.value = 1
}
return null
@@ -96,7 +76,7 @@ private fun binderWrapperPackageInstaller(appContext: Context): PackageInstaller
}
fun Context.getPackageInstaller(): PackageInstaller {
if(SharedPrefs(this).dhizuku) {
if(SP.dhizuku) {
if (!dhizukuPermissionGranted()) {
dhizukuErrorStatus.value = 2
return this.packageManager.packageInstaller
@@ -107,26 +87,6 @@ fun Context.getPackageInstaller(): PackageInstaller {
}
}
fun Context.getDPM(): DevicePolicyManager {
if(SharedPrefs(this).dhizuku) {
if (!dhizukuPermissionGranted()) {
dhizukuErrorStatus.value = 2
return this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
}
return binderWrapperDevicePolicyManager(this) ?: this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
} else {
return this.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
}
}
fun Context.getReceiver(): ComponentName {
return if(SharedPrefs(this).dhizuku) {
Dhizuku.getOwnerComponent()
} else {
MyAdminComponent
}
}
val dhizukuErrorStatus = MutableStateFlow(0)
data class PermissionItem(
@@ -195,7 +155,7 @@ fun permissionList(): List<PermissionItem>{
@RequiresApi(26)
fun handleNetworkLogs(context: Context, batchToken: Long) {
val networkEvents = context.getDPM().retrieveNetworkLogs(context.getReceiver(), batchToken) ?: return
val networkEvents = Privilege.DPM.retrieveNetworkLogs(Privilege.DAR, batchToken) ?: return
val file = context.filesDir.resolve("NetworkLogs.json")
val fileExist = file.exists()
val json = Json { ignoreUnknownKeys = true; explicitNulls = false }
@@ -452,19 +412,16 @@ fun parseSecurityEventData(event: SecurityLog.SecurityEvent): JsonElement? {
}
}
fun setDefaultAffiliationID(context: Context) {
fun setDefaultAffiliationID() {
if(VERSION.SDK_INT < 26) return
val sp = SharedPrefs(context)
val privilege = myPrivilege.value
if(!sp.isDefaultAffiliationIdSet) {
val privilege = Privilege.status.value
if(!SP.isDefaultAffiliationIdSet) {
try {
if(privilege.device || (!privilege.primary && privilege.profile)) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
val affiliationIDs = dpm.getAffiliationIds(receiver)
val affiliationIDs = Privilege.DPM.getAffiliationIds(Privilege.DAR)
if(affiliationIDs.isEmpty()) {
dpm.setAffiliationIds(receiver, setOf("OwnDroid_default_affiliation_id"))
sp.isDefaultAffiliationIdSet = true
Privilege.DPM.setAffiliationIds(Privilege.DAR, setOf("OwnDroid_default_affiliation_id"))
SP.isDefaultAffiliationIdSet = true
Log.d("DPM", "Default affiliation id set")
}
}
@@ -510,33 +467,18 @@ fun parsePackageInstallerMessage(context: Context, result: Intent): String {
fun handlePrivilegeChange(context: Context) {
val privilege = myPrivilege.value
val activated = privilege.device || privilege.profile
val sp = SharedPrefs(context)
sp.dhizukuServer = false
if(activated) {
val privilege = Privilege.status.value
SP.dhizukuServer = false
if (privilege.activated) {
createShortcuts(context)
if(!privilege.dhizuku) {
setDefaultAffiliationID(context)
if (!privilege.dhizuku) {
setDefaultAffiliationID()
}
} else {
sp.isDefaultAffiliationIdSet = false
SP.isDefaultAffiliationIdSet = false
if(VERSION.SDK_INT >= 25) {
ShortcutManagerCompat.removeAllDynamicShortcuts(context)
}
sp.isApiEnabled = false
SP.isApiEnabled = false
}
}
fun checkPrivilege(context: Context) {
val sp = SharedPrefs(context)
if (sp.dhizuku) {
if (Dhizuku.init(context)) {
if (!dhizukuPermissionGranted()) { dhizukuErrorStatus.value = 2 }
} else {
sp.dhizuku = false
dhizukuErrorStatus.value = 1
}
}
updatePrivilege(context)
}

View File

@@ -129,11 +129,11 @@ import androidx.core.os.bundleOf
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.ChoosePackageContract
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.formatDate
import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.humanReadableDate
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -166,7 +166,7 @@ import kotlin.reflect.jvm.jvmErasure
@Composable
fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
MyScaffold(R.string.network, onNavigateUp, 0.dp) {
if(!privilege.dhizuku) FunctionItem(R.string.wifi, icon = R.drawable.wifi_fill0) { onNavigate(WiFi) }
if(VERSION.SDK_INT >= 30) {
@@ -202,15 +202,13 @@ fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable
fun NetworkOptionsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) }
MyScaffold(R.string.options, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) {
SwitchItem(R.string.lockdown_admin_configured_network, icon = R.drawable.wifi_password_fill0,
getState = { dpm.hasLockdownAdminConfiguredNetworks(receiver) }, onCheckedChange = { dpm.setConfiguredNetworksLockdownState(receiver,it) },
getState = { Privilege.DPM.hasLockdownAdminConfiguredNetworks(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setConfiguredNetworksLockdownState(Privilege.DAR, it) },
onClickBlank = { dialog = 1 }
)
}
@@ -265,7 +263,7 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
HorizontalPager(state = pagerState, verticalAlignment = Alignment.Top) { page ->
if(page == 0) {
val wm = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
@Suppress("DEPRECATION") Column(
modifier = Modifier.fillMaxSize().padding(top = 12.dp)
) {
@@ -313,13 +311,11 @@ fun WifiScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit, onNavigateTo
}
}
if(wifiMacDialog && VERSION.SDK_INT >= 24) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
AlertDialog(
onDismissRequest = { wifiMacDialog = false },
confirmButton = { TextButton(onClick = { wifiMacDialog = false }) { Text(stringResource(R.string.confirm)) } },
text = {
val mac = dpm.getWifiMacAddress(receiver)
val mac = Privilege.DPM.getWifiMacAddress(Privilege.DAR)
OutlinedTextField(
value = mac ?: stringResource(R.string.none), label = { Text(stringResource(R.string.wifi_mac_address)) },
onValueChange = {}, readOnly = true, modifier = Modifier.fillMaxWidth(), textStyle = typography.bodyLarge,
@@ -763,9 +759,8 @@ private fun AddNetworkScreen(wifiConfig: WifiConfiguration? = null, onNavigateUp
@Composable
fun WifiSecurityLevelScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
var selectedWifiSecLevel by remember { mutableIntStateOf(0) }
LaunchedEffect(Unit) { selectedWifiSecLevel = dpm.minimumRequiredWifiSecurityLevel }
LaunchedEffect(Unit) { selectedWifiSecLevel = Privilege.DPM.minimumRequiredWifiSecurityLevel }
MyScaffold(R.string.min_wifi_security_level, onNavigateUp, 0.dp) {
FullWidthRadioButtonItem(R.string.wifi_security_open, selectedWifiSecLevel == WIFI_SECURITY_OPEN) { selectedWifiSecLevel = WIFI_SECURITY_OPEN }
FullWidthRadioButtonItem("WEP, WPA(2)-PSK", selectedWifiSecLevel == WIFI_SECURITY_PERSONAL) { selectedWifiSecLevel = WIFI_SECURITY_PERSONAL }
@@ -773,7 +768,7 @@ fun WifiSecurityLevelScreen(onNavigateUp: () -> Unit) {
FullWidthRadioButtonItem("WPA3-192bit", selectedWifiSecLevel == WIFI_SECURITY_ENTERPRISE_192) { selectedWifiSecLevel = WIFI_SECURITY_ENTERPRISE_192 }
Button(
onClick = {
dpm.minimumRequiredWifiSecurityLevel = selectedWifiSecLevel
Privilege.DPM.minimumRequiredWifiSecurityLevel = selectedWifiSecLevel
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = HorizontalPadding)
@@ -790,13 +785,12 @@ fun WifiSecurityLevelScreen(onNavigateUp: () -> Unit) {
@Composable
fun WifiSsidPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
MyScaffold(R.string.wifi_ssid_policy, onNavigateUp, 0.dp) {
var selectedPolicyType by remember { mutableIntStateOf(-1) }
val ssidList = remember { mutableStateListOf<WifiSsid>() }
fun refreshPolicy() {
val policy = dpm.wifiSsidPolicy
val policy = Privilege.DPM.wifiSsidPolicy
ssidList.clear()
selectedPolicyType = policy?.policyType ?: -1
ssidList.addAll(policy?.ssids ?: mutableSetOf())
@@ -842,7 +836,7 @@ fun WifiSsidPolicyScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
focusMgr.clearFocus()
dpm.wifiSsidPolicy = if(selectedPolicyType == -1 || ssidList.isEmpty()) {
Privilege.DPM.wifiSsidPolicy = if(selectedPolicyType == -1 || ssidList.isEmpty()) {
null
} else {
WifiSsidPolicy(selectedPolicyType, ssidList.toSet())
@@ -894,7 +888,7 @@ fun NetworkStats.toBucketList(): List<NetworkStats.Bucket> {
@Composable
fun NetworkStatsScreen(onNavigateUp: () -> Unit, onNavigateToViewer: (NetworkStatsViewer) -> Unit) {
val context = LocalContext.current
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val fm = LocalFocusManager.current
val nsm = context.getSystemService(NetworkStatsManager::class.java)
val coroutine = rememberCoroutineScope()
@@ -1392,8 +1386,6 @@ fun NetworkStatsViewerScreen(nsv: NetworkStatsViewer, onNavigateUp: () -> Unit)
@Composable
fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
MyScaffold(R.string.private_dns, onNavigateUp) {
fun getDnsStatus(code: Int) = when (code) {
@@ -1409,16 +1401,16 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
PRIVATE_DNS_SET_ERROR_FAILURE_SETTING -> R.string.failed
else -> R.string.place_holder
}
var dnsMode by remember { mutableIntStateOf(dpm.getGlobalPrivateDnsMode(receiver)) }
var dnsMode by remember { mutableIntStateOf(Privilege.DPM.getGlobalPrivateDnsMode(Privilege.DAR)) }
Spacer(Modifier.padding(vertical = 5.dp))
Text(stringResource(R.string.current_state, stringResource(getDnsStatus(dnsMode))))
AnimatedVisibility(visible = dpm.getGlobalPrivateDnsMode(receiver)!=PRIVATE_DNS_MODE_OPPORTUNISTIC) {
AnimatedVisibility(Privilege.DPM.getGlobalPrivateDnsMode(Privilege.DAR) != PRIVATE_DNS_MODE_OPPORTUNISTIC) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
val result = dpm.setGlobalPrivateDnsModeOpportunistic(receiver)
val result = Privilege.DPM.setGlobalPrivateDnsModeOpportunistic(Privilege.DAR)
context.popToast(getOperationResult(result))
dnsMode = dpm.getGlobalPrivateDnsMode(receiver)
dnsMode = Privilege.DPM.getGlobalPrivateDnsMode(Privilege.DAR)
},
modifier = Modifier.fillMaxWidth()
) {
@@ -1427,7 +1419,7 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
}
Notes(R.string.info_private_dns_mode_oppertunistic)
Spacer(Modifier.padding(vertical = 10.dp))
var inputHost by remember { mutableStateOf(dpm.getGlobalPrivateDnsHost(receiver) ?: "") }
var inputHost by remember { mutableStateOf(Privilege.DPM.getGlobalPrivateDnsHost(Privilege.DAR) ?: "") }
OutlinedTextField(
value = inputHost,
onValueChange = { inputHost=it },
@@ -1441,7 +1433,7 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
onClick = {
focusMgr.clearFocus()
try {
val result = dpm.setGlobalPrivateDnsModeSpecifiedHost(receiver,inputHost)
val result = Privilege.DPM.setGlobalPrivateDnsModeSpecifiedHost(Privilege.DAR, inputHost)
context.popToast(getOperationResult(result))
} catch(e: IllegalArgumentException) {
e.printStackTrace()
@@ -1450,7 +1442,7 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
e.printStackTrace()
context.popToast(R.string.security_exception)
} finally {
dnsMode = dpm.getGlobalPrivateDnsMode(receiver)
dnsMode = Privilege.DPM.getGlobalPrivateDnsMode(Privilege.DAR)
}
},
modifier = Modifier.fillMaxWidth()
@@ -1467,19 +1459,17 @@ fun PrivateDnsScreen(onNavigateUp: () -> Unit) {
@Composable
fun AlwaysOnVpnPackageScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var lockdown by rememberSaveable { mutableStateOf(false) }
var pkgName by rememberSaveable { mutableStateOf("") }
val focusMgr = LocalFocusManager.current
val refresh = { pkgName = dpm.getAlwaysOnVpnPackage(receiver) ?: "" }
val refresh = { pkgName = Privilege.DPM.getAlwaysOnVpnPackage(Privilege.DAR) ?: "" }
LaunchedEffect(Unit) { refresh() }
val choosePackage = rememberLauncherForActivityResult(ChoosePackageContract()) { result ->
result?.let { pkgName = it }
}
val setAlwaysOnVpn: (String?, Boolean)->Boolean = { vpnPkg: String?, lockdownEnabled: Boolean ->
try {
dpm.setAlwaysOnVpnPackage(receiver, vpnPkg, lockdownEnabled)
Privilege.DPM.setAlwaysOnVpnPackage(Privilege.DAR, vpnPkg, lockdownEnabled)
context.showOperationResultToast(true)
true
} catch(e: UnsupportedOperationException) {
@@ -1532,8 +1522,6 @@ fun AlwaysOnVpnPackageScreen(onNavigateUp: () -> Unit) {
@Composable
fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var proxyType by remember { mutableIntStateOf(0) }
var proxyUri by remember { mutableStateOf("") }
@@ -1584,7 +1572,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
if(proxyType == 0) {
dpm.setRecommendedGlobalProxy(receiver, null)
Privilege.DPM.setRecommendedGlobalProxy(Privilege.DAR, null)
context.showOperationResultToast(true)
return@Button
}
@@ -1615,7 +1603,7 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) {
context.popToast(R.string.invalid_config)
return@Button
}
dpm.setRecommendedGlobalProxy(receiver, proxyInfo)
Privilege.DPM.setRecommendedGlobalProxy(Privilege.DAR, proxyInfo)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
@@ -1632,8 +1620,6 @@ fun RecommendedGlobalProxyScreen(onNavigateUp: () -> Unit) {
@Composable
fun NetworkLoggingScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val logFile = context.filesDir.resolve("NetworkLogs.json")
var fileSize by remember { mutableLongStateOf(0) }
LaunchedEffect(Unit) { fileSize = logFile.length() }
@@ -1648,8 +1634,8 @@ fun NetworkLoggingScreen(onNavigateUp: () -> Unit) {
MyScaffold(R.string.network_logging, onNavigateUp) {
SwitchItem(
R.string.enable,
getState = { dpm.isNetworkLoggingEnabled(receiver) },
onCheckedChange = { dpm.setNetworkLoggingEnabled(receiver,it) },
getState = { Privilege.DPM.isNetworkLoggingEnabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setNetworkLoggingEnabled(Privilege.DAR, it) },
padding = false
)
Text(stringResource(R.string.log_file_size_is, formatFileSize(fileSize)))
@@ -1684,7 +1670,6 @@ fun NetworkLoggingScreen(onNavigateUp: () -> Unit) {
@Composable
fun WifiAuthKeypairScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
var keyPair by remember { mutableStateOf("") }
MyScaffold(R.string.wifi_auth_keypair, onNavigateUp) {
@@ -1698,7 +1683,7 @@ fun WifiAuthKeypairScreen(onNavigateUp: () -> Unit) {
)
Spacer(Modifier.padding(vertical = 5.dp))
val isExist = try {
dpm.isKeyPairGrantedToWifiAuth(keyPair)
Privilege.DPM.isKeyPairGrantedToWifiAuth(keyPair)
} catch(e: java.lang.IllegalArgumentException) {
e.printStackTrace()
false
@@ -1707,13 +1692,13 @@ fun WifiAuthKeypairScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button(
onClick = { context.showOperationResultToast(dpm.grantKeyPairToWifiAuth(keyPair)) },
onClick = { context.showOperationResultToast(Privilege.DPM.grantKeyPairToWifiAuth(keyPair)) },
modifier = Modifier.fillMaxWidth(0.49F)
) {
Text(stringResource(R.string.grant))
}
Button(
onClick = { context.showOperationResultToast(dpm.revokeKeyPairFromWifiAuth(keyPair)) },
onClick = { context.showOperationResultToast(Privilege.DPM.revokeKeyPairFromWifiAuth(keyPair)) },
modifier = Modifier.fillMaxWidth(0.96F)
) {
Text(stringResource(R.string.revoke))
@@ -1727,19 +1712,17 @@ fun WifiAuthKeypairScreen(onNavigateUp: () -> Unit) {
@RequiresApi(33)
@Composable
fun PreferentialNetworkServiceScreen(onNavigateUp: () -> Unit, onNavigate: (AddPreferentialNetworkServiceConfig) -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
var masterEnabled by remember { mutableStateOf(false) }
val configs = remember { mutableStateListOf<PreferentialNetworkServiceConfig>() }
fun refresh() {
masterEnabled = dpm.isPreferentialNetworkServiceEnabled
masterEnabled = Privilege.DPM.isPreferentialNetworkServiceEnabled
configs.clear()
configs.addAll(dpm.preferentialNetworkServiceConfigs)
configs.addAll(Privilege.DPM.preferentialNetworkServiceConfigs)
}
LaunchedEffect(Unit) { refresh() }
MySmallTitleScaffold(R.string.preferential_network_service, onNavigateUp, 0.dp) {
SwitchItem(R.string.enabled, state = masterEnabled, onCheckedChange = {
dpm.isPreferentialNetworkServiceEnabled = it
Privilege.DPM.isPreferentialNetworkServiceEnabled = it
refresh()
})
Spacer(Modifier.padding(vertical = 4.dp))
@@ -1794,7 +1777,6 @@ fun PreferentialNetworkServiceScreen(onNavigateUp: () -> Unit, onNavigate: (AddP
fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServiceConfig,onNavigateUp: () -> Unit) {
val updateMode = route.index != -1
val context = LocalContext.current
val dpm = context.getDPM()
var enabled by remember { mutableStateOf(route.enabled) }
var id by remember { mutableIntStateOf(route.id) }
var allowFallback by remember { mutableStateOf(route.allowFallback) }
@@ -1854,10 +1836,10 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
setIncludedUids(includedUids.lines().filter { it.isNotBlank() }.map { it.toInt() }.toIntArray())
if(VERSION.SDK_INT >= 34) setShouldBlockNonMatchingNetworks(blockNonMatching)
}.build()
val configs = dpm.preferentialNetworkServiceConfigs
val configs = Privilege.DPM.preferentialNetworkServiceConfigs
if(updateMode) configs[route.index] = config
else configs += config
dpm.preferentialNetworkServiceConfigs = configs
Privilege.DPM.preferentialNetworkServiceConfigs = configs
onNavigateUp()
} catch(e: Exception) {
context.showOperationResultToast(false)
@@ -1872,7 +1854,7 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
if(updateMode) Button(
onClick = {
try {
dpm.preferentialNetworkServiceConfigs = dpm.preferentialNetworkServiceConfigs.drop(route.index)
Privilege.DPM.preferentialNetworkServiceConfigs = Privilege.DPM.preferentialNetworkServiceConfigs.drop(route.index)
onNavigateUp()
} catch(e: Exception) {
context.showOperationResultToast(false)
@@ -1892,22 +1874,19 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
@RequiresApi(28)
@Composable
fun OverrideApnScreen(onNavigateUp: () -> Unit, onNavigateToAddSetting: (Bundle) -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var enabled by remember { mutableStateOf(false) }
val settings = remember { mutableStateListOf<ApnSetting>() }
fun refresh() {
enabled = dpm.isOverrideApnEnabled(receiver)
enabled = Privilege.DPM.isOverrideApnEnabled(Privilege.DAR)
settings.clear()
settings.addAll(dpm.getOverrideApns(receiver))
settings.addAll(Privilege.DPM.getOverrideApns(Privilege.DAR))
}
LaunchedEffect(Unit) { refresh() }
MyScaffold(R.string.override_apn, onNavigateUp, 0.dp) {
SwitchItem(
R.string.enable, state = enabled,
onCheckedChange = {
dpm.setOverrideApnsEnabled(receiver, it)
Privilege.DPM.setOverrideApnsEnabled(Privilege.DAR, it)
refresh()
}
)
@@ -1957,9 +1936,6 @@ private val apnTypes = listOf(
@RequiresApi(28)
@Composable
fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val fm = LocalFocusManager.current
var dropdown by remember { mutableIntStateOf(0) } // 1:Auth type, 2:MVNO type, 3:Protocol, 4:Roaming protocol
var dialog by remember { mutableIntStateOf(0) } // 1:Proxy, 2:MMS proxy
@@ -2204,9 +2180,9 @@ fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
if(VERSION.SDK_INT >= 35) setAlwaysOn(alwaysOn)
}.build()
if(origin == null) {
dpm.addOverrideApn(receiver, setting)
Privilege.DPM.addOverrideApn(Privilege.DAR, setting)
} else {
dpm.updateOverrideApn(receiver, origin.id, setting)
Privilege.DPM.updateOverrideApn(Privilege.DAR, origin.id, setting)
}
onNavigateUp()
} catch(e: Exception) {
@@ -2219,7 +2195,7 @@ fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
}
if(origin != null) Button(
{
dpm.removeOverrideApn(receiver, origin.id)
Privilege.DPM.removeOverrideApn(Privilege.DAR, origin.id)
onNavigateUp()
},
Modifier.fillMaxWidth(),

View File

@@ -66,9 +66,9 @@ import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.startActivity
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SharedPrefs
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -88,11 +88,11 @@ import kotlinx.serialization.Serializable
@Composable
fun PasswordScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val context = LocalContext.current
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) }
MyScaffold(R.string.password_and_keyguard, onNavigateUp, 0.dp) {
FunctionItem(R.string.password_info, icon = R.drawable.info_fill0) { onNavigate(PasswordInfo) }
if(SharedPrefs(context).displayDangerousFeatures) {
if(SP.displayDangerousFeatures) {
if(VERSION.SDK_INT >= 26) {
FunctionItem(R.string.reset_password_token, icon = R.drawable.key_vertical_fill0) { onNavigate(ResetPasswordToken) }
}
@@ -116,16 +116,14 @@ fun PasswordScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
}
}
if(dialog != 0) {
val dpm = context.getDPM()
val receiver = context.getReceiver()
var input by remember { mutableStateOf("") }
LaunchedEffect(Unit) {
input = when(dialog) {
1 -> dpm.getMaximumTimeToLock(receiver).toString()
2 -> dpm.getRequiredStrongAuthTimeout(receiver).toString()
3 -> dpm.getPasswordExpirationTimeout(receiver).toString()
4 -> dpm.getMaximumFailedPasswordsForWipe(receiver).toString()
5 -> dpm.getPasswordHistoryLength(receiver).toString()
1 -> Privilege.DPM.getMaximumTimeToLock(Privilege.DAR).toString()
2 -> Privilege.DPM.getRequiredStrongAuthTimeout(Privilege.DAR).toString()
3 -> Privilege.DPM.getPasswordExpirationTimeout(Privilege.DAR).toString()
4 -> Privilege.DPM.getMaximumFailedPasswordsForWipe(Privilege.DAR).toString()
5 -> Privilege.DPM.getPasswordHistoryLength(Privilege.DAR).toString()
else -> ""
}
}
@@ -180,11 +178,11 @@ fun PasswordScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
TextButton(
onClick = {
when(dialog) {
1 -> dpm.setMaximumTimeToLock(receiver, input.toLong())
2 -> dpm.setRequiredStrongAuthTimeout(receiver, input.toLong())
3 -> dpm.setPasswordExpirationTimeout(receiver, input.toLong())
4 -> dpm.setMaximumFailedPasswordsForWipe(receiver, input.toInt())
5 -> dpm.setPasswordHistoryLength(receiver, input.toInt())
1 -> Privilege.DPM.setMaximumTimeToLock(Privilege.DAR, input.toLong())
2 -> Privilege.DPM.setRequiredStrongAuthTimeout(Privilege.DAR, input.toLong())
3 -> Privilege.DPM.setPasswordExpirationTimeout(Privilege.DAR, input.toLong())
4 -> Privilege.DPM.setMaximumFailedPasswordsForWipe(Privilege.DAR, input.toInt())
5 -> Privilege.DPM.setPasswordHistoryLength(Privilege.DAR, input.toInt())
}
dialog = 0
}
@@ -208,14 +206,11 @@ fun PasswordScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable
fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) } // 0:none, 1:password complexity
MyScaffold(R.string.password_info, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 29) {
val text = when(dpm.passwordComplexity) {
val text = when(Privilege.DPM.passwordComplexity) {
PASSWORD_COMPLEXITY_NONE -> R.string.none
PASSWORD_COMPLEXITY_LOW -> R.string.low
PASSWORD_COMPLEXITY_MEDIUM -> R.string.medium
@@ -224,9 +219,9 @@ fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
}
InfoItem(R.string.current_password_complexity, text, true) { dialog = 1 }
}
InfoItem(R.string.password_sufficient, dpm.isActivePasswordSufficient.yesOrNo)
InfoItem(R.string.password_sufficient, Privilege.DPM.isActivePasswordSufficient.yesOrNo)
if(VERSION.SDK_INT >= 28 && privilege.work) {
InfoItem(R.string.unified_password, dpm.isUsingUnifiedPassword(receiver).yesOrNo)
InfoItem(R.string.unified_password, Privilege.DPM.isUsingUnifiedPassword(Privilege.DAR).yesOrNo)
}
}
if(dialog != 0) AlertDialog(
@@ -246,8 +241,6 @@ fun PasswordInfoScreen(onNavigateUp: () -> Unit) {
@Composable
fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var token by remember { mutableStateOf("") }
val tokenByteArray = token.toByteArray()
val focusMgr = LocalFocusManager.current
@@ -267,7 +260,7 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
try {
context.showOperationResultToast(dpm.setResetPasswordToken(receiver, tokenByteArray))
context.showOperationResultToast(Privilege.DPM.setResetPasswordToken(Privilege.DAR, tokenByteArray))
} catch(_:SecurityException) {
context.popToast(R.string.security_exception)
}
@@ -283,7 +276,7 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) {
) {
Button(
onClick = {
if(!dpm.isResetPasswordTokenActive(receiver)) {
if(!Privilege.DPM.isResetPasswordTokenActive(Privilege.DAR)) {
try { activateToken(context) }
catch(_:NullPointerException) { context.popToast(R.string.please_set_a_token) }
} else { context.popToast(R.string.token_already_activated) }
@@ -293,7 +286,7 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.activate))
}
Button(
onClick = { context.showOperationResultToast(dpm.clearResetPasswordToken(receiver)) },
onClick = { context.showOperationResultToast(Privilege.DPM.clearResetPasswordToken(Privilege.DAR)) },
modifier = Modifier.fillMaxWidth(0.96F)
) {
Text(stringResource(R.string.clear))
@@ -309,8 +302,6 @@ fun ResetPasswordTokenScreen(onNavigateUp: () -> Unit) {
@Composable
fun ResetPasswordScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var password by remember { mutableStateOf("") }
var useToken by remember { mutableStateOf(false) }
@@ -401,9 +392,9 @@ fun ResetPasswordScreen(onNavigateUp: () -> Unit) {
TextButton(
onClick = {
val success = if(VERSION.SDK_INT >= 26 && useToken) {
dpm.resetPasswordWithToken(receiver, password, tokenByteArray, flag)
Privilege.DPM.resetPasswordWithToken(Privilege.DAR, password, tokenByteArray, flag)
} else {
dpm.resetPassword(password, flag)
Privilege.DPM.resetPassword(password, flag)
}
context.showOperationResultToast(success)
password = ""
@@ -430,7 +421,6 @@ fun ResetPasswordScreen(onNavigateUp: () -> Unit) {
@Composable
fun RequiredPasswordComplexityScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val passwordComplexity = mapOf(
PASSWORD_COMPLEXITY_NONE to R.string.none,
PASSWORD_COMPLEXITY_LOW to R.string.low,
@@ -438,7 +428,7 @@ fun RequiredPasswordComplexityScreen(onNavigateUp: () -> Unit) {
PASSWORD_COMPLEXITY_HIGH to R.string.high
)
var selectedItem by remember { mutableIntStateOf(PASSWORD_COMPLEXITY_NONE) }
LaunchedEffect(Unit) { selectedItem = dpm.requiredPasswordComplexity }
LaunchedEffect(Unit) { selectedItem = Privilege.DPM.requiredPasswordComplexity }
MyScaffold(R.string.required_password_complexity, onNavigateUp, 0.dp) {
passwordComplexity.forEach {
FullWidthRadioButtonItem(it.value, selectedItem == it.key) { selectedItem = it.key }
@@ -446,8 +436,8 @@ fun RequiredPasswordComplexityScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
dpm.requiredPasswordComplexity = selectedItem
selectedItem = dpm.requiredPasswordComplexity
Privilege.DPM.requiredPasswordComplexity = selectedItem
selectedItem = Privilege.DPM.requiredPasswordComplexity
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp, horizontal = HorizontalPadding)
@@ -463,8 +453,6 @@ fun RequiredPasswordComplexityScreen(onNavigateUp: () -> Unit) {
@Composable
fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var flag by remember { mutableIntStateOf(0) }
var mode by remember { mutableIntStateOf(0) } // 0:Enable all, 1:Disable all, 2:Custom
val flagsLiat = mutableListOf(
@@ -482,14 +470,14 @@ fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
}
if(VERSION.SDK_INT >= 34) flagsLiat += R.string.disable_keyguard_features_shortcuts to KEYGUARD_DISABLE_SHORTCUTS_ALL
fun refresh() {
flag = dpm.getKeyguardDisabledFeatures(receiver)
flag = Privilege.DPM.getKeyguardDisabledFeatures(Privilege.DAR)
mode = when(flag) {
KEYGUARD_DISABLE_FEATURES_NONE -> 0
KEYGUARD_DISABLE_FEATURES_ALL -> 1
else -> 2
}
}
LaunchedEffect(mode) { if(mode != 2) flag = dpm.getKeyguardDisabledFeatures(receiver) }
LaunchedEffect(mode) { if(mode != 2) flag = Privilege.DPM.getKeyguardDisabledFeatures(Privilege.DAR) }
LaunchedEffect(Unit) { refresh() }
MyScaffold(R.string.disable_keyguard_features, onNavigateUp) {
FullWidthRadioButtonItem(R.string.enable_all, mode == 0) { mode = 0 }
@@ -507,7 +495,7 @@ fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
val disabledFeatures = if(mode == 0) KEYGUARD_DISABLE_FEATURES_NONE else if(mode == 1) KEYGUARD_DISABLE_FEATURES_ALL else flag
dpm.setKeyguardDisabledFeatures(receiver, disabledFeatures)
Privilege.DPM.setKeyguardDisabledFeatures(Privilege.DAR, disabledFeatures)
refresh()
context.showOperationResultToast(true)
},
@@ -523,8 +511,6 @@ fun KeyguardDisabledFeaturesScreen(onNavigateUp: () -> Unit) {
@Composable
fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val passwordQuality = mapOf(
PASSWORD_QUALITY_UNSPECIFIED to R.string.password_quality_unspecified,
PASSWORD_QUALITY_SOMETHING to R.string.password_quality_something,
@@ -535,7 +521,7 @@ fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) {
PASSWORD_QUALITY_NUMERIC_COMPLEX to R.string.password_quality_numeric_complex
)
var selectedItem by remember { mutableIntStateOf(PASSWORD_QUALITY_UNSPECIFIED) }
LaunchedEffect(Unit) { selectedItem=dpm.getPasswordQuality(receiver) }
LaunchedEffect(Unit) { selectedItem = Privilege.DPM.getPasswordQuality(Privilege.DAR) }
MyScaffold(R.string.required_password_quality, onNavigateUp) {
passwordQuality.forEach {
RadioButtonItem(it.value, selectedItem == it.key) { selectedItem = it.key }
@@ -543,7 +529,7 @@ fun RequiredPasswordQualityScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
dpm.setPasswordQuality(receiver,selectedItem)
Privilege.DPM.setPasswordQuality(Privilege.DAR, selectedItem)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -558,7 +544,7 @@ private fun activateToken(context: Context) {
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val confirmIntent = keyguardManager.createConfirmDeviceCredentialIntent(context.getString(R.string.app_name), desc)
if (confirmIntent != null) {
startActivity(context,confirmIntent, null)
startActivity(context, confirmIntent, null)
} else {
context.showOperationResultToast(false)
}

View File

@@ -94,10 +94,10 @@ import com.bintianqi.owndroid.DhizukuPermissions
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.IUserService
import com.bintianqi.owndroid.MyAdminComponent
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.Settings
import com.bintianqi.owndroid.SharedPrefs
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CircularProgressDialog
import com.bintianqi.owndroid.ui.InfoItem
@@ -107,7 +107,6 @@ import com.bintianqi.owndroid.ui.MySmallTitleScaffold
import com.bintianqi.owndroid.ui.NavIcon
import com.bintianqi.owndroid.ui.Notes
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.updatePrivilege
import com.bintianqi.owndroid.useShizuku
import com.bintianqi.owndroid.yesOrNo
import com.google.accompanist.drawablepainter.rememberDrawablePainter
@@ -129,13 +128,17 @@ fun WorkModesScreen(
) {
val context = LocalContext.current
val coroutine = rememberCoroutineScope()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 0: none, 1: device owner, 2: circular progress indicator, 3: result, 4: deactivate, 5: command */
var dialog by remember { mutableIntStateOf(0) }
var operationSucceed by remember { mutableStateOf(false) }
LaunchedEffect(privilege) {
if (!params.canNavigateUp && privilege.device) {
delay(1000)
if (dialog != 3) dialog = 3 // Activated by ADB command
if (dialog != 3) { // Activated by ADB command
operationSucceed = true
dialog = 3
}
}
}
Scaffold(
@@ -194,15 +197,13 @@ fun WorkModesScreen(
contentWindowInsets = WindowInsets.ime
) { paddingValues ->
var navigateUpOnSucceed by remember { mutableStateOf(true) }
var operationSucceed by remember { mutableStateOf(false) }
var resultText by remember { mutableStateOf("") }
fun handleResult(succeeded: Boolean, activateSucceeded: Boolean, output: String?) {
if(succeeded) {
operationSucceed = activateSucceeded
resultText = output ?: ""
dialog = 3
updatePrivilege(context)
handlePrivilegeChange(context)
Privilege.updateStatus()
} else {
dialog = 0
context.showOperationResultToast(false)
@@ -261,7 +262,7 @@ fun WorkModesScreen(
}
if(
privilege.work || (VERSION.SDK_INT < 24 ||
context.getDPM().isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE))
Privilege.DPM.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE))
) Row(
Modifier
.fillMaxWidth()
@@ -367,18 +368,18 @@ fun WorkModesScreen(
TextButton(
{
if(privilege.dhizuku) {
SharedPrefs(context).dhizuku = false
SP.dhizuku = false
Privilege.initialize(context)
Privilege.updateStatus()
} else {
val dpm = context.getDPM()
if(privilege.device) {
dpm.clearDeviceOwnerApp(context.packageName)
Privilege.DPM.clearDeviceOwnerApp(context.packageName)
} else if(VERSION.SDK_INT >= 24) {
dpm.clearProfileOwner(MyAdminComponent)
Privilege.DPM.clearProfileOwner(MyAdminComponent)
}
// Status updated in Receiver.onDisabled()
}
dialog = 0
updatePrivilege(context)
handlePrivilegeChange(context)
},
enabled = time == 0,
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)
@@ -440,16 +441,23 @@ fun activateUsingRoot(context: Context, callback: (Boolean, Boolean, String?) ->
fun activateUsingDhizuku(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
fun doTransfer() {
try {
val dpm = binderWrapperDevicePolicyManager(context)
if(dpm == null) {
context.showOperationResultToast(false)
if (SP.dhizuku) {
Privilege.DPM.transferOwnership(Privilege.DAR, MyAdminComponent, PersistableBundle())
SP.dhizuku = false
Privilege.initialize(context)
} else {
dpm.transferOwnership(Dhizuku.getOwnerComponent(), MyAdminComponent, PersistableBundle())
callback(true, true, null)
val dpm = binderWrapperDevicePolicyManager(context)
if (dpm == null) {
callback(false, false, null)
return
} else {
dpm.transferOwnership(Dhizuku.getOwnerComponent(), MyAdminComponent, PersistableBundle())
}
}
callback(true, true, null)
} catch (e: Exception) {
e.printStackTrace()
callback(true, false, null)
callback(false, false, null)
}
}
if(Dhizuku.init(context)) {
@@ -470,7 +478,8 @@ fun activateUsingDhizuku(context: Context, callback: (Boolean, Boolean, String?)
fun activateDhizukuMode(context: Context, callback: (Boolean, Boolean, String?) -> Unit) {
fun onSucceed() {
SharedPrefs(context).dhizuku = true
SP.dhizuku = true
Privilege.initialize(context)
callback(true, true, null)
}
if(Dhizuku.init(context)) {
@@ -496,13 +505,12 @@ const val ACTIVATE_DEVICE_OWNER_COMMAND = "dpm set-device-owner com.bintianqi.ow
fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val pm = context.packageManager
val sp = SharedPrefs(context)
val file = context.filesDir.resolve(DHIZUKU_CLIENTS_FILE)
var enabled by remember { mutableStateOf(sp.dhizukuServer) }
var enabled by remember { mutableStateOf(SP.dhizukuServer) }
val clients = remember { mutableStateListOf<DhizukuClientInfo>() }
fun changeEnableState(status: Boolean) {
enabled = status
sp.dhizukuServer = status
SP.dhizukuServer = status
}
fun writeList() {
file.writeText(Json.encodeToString(clients.toList()))
@@ -519,7 +527,7 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
}
MyLazyScaffold(R.string.dhizuku_server, onNavigateUp) {
item {
SwitchItem(R.string.enable, getState = { sp.dhizukuServer }, onCheckedChange = ::changeEnableState)
SwitchItem(R.string.enable, getState = { SP.dhizukuServer }, onCheckedChange = ::changeEnableState)
HorizontalDivider(Modifier.padding(vertical = 8.dp))
}
if (enabled) itemsIndexed(clients) { index, client ->
@@ -531,10 +539,14 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
val info = pm.getApplicationInfo(name, 0)
var expand by remember { mutableStateOf(false) }
Card(
Modifier.fillMaxWidth().padding(HorizontalPadding, 8.dp)
Modifier
.fillMaxWidth()
.padding(HorizontalPadding, 8.dp)
) {
Row(
Modifier.fillMaxWidth().padding(8.dp, 8.dp, 0.dp, 8.dp),
Modifier
.fillMaxWidth()
.padding(8.dp, 8.dp, 0.dp, 8.dp),
Arrangement.SpaceBetween, Alignment.CenterVertically
) {
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -597,10 +609,8 @@ fun DhizukuServerSettingsScreen(onNavigateUp: () -> Unit) {
@Composable
fun LockScreenInfoScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var infoText by remember { mutableStateOf(dpm.deviceOwnerLockScreenInfo?.toString() ?: "") }
var infoText by remember { mutableStateOf(Privilege.DPM.deviceOwnerLockScreenInfo?.toString() ?: "") }
MyScaffold(R.string.lock_screen_info, onNavigateUp) {
OutlinedTextField(
value = infoText,
@@ -615,7 +625,7 @@ fun LockScreenInfoScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
focusMgr.clearFocus()
dpm.setDeviceOwnerLockScreenInfo(receiver,infoText)
Privilege.DPM.setDeviceOwnerLockScreenInfo(Privilege.DAR, infoText)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -625,7 +635,7 @@ fun LockScreenInfoScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
focusMgr.clearFocus()
dpm.setDeviceOwnerLockScreenInfo(receiver, null)
Privilege.DPM.setDeviceOwnerLockScreenInfo(Privilege.DAR, null)
infoText = ""
context.showOperationResultToast(true)
},
@@ -659,15 +669,12 @@ enum class DelegatedScope(val id: String, @StringRes val string: Int, val requir
@RequiresApi(26)
@Composable
fun DelegatedAdminsScreen(onNavigateUp: () -> Unit, onNavigate: (AddDelegatedAdmin) -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val packages = remember { mutableStateMapOf<String, MutableList<DelegatedScope>>() }
fun refresh() {
val list = mutableMapOf<String, MutableList<DelegatedScope>>()
DelegatedScope.entries.forEach { ds ->
if(VERSION.SDK_INT >= ds.requiresApi) {
dpm.getDelegatePackages(receiver, ds.id)?.forEach { pkg ->
Privilege.DPM.getDelegatePackages(Privilege.DAR, ds.id)?.forEach { pkg ->
if(list[pkg] != null) {
list[pkg]!!.add(ds)
} else {
@@ -728,7 +735,6 @@ fun DelegatedAdminsScreen(onNavigateUp: () -> Unit, onNavigate: (AddDelegatedAdm
fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) {
val updateMode = data.pkg.isNotEmpty()
val fm = LocalFocusManager.current
val context = LocalContext.current
var input by remember { mutableStateOf(data.pkg) }
val scopes = remember { mutableStateListOf(*data.scopes.toTypedArray()) }
val choosePackage = rememberLauncherForActivityResult(ChoosePackageContract()) { result ->
@@ -768,7 +774,7 @@ fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) {
}
Button(
onClick = {
context.getDPM().setDelegatedScopes(context.getReceiver(), input, scopes.map { it.id })
Privilege.DPM.setDelegatedScopes(Privilege.DAR, input, scopes.map { it.id })
onNavigateUp()
},
modifier = Modifier
@@ -780,7 +786,7 @@ fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) {
}
if(updateMode) Button(
onClick = {
context.getDPM().setDelegatedScopes(context.getReceiver(), input, emptyList())
Privilege.DPM.setDelegatedScopes(Privilege.DAR, input, emptyList())
onNavigateUp()
},
modifier = Modifier
@@ -797,16 +803,14 @@ fun AddDelegatedAdminScreen(data: AddDelegatedAdmin, onNavigateUp: () -> Unit) {
@Composable
fun DeviceInfoScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) }
MyScaffold(R.string.device_info, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT>=34 && (privilege.device || privilege.org)) {
InfoItem(R.string.financed_device, dpm.isDeviceFinanced.yesOrNo)
InfoItem(R.string.financed_device, Privilege.DPM.isDeviceFinanced.yesOrNo)
}
if(VERSION.SDK_INT >= 33) {
val dpmRole = dpm.devicePolicyManagementRoleHolderPackage
val dpmRole = Privilege.DPM.devicePolicyManagementRoleHolderPackage
InfoItem(R.string.dpmrh, dpmRole ?: stringResource(R.string.none))
}
val encryptionStatus = mutableMapOf(
@@ -816,14 +820,14 @@ fun DeviceInfoScreen(onNavigateUp: () -> Unit) {
)
if(VERSION.SDK_INT >= 23) { encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY] = R.string.es_active_default_key }
if(VERSION.SDK_INT >= 24) { encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER] = R.string.es_active_per_user }
InfoItem(R.string.encryption_status, encryptionStatus[dpm.storageEncryptionStatus] ?: R.string.unknown)
InfoItem(R.string.encryption_status, encryptionStatus[Privilege.DPM.storageEncryptionStatus] ?: R.string.unknown)
if(VERSION.SDK_INT >= 28) {
InfoItem(R.string.support_device_id_attestation, dpm.isDeviceIdAttestationSupported.yesOrNo, true) { dialog = 1 }
InfoItem(R.string.support_device_id_attestation, Privilege.DPM.isDeviceIdAttestationSupported.yesOrNo, true) { dialog = 1 }
}
if (VERSION.SDK_INT >= 30) {
InfoItem(R.string.support_unique_device_attestation, dpm.isUniqueDeviceAttestationSupported.yesOrNo, true) { dialog = 2 }
InfoItem(R.string.support_unique_device_attestation, Privilege.DPM.isUniqueDeviceAttestationSupported.yesOrNo, true) { dialog = 2 }
}
val adminList = dpm.activeAdmins
val adminList = Privilege.DPM.activeAdmins
if(adminList != null) {
InfoItem(R.string.activated_device_admin, adminList.joinToString("\n") { it.flattenToShortString() })
}
@@ -841,13 +845,11 @@ fun DeviceInfoScreen(onNavigateUp: () -> Unit) {
@Composable
fun SupportMessageScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var shortMsg by remember { mutableStateOf("") }
var longMsg by remember { mutableStateOf("") }
val refreshMsg = {
shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: ""
longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: ""
shortMsg = Privilege.DPM.getShortSupportMessage(Privilege.DAR)?.toString() ?: ""
longMsg = Privilege.DPM.getLongSupportMessage(Privilege.DAR)?.toString() ?: ""
}
LaunchedEffect(Unit) { refreshMsg() }
MyScaffold(R.string.support_messages, onNavigateUp) {
@@ -863,7 +865,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button(
onClick = {
dpm.setShortSupportMessage(receiver, shortMsg)
Privilege.DPM.setShortSupportMessage(Privilege.DAR, shortMsg)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -873,7 +875,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
dpm.setShortSupportMessage(receiver, null)
Privilege.DPM.setShortSupportMessage(Privilege.DAR, null)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -896,7 +898,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button(
onClick = {
dpm.setLongSupportMessage(receiver, longMsg)
Privilege.DPM.setLongSupportMessage(Privilege.DAR, longMsg)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -906,7 +908,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
dpm.setLongSupportMessage(receiver, null)
Privilege.DPM.setLongSupportMessage(Privilege.DAR, null)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -925,7 +927,7 @@ fun SupportMessageScreen(onNavigateUp: () -> Unit) {
@Composable
fun TransferOwnershipScreen(onNavigateUp: () -> Unit, onTransferred: () -> Unit) {
val context = LocalContext.current
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val focusMgr = LocalFocusManager.current
var input by remember { mutableStateOf("") }
val componentName = ComponentName.unflattenFromString(input)
@@ -960,12 +962,10 @@ fun TransferOwnershipScreen(onNavigateUp: () -> Unit, onTransferred: () -> Unit)
confirmButton = {
TextButton(
onClick = {
val dpm = context.getDPM()
val receiver = context.getReceiver()
try {
dpm.transferOwnership(receiver, componentName!!, null)
Privilege.DPM.transferOwnership(Privilege.DAR, componentName!!, null)
Privilege.updateStatus()
context.showOperationResultToast(true)
updatePrivilege(context)
dialog = false
onTransferred()
} catch(e: Exception) {

View File

@@ -121,12 +121,12 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.ChoosePackageContract
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.NotificationUtils
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.SharedPrefs
import com.bintianqi.owndroid.SP
import com.bintianqi.owndroid.createShortcuts
import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.humanReadableDate
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.parseDate
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
@@ -161,14 +161,11 @@ import kotlin.math.roundToLong
@Composable
fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val sp = SharedPrefs(context)
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
/** 1: reboot, 2: bug report, 3: org name, 4: org id, 5: enrollment specific id*/
var dialog by remember { mutableIntStateOf(0) }
var enrollmentSpecificId by remember {
mutableStateOf(if (VERSION.SDK_INT >= 31 && (privilege.device || privilege.profile)) dpm.enrollmentSpecificId else "")
mutableStateOf(if (VERSION.SDK_INT >= 31 && (privilege.device || privilege.profile)) Privilege.DPM.enrollmentSpecificId else "")
}
MyScaffold(R.string.system, onNavigateUp, 0.dp) {
FunctionItem(R.string.options, icon = R.drawable.tune_fill0) { onNavigate(SystemOptions) }
@@ -178,7 +175,7 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
if(VERSION.SDK_INT >= 24 && privilege.device) {
FunctionItem(R.string.reboot, icon = R.drawable.restart_alt_fill0) { dialog = 1 }
}
if(VERSION.SDK_INT >= 24 && privilege.device && (VERSION.SDK_INT < 28 || dpm.isAffiliatedUser)) {
if(VERSION.SDK_INT >= 24 && privilege.device && (VERSION.SDK_INT < 28 || privilege.affiliated)) {
FunctionItem(R.string.bug_report, icon = R.drawable.bug_report_fill0) { dialog = 2 }
}
if(VERSION.SDK_INT >= 28 && (privilege.device || privilege.org)) {
@@ -235,7 +232,7 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
if(VERSION.SDK_INT >= 30 && (privilege.device || privilege.org)) {
FunctionItem(R.string.frp_policy, icon = R.drawable.device_reset_fill0) { onNavigate(FrpPolicy) }
}
if(sp.displayDangerousFeatures && !privilege.work) {
if(SP.displayDangerousFeatures && !privilege.work) {
FunctionItem(R.string.wipe_data, icon = R.drawable.device_reset_fill0) { onNavigate(WipeData) }
}
}
@@ -252,9 +249,9 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
TextButton(
onClick = {
if(dialog == 1) {
dpm.reboot(receiver)
Privilege.DPM.reboot(Privilege.DAR)
} else {
context.showOperationResultToast(dpm.requestBugreport(receiver))
context.showOperationResultToast(Privilege.DPM.requestBugreport(Privilege.DAR))
}
dialog = 0
}
@@ -270,7 +267,7 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
text = {
val focusMgr = LocalFocusManager.current
LaunchedEffect(Unit) {
if(dialog == 5 && VERSION.SDK_INT >= 31) input = dpm.enrollmentSpecificId
if(dialog == 5 && VERSION.SDK_INT >= 31) input = Privilege.DPM.enrollmentSpecificId
}
Column {
OutlinedTextField(
@@ -306,10 +303,10 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
TextButton(
onClick = {
try {
if (dialog == 3 && VERSION.SDK_INT >= 24) dpm.setOrganizationName(receiver, input)
if (dialog == 3 && VERSION.SDK_INT >= 24) Privilege.DPM.setOrganizationName(Privilege.DAR, input)
if (dialog == 4 && VERSION.SDK_INT >= 31) {
dpm.setOrganizationId(input)
enrollmentSpecificId = dpm.enrollmentSpecificId
Privilege.DPM.setOrganizationId(input)
enrollmentSpecificId = Privilege.DPM.enrollmentSpecificId
}
dialog = 0
} catch(_: IllegalStateException) {
@@ -330,66 +327,71 @@ fun SystemManagerScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable
fun SystemOptionsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) }
MyScaffold(R.string.options, onNavigateUp, 0.dp) {
SwitchItem(R.string.disable_cam, icon = R.drawable.no_photography_fill0,
getState = { dpm.getCameraDisabled(null) }, onCheckedChange = {
dpm.setCameraDisabled(receiver, it)
getState = { Privilege.DPM.getCameraDisabled(null) }, onCheckedChange = {
Privilege.DPM.setCameraDisabled(Privilege.DAR, it)
createShortcuts(context)
}
)
SwitchItem(R.string.disable_screen_capture, icon = R.drawable.screenshot_fill0,
getState = { dpm.getScreenCaptureDisabled(null) }, onCheckedChange = { dpm.setScreenCaptureDisabled(receiver,it) }
getState = { Privilege.DPM.getScreenCaptureDisabled(null) },
onCheckedChange = { Privilege.DPM.setScreenCaptureDisabled(Privilege.DAR, it) }
)
if(VERSION.SDK_INT >= 34 && (privilege.device || (privilege.profile && privilege.affiliated))) {
SwitchItem(R.string.disable_status_bar, icon = R.drawable.notifications_fill0,
getState = { dpm.isStatusBarDisabled}, onCheckedChange = { dpm.setStatusBarDisabled(receiver,it) }
getState = { Privilege.DPM.isStatusBarDisabled},
onCheckedChange = { Privilege.DPM.setStatusBarDisabled(Privilege.DAR, it) }
)
}
if(privilege.device || privilege.org) {
if(VERSION.SDK_INT >= 30) {
SwitchItem(R.string.auto_time, icon = R.drawable.schedule_fill0,
getState = { dpm.getAutoTimeEnabled(receiver) }, onCheckedChange = { dpm.setAutoTimeEnabled(receiver,it) }
getState = { Privilege.DPM.getAutoTimeEnabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setAutoTimeEnabled(Privilege.DAR, it) }
)
SwitchItem(R.string.auto_timezone, icon = R.drawable.globe_fill0,
getState = { dpm.getAutoTimeZoneEnabled(receiver) }, onCheckedChange = { dpm.setAutoTimeZoneEnabled(receiver,it) }
getState = { Privilege.DPM.getAutoTimeZoneEnabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setAutoTimeZoneEnabled(Privilege.DAR, it) }
)
} else {
SwitchItem(R.string.require_auto_time, icon = R.drawable.schedule_fill0,
getState = { dpm.autoTimeRequired }, onCheckedChange = { dpm.setAutoTimeRequired(receiver,it) }, padding = false)
getState = { Privilege.DPM.autoTimeRequired },
onCheckedChange = { Privilege.DPM.setAutoTimeRequired(Privilege.DAR, it) }, padding = false)
}
}
if (!privilege.work) SwitchItem(R.string.master_mute, icon = R.drawable.volume_off_fill0,
getState = { dpm.isMasterVolumeMuted(receiver) }, onCheckedChange = {
dpm.setMasterVolumeMuted(receiver,it)
getState = { Privilege.DPM.isMasterVolumeMuted(Privilege.DAR) }, onCheckedChange = {
Privilege.DPM.setMasterVolumeMuted(Privilege.DAR, it)
createShortcuts(context)
}
)
if(VERSION.SDK_INT >= 26) {
SwitchItem(R.string.backup_service, icon = R.drawable.backup_fill0,
getState = { dpm.isBackupServiceEnabled(receiver) }, onCheckedChange = { dpm.setBackupServiceEnabled(receiver,it) },
getState = { Privilege.DPM.isBackupServiceEnabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setBackupServiceEnabled(Privilege.DAR, it) },
onClickBlank = { dialog = 1 }
)
}
if(VERSION.SDK_INT >= 24 && privilege.work) {
SwitchItem(R.string.disable_bt_contact_share, icon = R.drawable.account_circle_fill0,
getState = { dpm.getBluetoothContactSharingDisabled(receiver) },
onCheckedChange = { dpm.setBluetoothContactSharingDisabled(receiver,it) }
getState = { Privilege.DPM.getBluetoothContactSharingDisabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setBluetoothContactSharingDisabled(Privilege.DAR, it) }
)
}
if(VERSION.SDK_INT >= 30 && privilege.device) {
SwitchItem(R.string.common_criteria_mode , icon =R.drawable.security_fill0,
getState = { dpm.isCommonCriteriaModeEnabled(receiver) }, onCheckedChange = { dpm.setCommonCriteriaModeEnabled(receiver,it) },
getState = { Privilege.DPM.isCommonCriteriaModeEnabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setCommonCriteriaModeEnabled(Privilege.DAR, it) },
onClickBlank = { dialog = 2 }
)
}
if(VERSION.SDK_INT >= 31 && (privilege.device || privilege.org) && dpm.canUsbDataSignalingBeDisabled()) {
if(VERSION.SDK_INT >= 31 && (privilege.device || privilege.org) && Privilege.DPM.canUsbDataSignalingBeDisabled()) {
SwitchItem(
R.string.disable_usb_signal, icon = R.drawable.usb_fill0, getState = { !dpm.isUsbDataSignalingEnabled },
onCheckedChange = { dpm.isUsbDataSignalingEnabled = !it },
R.string.disable_usb_signal, icon = R.drawable.usb_fill0, getState = { !Privilege.DPM.isUsbDataSignalingEnabled },
onCheckedChange = { Privilege.DPM.isUsbDataSignalingEnabled = !it },
)
}
}
@@ -415,9 +417,7 @@ fun SystemOptionsScreen(onNavigateUp: () -> Unit) {
@Composable
fun KeyguardScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
MyScaffold(R.string.keyguard, onNavigateUp) {
if(VERSION.SDK_INT >= 23 && (privilege.device || (VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated))) {
Row(
@@ -425,13 +425,13 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
modifier = Modifier.fillMaxWidth()
) {
Button(
onClick = { context.showOperationResultToast(dpm.setKeyguardDisabled(receiver, true)) },
onClick = { context.showOperationResultToast(Privilege.DPM.setKeyguardDisabled(Privilege.DAR, true)) },
modifier = Modifier.fillMaxWidth(0.49F)
) {
Text(stringResource(R.string.disable))
}
Button(
onClick = { context.showOperationResultToast(dpm.setKeyguardDisabled(receiver, false)) },
onClick = { context.showOperationResultToast(Privilege.DPM.setKeyguardDisabled(Privilege.DAR, false)) },
modifier = Modifier.fillMaxWidth(0.96F)
) {
Text(stringResource(R.string.enable))
@@ -452,7 +452,7 @@ fun KeyguardScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
if(VERSION.SDK_INT >= 26) dpm.lockNow(flag) else dpm.lockNow()
if(VERSION.SDK_INT >= 26) Privilege.DPM.lockNow(flag) else Privilege.DPM.lockNow()
},
modifier = Modifier.fillMaxWidth()
) {
@@ -553,8 +553,6 @@ fun HardwareMonitorScreen(onNavigateUp: () -> Unit) {
@Composable
fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val pagerState = rememberPagerState { 2 }
var picker by remember { mutableIntStateOf(0) } //0:None, 1:DatePicker, 2:TimePicker
@@ -617,7 +615,7 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
val timeMillis = datePickerState.selectedDateMillis!! + timePickerState.hour * 3600000 + timePickerState.minute * 60000
context.showOperationResultToast(dpm.setTime(receiver, timeMillis))
context.showOperationResultToast(Privilege.DPM.setTime(Privilege.DAR, timeMillis))
},
modifier = Modifier.fillMaxWidth(),
enabled = datePickerState.selectedDateMillis != null
@@ -637,7 +635,7 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
val timeMillis = inputTime.toLong()
context.showOperationResultToast(dpm.setTime(receiver, timeMillis))
context.showOperationResultToast(Privilege.DPM.setTime(Privilege.DAR, timeMillis))
},
modifier = Modifier
.fillMaxWidth()
@@ -677,9 +675,7 @@ fun ChangeTimeScreen(onNavigateUp: () -> Unit) {
@Composable
fun ChangeTimeZoneScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
val receiver = context.getReceiver()
var inputTimezone by remember { mutableStateOf("") }
var dialog by remember { mutableStateOf(false) }
MyScaffold(R.string.change_timezone, onNavigateUp) {
@@ -699,7 +695,7 @@ fun ChangeTimeZoneScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
context.showOperationResultToast(dpm.setTimeZone(receiver, inputTimezone))
context.showOperationResultToast(Privilege.DPM.setTimeZone(Privilege.DAR, inputTimezone))
},
modifier = Modifier.fillMaxWidth()
) {
@@ -741,9 +737,7 @@ fun ChangeTimeZoneScreen(onNavigateUp: () -> Unit) {
@RequiresApi(36)
@Composable
fun AutoTimePolicyScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.auto_time_policy, onNavigateUp, 0.dp) {
val context = LocalContext.current
val dpm = context.getDPM()
var policy by remember { mutableIntStateOf(dpm.autoTimePolicy) }
var policy by remember { mutableIntStateOf(Privilege.DPM.autoTimePolicy) }
listOf(
DevicePolicyManager.AUTO_TIME_ENABLED to R.string.enable,
DevicePolicyManager.AUTO_TIME_DISABLED to R.string.disabled,
@@ -754,8 +748,8 @@ fun AutoTimePolicyScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.auto_ti
}
}
Button({
dpm.autoTimePolicy = policy
policy = dpm.autoTimePolicy
Privilege.DPM.autoTimePolicy = policy
policy = Privilege.DPM.autoTimePolicy
}, Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding)) {
Text(stringResource(R.string.apply))
}
@@ -766,9 +760,7 @@ fun AutoTimePolicyScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.auto_ti
@RequiresApi(36)
@Composable
fun AutoTimeZonePolicyScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.auto_timezone_policy, onNavigateUp, 0.dp) {
val context = LocalContext.current
val dpm = context.getDPM()
var policy by remember { mutableIntStateOf(dpm.autoTimeZonePolicy) }
var policy by remember { mutableIntStateOf(Privilege.DPM.autoTimeZonePolicy) }
listOf(
DevicePolicyManager.AUTO_TIME_ZONE_ENABLED to R.string.enable,
DevicePolicyManager.AUTO_TIME_ZONE_DISABLED to R.string.disabled,
@@ -779,8 +771,8 @@ fun AutoTimeZonePolicyScreen(onNavigateUp: () -> Unit) = MyScaffold(R.string.aut
}
}
Button({
dpm.autoTimeZonePolicy = policy
policy = dpm.autoTimeZonePolicy
Privilege.DPM.autoTimeZonePolicy = policy
policy = Privilege.DPM.autoTimeZonePolicy
}, Modifier.fillMaxWidth().padding(horizontal = HorizontalPadding)) {
Text(stringResource(R.string.apply))
}
@@ -972,10 +964,8 @@ fun KeyPairs(navCtrl: NavHostController) {
@Composable
fun ContentProtectionPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var policy by remember { mutableIntStateOf(DevicePolicyManager.CONTENT_PROTECTION_NOT_CONTROLLED_BY_POLICY) }
fun refresh() { policy = dpm.getContentProtectionPolicy(receiver) }
fun refresh() { policy = Privilege.DPM.getContentProtectionPolicy(Privilege.DAR) }
LaunchedEffect(Unit) { refresh() }
MyScaffold(R.string.content_protection_policy, onNavigateUp, 0.dp) {
mapOf(
@@ -987,7 +977,7 @@ fun ContentProtectionPolicyScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
dpm.setContentProtectionPolicy(receiver, policy)
Privilege.DPM.setContentProtectionPolicy(Privilege.DAR, policy)
refresh()
context.showOperationResultToast(true)
},
@@ -1007,9 +997,7 @@ fun ContentProtectionPolicyScreen(onNavigateUp: () -> Unit) {
@Composable
fun PermissionPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var selectedPolicy by remember { mutableIntStateOf(dpm.getPermissionPolicy(receiver)) }
var selectedPolicy by remember { mutableIntStateOf(Privilege.DPM.getPermissionPolicy(Privilege.DAR)) }
MyScaffold(R.string.permission_policy, onNavigateUp, 0.dp) {
FullWidthRadioButtonItem(R.string.default_stringres, selectedPolicy == PERMISSION_POLICY_PROMPT) {
selectedPolicy = PERMISSION_POLICY_PROMPT
@@ -1023,7 +1011,7 @@ fun PermissionPolicyScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
dpm.setPermissionPolicy(receiver,selectedPolicy)
Privilege.DPM.setPermissionPolicy(Privilege.DAR,selectedPolicy)
context.showOperationResultToast(true)
},
modifier = Modifier
@@ -1042,8 +1030,7 @@ fun PermissionPolicyScreen(onNavigateUp: () -> Unit) {
@Composable
fun MtePolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
var selectedMtePolicy by remember { mutableIntStateOf(dpm.mtePolicy) }
var selectedMtePolicy by remember { mutableIntStateOf(Privilege.DPM.mtePolicy) }
MyScaffold(R.string.mte_policy, onNavigateUp, 0.dp) {
FullWidthRadioButtonItem(R.string.decide_by_user, selectedMtePolicy == MTE_NOT_CONTROLLED_BY_POLICY) {
selectedMtePolicy = MTE_NOT_CONTROLLED_BY_POLICY
@@ -1053,12 +1040,12 @@ fun MtePolicyScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
try {
dpm.mtePolicy = selectedMtePolicy
Privilege.DPM.mtePolicy = selectedMtePolicy
context.showOperationResultToast(true)
} catch(_: java.lang.UnsupportedOperationException) {
context.popToast(R.string.unsupported)
}
selectedMtePolicy = dpm.mtePolicy
selectedMtePolicy = Privilege.DPM.mtePolicy
},
modifier = Modifier
.fillMaxWidth()
@@ -1076,8 +1063,7 @@ fun MtePolicyScreen(onNavigateUp: () -> Unit) {
@Composable
fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
var appPolicy by remember { mutableIntStateOf(dpm.nearbyAppStreamingPolicy) }
var appPolicy by remember { mutableIntStateOf(Privilege.DPM.nearbyAppStreamingPolicy) }
MySmallTitleScaffold(R.string.nearby_streaming_policy, onNavigateUp, 0.dp) {
Text(
stringResource(R.string.nearby_app_streaming),
@@ -1095,8 +1081,8 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
) { appPolicy = NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY }
Button(
onClick = {
dpm.nearbyAppStreamingPolicy = appPolicy
appPolicy = dpm.nearbyAppStreamingPolicy
Privilege.DPM.nearbyAppStreamingPolicy = appPolicy
appPolicy = Privilege.DPM.nearbyAppStreamingPolicy
context.showOperationResultToast(true)
},
modifier = Modifier
@@ -1106,7 +1092,7 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.apply))
}
Notes(R.string.info_nearby_app_streaming_policy, HorizontalPadding)
var notificationPolicy by remember { mutableIntStateOf(dpm.nearbyNotificationStreamingPolicy) }
var notificationPolicy by remember { mutableIntStateOf(Privilege.DPM.nearbyNotificationStreamingPolicy) }
Text(
stringResource(R.string.nearby_notification_streaming),
Modifier.padding(start = 8.dp, top = 10.dp, bottom = 4.dp), style = typography.titleLarge
@@ -1129,8 +1115,8 @@ fun NearbyStreamingPolicyScreen(onNavigateUp: () -> Unit) {
) { notificationPolicy = NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY }
Button(
onClick = {
dpm.nearbyNotificationStreamingPolicy = notificationPolicy
notificationPolicy = dpm.nearbyNotificationStreamingPolicy
Privilege.DPM.nearbyNotificationStreamingPolicy = notificationPolicy
notificationPolicy = Privilege.DPM.nearbyNotificationStreamingPolicy
context.showOperationResultToast(true)
},
modifier = Modifier
@@ -1213,7 +1199,6 @@ fun LockTaskModeScreen(onNavigateUp: () -> Unit) {
@Composable
private fun ColumnScope.StartLockTaskMode() {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
var startLockTaskApp by rememberSaveable { mutableStateOf("") }
var startLockTaskActivity by rememberSaveable { mutableStateOf("") }
@@ -1256,7 +1241,7 @@ private fun ColumnScope.StartLockTaskMode() {
modifier = Modifier.fillMaxWidth(),
onClick = {
if(!NotificationUtils.checkPermission(context)) return@Button
if(!dpm.isLockTaskPermitted(startLockTaskApp)) {
if(!Privilege.DPM.isLockTaskPermitted(startLockTaskApp)) {
context.popToast(R.string.app_not_allowed)
return@Button
}
@@ -1281,15 +1266,13 @@ private fun ColumnScope.StartLockTaskMode() {
@Composable
private fun ColumnScope.LockTaskPackages() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val lockTaskPackages = remember { mutableStateListOf<String>() }
var input by rememberSaveable { mutableStateOf("") }
val choosePackage = rememberLauncherForActivityResult(ChoosePackageContract()) { result ->
result?.let { input = it }
}
LaunchedEffect(Unit) { lockTaskPackages.addAll(dpm.getLockTaskPackages(receiver)) }
LaunchedEffect(Unit) { lockTaskPackages.addAll(Privilege.DPM.getLockTaskPackages(Privilege.DAR)) }
Spacer(Modifier.padding(vertical = 5.dp))
if(lockTaskPackages.isEmpty()) Text(text = stringResource(R.string.none))
for(i in lockTaskPackages) {
@@ -1335,7 +1318,7 @@ private fun ColumnScope.LockTaskPackages() {
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
dpm.setLockTaskPackages(receiver, lockTaskPackages.toTypedArray())
Privilege.DPM.setLockTaskPackages(Privilege.DAR, lockTaskPackages.toTypedArray())
context.showOperationResultToast(true)
}
) {
@@ -1348,13 +1331,11 @@ private fun ColumnScope.LockTaskPackages() {
@Composable
private fun ColumnScope.LockTaskFeatures() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var flags by remember { mutableIntStateOf(0) }
var custom by rememberSaveable { mutableStateOf(false) }
var errorMessage by remember { mutableStateOf<String?>(null) }
fun refresh() {
flags = dpm.getLockTaskFeatures(receiver)
flags = Privilege.DPM.getLockTaskFeatures(Privilege.DAR)
custom = flags != 0
}
LaunchedEffect(Unit) { refresh() }
@@ -1385,7 +1366,7 @@ private fun ColumnScope.LockTaskFeatures() {
.padding(vertical = 4.dp, horizontal = HorizontalPadding),
onClick = {
try {
dpm.setLockTaskFeatures(receiver, flags)
Privilege.DPM.setLockTaskFeatures(Privilege.DAR, flags)
context.showOperationResultToast(true)
} catch (e: IllegalArgumentException) {
errorMessage = e.message
@@ -1409,8 +1390,6 @@ data class CaCertInfo(
@Composable
fun CaCertScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
/** 0:none, 1:install, 2:info, 3:uninstall all */
var dialog by remember { mutableIntStateOf(0) }
var caCertByteArray by remember { mutableStateOf(byteArrayOf()) }
@@ -1436,7 +1415,7 @@ fun CaCertScreen(onNavigateUp: () -> Unit) {
caCerts.clear()
coroutine.launch(Dispatchers.IO) {
val md = MessageDigest.getInstance("SHA-256")
dpm.getInstalledCaCerts(receiver).forEach { ba ->
Privilege.DPM.getInstalledCaCerts(Privilege.DAR).forEach { ba ->
val hash = md.digest(ba).toHexString()
withContext(Dispatchers.Main) { caCerts += CaCertInfo(hash, ba) }
}
@@ -1519,7 +1498,7 @@ fun CaCertScreen(onNavigateUp: () -> Unit) {
.padding(top = 4.dp), Arrangement.SpaceBetween) {
TextButton(
onClick = {
dpm.uninstallCaCert(receiver, caCertByteArray)
Privilege.DPM.uninstallCaCert(Privilege.DAR, caCertByteArray)
refresh()
dialog = 0
},
@@ -1544,10 +1523,10 @@ fun CaCertScreen(onNavigateUp: () -> Unit) {
TextButton({
try {
if(dialog == 1) {
context.showOperationResultToast(dpm.installCaCert(receiver, caCertByteArray))
context.showOperationResultToast(Privilege.DPM.installCaCert(Privilege.DAR, caCertByteArray))
}
if(dialog == 3) {
dpm.uninstallAllUserCaCerts(receiver)
Privilege.DPM.uninstallAllUserCaCerts(Privilege.DAR)
}
refresh()
dialog = 0
@@ -1575,8 +1554,6 @@ fun CaCertScreen(onNavigateUp: () -> Unit) {
@Composable
fun SecurityLoggingScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val logFile = context.filesDir.resolve("SecurityLogs.json")
var fileSize by remember { mutableLongStateOf(0) }
LaunchedEffect(Unit) { fileSize = logFile.length() }
@@ -1597,7 +1574,8 @@ fun SecurityLoggingScreen(onNavigateUp: () -> Unit) {
MyScaffold(R.string.security_logging, onNavigateUp) {
SwitchItem(
R.string.enable,
getState = { dpm.isSecurityLoggingEnabled(receiver) }, onCheckedChange = { dpm.setSecurityLoggingEnabled(receiver, it) },
getState = { Privilege.DPM.isSecurityLoggingEnabled(Privilege.DAR) },
onCheckedChange = { Privilege.DPM.setSecurityLoggingEnabled(Privilege.DAR, it) },
padding = false
)
Text(stringResource(R.string.log_file_size_is, formatFileSize(fileSize)))
@@ -1626,7 +1604,7 @@ fun SecurityLoggingScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
val logs = dpm.retrievePreRebootSecurityLogs(receiver)
val logs = Privilege.DPM.retrievePreRebootSecurityLogs(Privilege.DAR)
if(logs == null) {
context.popToast(R.string.no_logs)
return@Button
@@ -1651,22 +1629,19 @@ fun SecurityLoggingScreen(onNavigateUp: () -> Unit) {
@Composable
fun DisableAccountManagementScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
MyScaffold(R.string.disable_account_management, onNavigateUp) {
val list = remember { mutableStateListOf<String>() }
fun refreshList() {
list.clear()
dpm.accountTypesWithManagementDisabled?.forEach { list += it }
Privilege.DPM.accountTypesWithManagementDisabled?.forEach { list += it }
}
LaunchedEffect(Unit) { refreshList() }
Column(modifier = Modifier.animateContentSize()) {
if(list.isEmpty()) Text(stringResource(R.string.none))
for(i in list) {
ListItem(i) {
dpm.setAccountManagementDisabled(receiver, i, false)
Privilege.DPM.setAccountManagementDisabled(Privilege.DAR, i, false)
refreshList()
}
}
@@ -1679,7 +1654,7 @@ fun DisableAccountManagementScreen(onNavigateUp: () -> Unit) {
trailingIcon = {
IconButton(
onClick = {
dpm.setAccountManagementDisabled(receiver, inputText, true)
Privilege.DPM.setAccountManagementDisabled(Privilege.DAR, inputText, true)
inputText = ""
refreshList()
},
@@ -1704,10 +1679,7 @@ fun DisableAccountManagementScreen(onNavigateUp: () -> Unit) {
@RequiresApi(30)
@Composable
fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
val receiver = context.getReceiver()
var usePolicy by remember { mutableStateOf(false) }
var enabled by remember { mutableStateOf(false) }
var unsupported by remember { mutableStateOf(false) }
@@ -1716,7 +1688,7 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
LaunchedEffect(Unit) {
var policy: FactoryResetProtectionPolicy? = null
try {
policy = dpm.getFactoryResetProtectionPolicy(receiver)
policy = Privilege.DPM.getFactoryResetProtectionPolicy(Privilege.DAR)
} catch(_: UnsupportedOperationException) {
unsupported = true
policy = null
@@ -1789,7 +1761,7 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
.setFactoryResetProtectionEnabled(enabled)
.setFactoryResetProtectionAccounts(accountList)
.build()
dpm.setFactoryResetProtectionPolicy(receiver, policy)
Privilege.DPM.setFactoryResetProtectionPolicy(Privilege.DAR, policy)
},
modifier = Modifier
.fillMaxWidth()
@@ -1807,8 +1779,7 @@ fun FrpPolicyScreen(onNavigateUp: () -> Unit) {
fun WipeDataScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val focusMgr = LocalFocusManager.current
var flag by remember { mutableIntStateOf(0) }
var warning by remember { mutableStateOf(false) }
@@ -1887,12 +1858,12 @@ fun WipeDataScreen(onNavigateUp: () -> Unit) {
onClick = {
if(silent && VERSION.SDK_INT >= 29) { flag = flag or WIPE_SILENTLY }
if(wipeDevice && VERSION.SDK_INT >= 34) {
dpm.wipeDevice(flag)
Privilege.DPM.wipeDevice(flag)
} else {
if(VERSION.SDK_INT >= 28 && reason != "") {
dpm.wipeData(flag, reason)
Privilege.DPM.wipeData(flag, reason)
} else {
dpm.wipeData(flag)
Privilege.DPM.wipeData(flag)
}
}
},
@@ -1918,11 +1889,9 @@ fun WipeDataScreen(onNavigateUp: () -> Unit) {
@Composable
fun SystemUpdatePolicyScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
MyScaffold(R.string.system_update_policy, onNavigateUp, 0.dp) {
var selectedPolicy by remember { mutableStateOf(dpm.systemUpdatePolicy?.policyType) }
var selectedPolicy by remember { mutableStateOf(Privilege.DPM.systemUpdatePolicy?.policyType) }
FullWidthRadioButtonItem(
R.string.system_update_policy_automatic,
selectedPolicy == TYPE_INSTALL_AUTOMATIC
@@ -1974,7 +1943,7 @@ fun SystemUpdatePolicyScreen(onNavigateUp: () -> Unit) {
TYPE_POSTPONE-> SystemUpdatePolicy.createPostponeInstallPolicy()
else -> null
}
dpm.setSystemUpdatePolicy(receiver,policy)
Privilege.DPM.setSystemUpdatePolicy(Privilege.DAR, policy)
context.showOperationResultToast(true)
},
modifier = Modifier
@@ -1984,7 +1953,7 @@ fun SystemUpdatePolicyScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.apply))
}
if(VERSION.SDK_INT >= 26) {
val sysUpdateInfo = dpm.getPendingSystemUpdate(receiver)
val sysUpdateInfo = Privilege.DPM.getPendingSystemUpdate(Privilege.DAR)
Column(Modifier.padding(HorizontalPadding)) {
if(sysUpdateInfo != null) {
Text(text = stringResource(R.string.update_received_time, Date(sysUpdateInfo.receivedTime)))
@@ -2008,8 +1977,6 @@ fun SystemUpdatePolicyScreen(onNavigateUp: () -> Unit) {
@Composable
fun InstallSystemUpdateScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val callback = object: InstallSystemUpdateCallback() {
override fun onInstallUpdateError(errorCode: Int, errorMessage: String) {
super.onInstallUpdateError(errorCode, errorMessage)
@@ -2043,7 +2010,7 @@ fun InstallSystemUpdateScreen(onNavigateUp: () -> Unit) {
onClick = {
val executor = Executors.newCachedThreadPool()
try {
dpm.installSystemUpdate(receiver, uri!!, executor, callback)
Privilege.DPM.installSystemUpdate(Privilege.DAR, uri!!, executor, callback)
context.popToast(R.string.start_install_system_update)
} catch(e: Exception) {
errorMessage = e.message

View File

@@ -55,8 +55,8 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.FunctionItem
import com.bintianqi.owndroid.ui.MyLazyScaffold
@@ -77,7 +77,7 @@ data class Restriction(
@RequiresApi(24)
@Composable
fun UserRestrictionScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val sb = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
fun navigateToOptions(title: Int, items: List<Restriction>) {
onNavigate(UserRestrictionOptions(title, items))
@@ -147,11 +147,9 @@ fun UserRestrictionOptionsScreen(
data: UserRestrictionOptions, onNavigateUp: () -> Unit
) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val status = remember { mutableStateMapOf<String, Boolean>() }
fun refresh() {
val restrictions = dpm.getUserRestrictions(receiver)
val restrictions = Privilege.DPM.getUserRestrictions(Privilege.DAR)
data.items.forEach {
status.put(it.id, restrictions.getBoolean(it.id))
}
@@ -178,9 +176,9 @@ fun UserRestrictionOptionsScreen(
{
try {
if (it) {
dpm.addUserRestriction(receiver, restriction.id)
Privilege.DPM.addUserRestriction(Privilege.DAR, restriction.id)
} else {
dpm.clearUserRestriction(receiver, restriction.id)
Privilege.DPM.clearUserRestriction(Privilege.DAR, restriction.id)
}
} catch (e: Exception) {
e.printStackTrace()
@@ -288,11 +286,9 @@ object RestrictionData {
@Composable
fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val list = remember { mutableStateListOf<String>() }
fun refresh() {
val restrictions = dpm.getUserRestrictions(receiver)
val restrictions = Privilege.DPM.getUserRestrictions(Privilege.DAR)
list.clear()
list.addAll(restrictions.keySet().filter { restrictions.getBoolean(it) })
}
@@ -315,7 +311,7 @@ fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
Text(it)
IconButton({
try {
dpm.clearUserRestriction(receiver, it)
Privilege.DPM.clearUserRestriction(Privilege.DAR, it)
} catch (e: Exception) {
e.printStackTrace()
context.showOperationResultToast(false)
@@ -330,7 +326,7 @@ fun UserRestrictionEditorScreen(onNavigateUp: () -> Unit) {
var input by remember { mutableStateOf("") }
fun add() {
try {
dpm.addUserRestriction(receiver, input)
Privilege.DPM.addUserRestriction(Privilege.DAR, input)
input = ""
} catch (e: Exception) {
e.printStackTrace()

View File

@@ -62,8 +62,8 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.HorizontalPadding
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.parseTimestamp
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
@@ -87,9 +87,7 @@ import kotlinx.serialization.Serializable
@Composable
fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
var dialog by remember { mutableIntStateOf(0) }
MyScaffold(R.string.users, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 28 && privilege.profile && privilege.affiliated) {
@@ -134,7 +132,7 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
text = {
if(dialog == 1) {
val um = context.getSystemService(Context.USER_SERVICE) as UserManager
val list = dpm.getSecondaryUsers(receiver)
val list = Privilege.DPM.getSecondaryUsers(Privilege.DAR)
if(list.isEmpty()) {
Text(stringResource(R.string.no_secondary_users))
} else {
@@ -148,7 +146,7 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
TextButton(
onClick = {
if(dialog == 2) {
val result = dpm.logoutUser(receiver)
val result = Privilege.DPM.logoutUser(Privilege.DAR)
context.popToast(userOperationResultCode(result))
}
dialog = 0
@@ -170,12 +168,10 @@ fun UsersScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable
fun UsersOptionsScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
MyScaffold(R.string.options, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 28) {
SwitchItem(R.string.enable_logout, getState = { dpm.isLogoutEnabled }, onCheckedChange = { dpm.setLogoutEnabled(receiver, it) })
SwitchItem(R.string.enable_logout, getState = { Privilege.DPM.isLogoutEnabled },
onCheckedChange = { Privilege.DPM.setLogoutEnabled(Privilege.DAR, it) })
}
}
}
@@ -185,9 +181,7 @@ fun UsersOptionsScreen(onNavigateUp: () -> Unit) {
@Composable
fun UserInfoScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val user = Process.myUserHandle()
var infoDialog by remember { mutableIntStateOf(0) }
@@ -202,8 +196,8 @@ fun UserInfoScreen(onNavigateUp: () -> Unit) {
if(it != 0L) InfoItem(R.string.creation_time, parseTimestamp(it))
}
if (VERSION.SDK_INT >= 28) {
InfoItem(R.string.logout_enabled, dpm.isLogoutEnabled.yesOrNo)
InfoItem(R.string.ephemeral_user, dpm.isEphemeralUser(receiver).yesOrNo)
InfoItem(R.string.logout_enabled, Privilege.DPM.isLogoutEnabled.yesOrNo)
InfoItem(R.string.ephemeral_user, Privilege.DPM.isEphemeralUser(Privilege.DAR).yesOrNo)
InfoItem(R.string.affiliated_user, privilege.affiliated.yesOrNo)
}
InfoItem(R.string.user_id, (Binder.getCallingUid() / 100000).toString())
@@ -226,8 +220,6 @@ fun UserInfoScreen(onNavigateUp: () -> Unit) {
fun UserOperationScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM()
val receiver = context.getReceiver()
var input by remember { mutableStateOf("") }
val focusMgr = LocalFocusManager.current
var useUserId by remember { mutableStateOf(false) }
@@ -266,7 +258,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) {
onClick = {
focusMgr.clearFocus()
withUserHandle {
val result = dpm.startUserInBackground(receiver, it)
val result = Privilege.DPM.startUserInBackground(Privilege.DAR, it)
context.popToast(userOperationResultCode(result))
}
},
@@ -280,7 +272,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
focusMgr.clearFocus()
withUserHandle { context.showOperationResultToast(dpm.switchUser(receiver, it)) }
withUserHandle { context.showOperationResultToast(Privilege.DPM.switchUser(Privilege.DAR, it)) }
},
enabled = legalInput,
modifier = Modifier.fillMaxWidth()
@@ -293,7 +285,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) {
onClick = {
focusMgr.clearFocus()
withUserHandle {
val result = dpm.stopUser(receiver, it)
val result = Privilege.DPM.stopUser(Privilege.DAR, it)
context.popToast(userOperationResultCode(result))
}
},
@@ -308,7 +300,7 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) {
onClick = {
focusMgr.clearFocus()
withUserHandle {
if(dpm.removeUser(receiver, it)) {
if(Privilege.DPM.removeUser(Privilege.DAR, it)) {
context.showOperationResultToast(true)
input = ""
} else {
@@ -332,8 +324,6 @@ fun UserOperationScreen(onNavigateUp: () -> Unit) {
fun CreateUserScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var userName by remember { mutableStateOf("") }
var creating by remember { mutableStateOf(false) }
@@ -369,7 +359,7 @@ fun CreateUserScreen(onNavigateUp: () -> Unit) {
creating = true
coroutine.launch(Dispatchers.IO) {
try {
val uh = dpm.createAndManageUser(receiver, userName, receiver, null, flag)
val uh = Privilege.DPM.createAndManageUser(Privilege.DAR, userName, Privilege.DAR, null, flag)
withContext(Dispatchers.Main) {
createdUserSerialNumber = userManager.getSerialNumberForUser(uh)
}
@@ -408,14 +398,12 @@ fun CreateUserScreen(onNavigateUp: () -> Unit) {
@Composable
fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var input by remember { mutableStateOf("") }
val list = remember { mutableStateListOf<String>() }
val refreshIds = {
list.clear()
list.addAll(dpm.getAffiliationIds(receiver))
list.addAll(Privilege.DPM.getAffiliationIds(Privilege.DAR))
}
LaunchedEffect(Unit) { refreshIds() }
MyScaffold(R.string.affiliation_id, onNavigateUp) {
@@ -449,7 +437,7 @@ fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
Button(
onClick = {
list.removeAll(setOf(""))
dpm.setAffiliationIds(receiver, list.toSet())
Privilege.DPM.setAffiliationIds(Privilege.DAR, list.toSet())
context.showOperationResultToast(true)
refreshIds()
},
@@ -466,8 +454,6 @@ fun AffiliationIdScreen(onNavigateUp: () -> Unit) {
@Composable
fun ChangeUsernameScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var inputUsername by remember { mutableStateOf("") }
MyScaffold(R.string.change_username, onNavigateUp) {
@@ -482,7 +468,7 @@ fun ChangeUsernameScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
dpm.setProfileName(receiver, inputUsername)
Privilege.DPM.setProfileName(Privilege.DAR, inputUsername)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -490,7 +476,7 @@ fun ChangeUsernameScreen(onNavigateUp: () -> Unit) {
Text(stringResource(R.string.apply))
}
Button(
onClick = { dpm.setProfileName(receiver,null) },
onClick = { Privilege.DPM.setProfileName(Privilege.DAR, null) },
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.reset))
@@ -504,14 +490,12 @@ fun ChangeUsernameScreen(onNavigateUp: () -> Unit) {
@Composable
fun UserSessionMessageScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var start by remember { mutableStateOf("") }
var end by remember { mutableStateOf("") }
val refreshMsg = {
start = dpm.getStartUserSessionMessage(receiver)?.toString() ?: ""
end = dpm.getEndUserSessionMessage(receiver)?.toString() ?: ""
start = Privilege.DPM.getStartUserSessionMessage(Privilege.DAR)?.toString() ?: ""
end = Privilege.DPM.getEndUserSessionMessage(Privilege.DAR)?.toString() ?: ""
}
LaunchedEffect(Unit) { refreshMsg() }
MyScaffold(R.string.user_session_msg, onNavigateUp) {
@@ -526,7 +510,7 @@ fun UserSessionMessageScreen(onNavigateUp: () -> Unit) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button(
onClick = {
dpm.setStartUserSessionMessage(receiver,start)
Privilege.DPM.setStartUserSessionMessage(Privilege.DAR, start)
refreshMsg()
},
modifier = Modifier.fillMaxWidth(0.49F)
@@ -535,7 +519,7 @@ fun UserSessionMessageScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
dpm.setStartUserSessionMessage(receiver,null)
Privilege.DPM.setStartUserSessionMessage(Privilege.DAR, null)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -556,7 +540,7 @@ fun UserSessionMessageScreen(onNavigateUp: () -> Unit) {
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Button(
onClick = {
dpm.setEndUserSessionMessage(receiver,end)
Privilege.DPM.setEndUserSessionMessage(Privilege.DAR, end)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -566,7 +550,7 @@ fun UserSessionMessageScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
dpm.setEndUserSessionMessage(receiver,null)
Privilege.DPM.setEndUserSessionMessage(Privilege.DAR, null)
refreshMsg()
context.showOperationResultToast(true)
},
@@ -594,7 +578,7 @@ private fun ChangeUserIconDialog(bitmap: Bitmap, onClose: () -> Unit) {
},
confirmButton = {
TextButton({
context.getDPM().setUserIcon(context.getReceiver(), bitmap)
Privilege.DPM.setUserIcon(Privilege.DAR, bitmap)
context.showOperationResultToast(true)
onClose()
}) {

View File

@@ -56,8 +56,9 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bintianqi.owndroid.IUserService
import com.bintianqi.owndroid.MyAdminComponent
import com.bintianqi.owndroid.Privilege
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.myPrivilege
import com.bintianqi.owndroid.popToast
import com.bintianqi.owndroid.showOperationResultToast
import com.bintianqi.owndroid.ui.CheckBoxItem
@@ -72,7 +73,7 @@ import kotlinx.serialization.Serializable
@Composable
fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
val privilege by myPrivilege.collectAsStateWithLifecycle()
val privilege by Privilege.status.collectAsStateWithLifecycle()
MyScaffold(R.string.work_profile, onNavigateUp, 0.dp) {
if(VERSION.SDK_INT >= 30 && !privilege.org) {
FunctionItem(R.string.org_owned_work_profile, icon = R.drawable.corporate_fare_fill0) { onNavigate(OrganizationOwnedProfile) }
@@ -90,7 +91,6 @@ fun WorkProfileScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
@Composable
fun CreateWorkProfileScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { }
MyScaffold(R.string.create_work_profile, onNavigateUp) {
@@ -133,7 +133,7 @@ fun CreateWorkProfileScreen(onNavigateUp: () -> Unit) {
try {
val intent = Intent(ACTION_PROVISION_MANAGED_PROFILE)
if(VERSION.SDK_INT >= 23) {
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,receiver)
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, MyAdminComponent)
} else {
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, context.packageName)
}
@@ -201,26 +201,24 @@ val activateOrgProfileCommand = "dpm mark-profile-owner-on-organization-owned-de
@Composable
fun SuspendPersonalAppScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var suspend by remember { mutableStateOf(dpm.getPersonalAppsSuspendedReasons(receiver) != PERSONAL_APPS_NOT_SUSPENDED) }
var suspend by remember { mutableStateOf(Privilege.DPM.getPersonalAppsSuspendedReasons(Privilege.DAR) != PERSONAL_APPS_NOT_SUSPENDED) }
MyScaffold(R.string.suspend_personal_app, onNavigateUp) {
SwitchItem(R.string.suspend_personal_app, state = suspend,
onCheckedChange = {
dpm.setPersonalAppsSuspended(receiver,it)
suspend = dpm.getPersonalAppsSuspendedReasons(receiver) != PERSONAL_APPS_NOT_SUSPENDED
Privilege.DPM.setPersonalAppsSuspended(Privilege.DAR, it)
suspend = Privilege.DPM.getPersonalAppsSuspendedReasons(Privilege.DAR) != PERSONAL_APPS_NOT_SUSPENDED
}, padding = false
)
var time by remember { mutableStateOf("") }
time = dpm.getManagedProfileMaximumTimeOff(receiver).toString()
time = Privilege.DPM.getManagedProfileMaximumTimeOff(Privilege.DAR).toString()
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.profile_max_time_off), style = typography.titleLarge)
Text(text = stringResource(R.string.profile_max_time_out_desc))
Text(
text = stringResource(
R.string.personal_app_suspended_because_timeout,
dpm.getPersonalAppsSuspendedReasons(receiver) == PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT
Privilege.DPM.getPersonalAppsSuspendedReasons(Privilege.DAR) == PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT
)
)
OutlinedTextField(
@@ -232,7 +230,7 @@ fun SuspendPersonalAppScreen(onNavigateUp: () -> Unit) {
Text(text = stringResource(R.string.cannot_less_than_72_hours))
Button(
onClick = {
dpm.setManagedProfileMaximumTimeOff(receiver,time.toLong())
Privilege.DPM.setManagedProfileMaximumTimeOff(Privilege.DAR, time.toLong())
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -248,8 +246,6 @@ fun SuspendPersonalAppScreen(onNavigateUp: () -> Unit) {
@Composable
fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
MyScaffold(R.string.intent_filter, onNavigateUp) {
var action by remember { mutableStateOf("") }
@@ -263,7 +259,7 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
dpm.addCrossProfileIntentFilter(receiver, IntentFilter(action), FLAG_PARENT_CAN_ACCESS_MANAGED)
Privilege.DPM.addCrossProfileIntentFilter(Privilege.DAR, IntentFilter(action), FLAG_PARENT_CAN_ACCESS_MANAGED)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -272,7 +268,7 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
}
Button(
onClick = {
dpm.addCrossProfileIntentFilter(receiver, IntentFilter(action), FLAG_MANAGED_CAN_ACCESS_PARENT)
Privilege.DPM.addCrossProfileIntentFilter(Privilege.DAR, IntentFilter(action), FLAG_MANAGED_CAN_ACCESS_PARENT)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -282,7 +278,7 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
Spacer(Modifier.padding(vertical = 2.dp))
Button(
onClick = {
dpm.clearCrossProfileIntentFilters(receiver)
Privilege.DPM.clearCrossProfileIntentFilters(Privilege.DAR)
context.showOperationResultToast(true)
},
modifier = Modifier.fillMaxWidth()
@@ -297,8 +293,6 @@ fun CrossProfileIntentFilterScreen(onNavigateUp: () -> Unit) {
@Composable
fun DeleteWorkProfileScreen(onNavigateUp: () -> Unit) {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
var flag by remember { mutableIntStateOf(0) }
var warning by remember { mutableStateOf(false) }
@@ -342,9 +336,9 @@ fun DeleteWorkProfileScreen(onNavigateUp: () -> Unit) {
TextButton(
onClick = {
if(VERSION.SDK_INT >= 28 && !silent) {
dpm.wipeData(flag, reason)
Privilege.DPM.wipeData(flag, reason)
} else {
dpm.wipeData(flag)
Privilege.DPM.wipeData(flag)
}
},
colors = ButtonDefaults.textButtonColors(contentColor = colorScheme.error)