From 6f54bf576fc5326c7c9801c57d5ffc3a8fcdc578 Mon Sep 17 00:00:00 2001 From: BinTianqi Date: Fri, 29 Aug 2025 20:58:39 +0800 Subject: [PATCH] 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. --- app/src/main/AndroidManifest.xml | 1 + .../com/bintianqi/owndroid/ApiReceiver.kt | 37 ++-- .../owndroid/AppInstallerActivity.kt | 3 +- .../java/com/bintianqi/owndroid/AppLock.kt | 7 +- .../com/bintianqi/owndroid/DhizukuServer.kt | 15 +- .../com/bintianqi/owndroid/MainActivity.kt | 48 ++-- .../bintianqi/owndroid/ManageSpaceActivity.kt | 2 +- .../com/bintianqi/owndroid/MyApplication.kt | 18 ++ .../com/bintianqi/owndroid/MyViewModel.kt | 20 +- .../java/com/bintianqi/owndroid/Privilege.kt | 87 +++++--- .../java/com/bintianqi/owndroid/Receiver.kt | 10 +- .../java/com/bintianqi/owndroid/Settings.kt | 41 ++-- .../owndroid/ShortcutsReceiverActivity.kt | 20 +- .../bintianqi/owndroid/dpm/Applications.kt | 143 +++++------- .../java/com/bintianqi/owndroid/dpm/DPM.kt | 96 ++------ .../com/bintianqi/owndroid/dpm/Network.kt | 104 ++++----- .../com/bintianqi/owndroid/dpm/Password.kt | 78 +++---- .../com/bintianqi/owndroid/dpm/Permissions.kt | 124 +++++------ .../java/com/bintianqi/owndroid/dpm/System.kt | 207 ++++++++---------- .../bintianqi/owndroid/dpm/UserRestriction.kt | 20 +- .../java/com/bintianqi/owndroid/dpm/Users.kt | 66 +++--- .../com/bintianqi/owndroid/dpm/WorkProfile.kt | 36 ++- 22 files changed, 496 insertions(+), 687 deletions(-) create mode 100644 app/src/main/java/com/bintianqi/owndroid/MyApplication.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 23877a5..f71f941 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,6 +24,7 @@ android:enableOnBackInvokedCallback="true" android:testOnly="false" android:manageSpaceActivity=".ManageSpaceActivity" + android:name=".MyApplication" tools:targetApi="35"> 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 diff --git a/app/src/main/java/com/bintianqi/owndroid/AppInstallerActivity.kt b/app/src/main/java/com/bintianqi/owndroid/AppInstallerActivity.kt index 91824a9..f37be6c 100644 --- a/app/src/main/java/com/bintianqi/owndroid/AppInstallerActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/AppInstallerActivity.kt @@ -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 ) diff --git a/app/src/main/java/com/bintianqi/owndroid/AppLock.kt b/app/src/main/java/com/bintianqi/owndroid/AppLock.kt index f5ab51e..d3c0052 100644 --- a/app/src/main/java/com/bintianqi/owndroid/AppLock.kt +++ b/app/src/main/java/com/bintianqi/owndroid/AppLock.kt @@ -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) } diff --git a/app/src/main/java/com/bintianqi/owndroid/DhizukuServer.kt b/app/src/main/java/com/bintianqi/owndroid/DhizukuServer.kt index b196238..488a19f 100644 --- a/app/src/main/java/com/bintianqi/owndroid/DhizukuServer.kt +++ b/app/src/main/java/com/bintianqi/owndroid/DhizukuServer.kt @@ -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 diff --git a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt index 521f6dd..53ee8f6 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MainActivity.kt @@ -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() - 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 { 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 { 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 { SettingsOptionsScreen(::navigateUp) } composable { val theme by vm.theme.collectAsStateWithLifecycle() - AppearanceScreen(::navigateUp, theme) { vm.theme.value = it } + AppearanceScreen(::navigateUp, theme, vm::changeTheme) } composable { AppLockSettingsScreen(::navigateUp) } composable { ApiSettings(::navigateUp) } @@ -459,11 +445,10 @@ fun Home(vm: MyViewModel, onLock: () -> Unit) { composable { 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 { 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) diff --git a/app/src/main/java/com/bintianqi/owndroid/ManageSpaceActivity.kt b/app/src/main/java/com/bintianqi/owndroid/ManageSpaceActivity.kt index 2027a6d..db671b9 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ManageSpaceActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ManageSpaceActivity.kt @@ -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 { diff --git a/app/src/main/java/com/bintianqi/owndroid/MyApplication.kt b/app/src/main/java/com/bintianqi/owndroid/MyApplication.kt new file mode 100644 index 0000000..9372942 --- /dev/null +++ b/app/src/main/java/com/bintianqi/owndroid/MyApplication.kt @@ -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 diff --git a/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt b/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt index 6b639a6..db9be42 100644 --- a/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt +++ b/app/src/main/java/com/bintianqi/owndroid/MyViewModel.kt @@ -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 } } diff --git a/app/src/main/java/com/bintianqi/owndroid/Privilege.kt b/app/src/main/java/com/bintianqi/owndroid/Privilege.kt index 8b19866..242a16d 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Privilege.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Privilege.kt @@ -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 - ) -} - diff --git a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt index 016feeb..e7b88d9 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Receiver.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Receiver.kt @@ -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 diff --git a/app/src/main/java/com/bintianqi/owndroid/Settings.kt b/app/src/main/java/com/bintianqi/owndroid/Settings.kt index 23abe1b..6eb883b 100644 --- a/app/src/main/java/com/bintianqi/owndroid/Settings.kt +++ b/app/src/main/java/com/bintianqi/owndroid/Settings.kt @@ -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) } } } diff --git a/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt b/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt index e234201..b8dee4a 100644 --- a/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt +++ b/app/src/main/java/com/bintianqi/owndroid/ShortcutsReceiverActivity.kt @@ -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)) diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt index d976ddb..d898059 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Applications.kt @@ -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() } 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() } 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() } 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() } 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(null) } val statusMap = remember { mutableStateMapOf() } 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() } 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() } 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() } 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() } 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() } 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() } 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() } 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 diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt index 914cbd0..a934e9f 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/DPM.kt @@ -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{ @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) -} diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt index 875d0fd..965ffa1 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Network.kt @@ -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() } 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 { @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() } 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() } 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(), diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt index 01c78dd..42d0e78 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Password.kt @@ -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) } diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt index b377f8d..fb4c6cf 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt @@ -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() } 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>() } fun refresh() { val list = mutableMapOf>() 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) { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt index 53b43ff..635957b 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/System.kt @@ -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() } 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(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() } 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 diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt index 14505f2..8527a26 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/UserRestriction.kt @@ -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) { 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() } 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() } 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() diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt index 2d8ccab..88689fa 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/Users.kt @@ -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() } 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() }) { diff --git a/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt b/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt index 545623a..1fac984 100644 --- a/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt +++ b/app/src/main/java/com/bintianqi/owndroid/dpm/WorkProfile.kt @@ -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)