Files
OwnDroid/app/src/main/java/com/bintianqi/owndroid/dpm/Permissions.kt
BinTianqi 21d3924801 edit proguard rules, keep IDevicePolicyManager
support getting device admin permission from Dhizuku
2024-07-21 18:14:56 +08:00

725 lines
32 KiB
Kotlin

package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint
import android.app.admin.DevicePolicyManager
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build.VERSION
import android.os.RemoteException
import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.R
import com.bintianqi.owndroid.Receiver
import com.bintianqi.owndroid.backToHomeStateFlow
import com.bintianqi.owndroid.ui.*
import com.rosan.dhizuku.api.Dhizuku
import com.rosan.dhizuku.api.DhizukuRequestPermissionListener
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Composable
fun DpmPermissions(navCtrl:NavHostController) {
val localNavCtrl = rememberNavController()
val backStackEntry by localNavCtrl.currentBackStackEntryAsState()
val scrollState = rememberScrollState()
Scaffold(
topBar = {
TopBar(backStackEntry,navCtrl,localNavCtrl) {
if(backStackEntry?.destination?.route=="Home"&&scrollState.maxValue>80) {
Text(
text = stringResource(R.string.permission),
modifier = Modifier.alpha((maxOf(scrollState.value-30,0)).toFloat()/80)
)
}
}
}
) {
NavHost(
navController = localNavCtrl, startDestination = "Home",
enterTransition = Animations.navHostEnterTransition,
exitTransition = Animations.navHostExitTransition,
popEnterTransition = Animations.navHostPopEnterTransition,
popExitTransition = Animations.navHostPopExitTransition,
modifier = Modifier.padding(top = it.calculateTopPadding())
) {
composable(route = "Home") { Home(localNavCtrl,scrollState) }
composable(route = "Shizuku") { ShizukuActivate() }
composable(route = "DeviceAdmin") { DeviceAdmin() }
composable(route = "ProfileOwner") { ProfileOwner() }
composable(route = "DeviceOwner") { DeviceOwner() }
composable(route = "DeviceInfo") { DeviceInfo() }
composable(route = "OrgID") { OrgID() }
composable(route = "SpecificID") { SpecificID() }
composable(route = "OrgName") { OrgName() }
composable(route = "DisableAccountManagement") { DisableAccountManagement() }
composable(route = "LockScreenInfo") { LockScreenInfo() }
composable(route = "SupportMsg") { SupportMsg() }
composable(route = "TransformOwnership") { TransformOwnership() }
}
}
}
@Composable
private fun Home(localNavCtrl:NavHostController,listScrollState:ScrollState) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
var dhizukuStatus by remember { mutableStateOf(sharedPref.getBoolean("dhizuku", false)) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(listScrollState)) {
Text(
text = stringResource(R.string.permission),
style = typography.headlineLarge,
modifier = Modifier.padding(top = 8.dp, bottom = 5.dp, start = 15.dp)
)
if(!dpm.isDeviceOwnerApp(context.packageName)) {
SwitchItem(
R.string.dhizuku, "", null,
{ dhizukuStatus },
{
toggleDhizukuMode(it, context)
dhizukuStatus = sharedPref.getBoolean("dhizuku", false)
}
)
}
SubPageItem(
R.string.device_admin, stringResource(if(context.isDeviceAdmin) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceAdmin") }
)
if(!context.isDeviceOwner) {
SubPageItem(
R.string.profile_owner, stringResource(if(context.isProfileOwner) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("ProfileOwner") }
)
}
if(!context.isProfileOwner) {
SubPageItem(
R.string.device_owner, stringResource(if(context.isDeviceOwner) R.string.activated else R.string.deactivated),
operation = { localNavCtrl.navigate("DeviceOwner") }
)
}
SubPageItem(R.string.shizuku,"") { localNavCtrl.navigate("Shizuku") }
SubPageItem(R.string.device_info, "", R.drawable.perm_device_information_fill0) { localNavCtrl.navigate("DeviceInfo") }
if((VERSION.SDK_INT >= 26 && context.isDeviceOwner) || (VERSION.SDK_INT>=24 && context.isProfileOwner)) {
SubPageItem(R.string.org_name, "", R.drawable.corporate_fare_fill0) { localNavCtrl.navigate("OrgName") }
}
if(VERSION.SDK_INT >= 31 && (context.isProfileOwner || context.isDeviceOwner)) {
SubPageItem(R.string.org_id, "", R.drawable.corporate_fare_fill0) { localNavCtrl.navigate("OrgID") }
SubPageItem(R.string.enrollment_specific_id, "", R.drawable.id_card_fill0) { localNavCtrl.navigate("SpecificID") }
}
if(context.isDeviceOwner || context.isProfileOwner) {
SubPageItem(R.string.disable_account_management, "", R.drawable.account_circle_fill0) { localNavCtrl.navigate("DisableAccountManagement") }
}
if(VERSION.SDK_INT >= 24 && (context.isDeviceOwner || dpm.isOrgProfile(receiver))) {
SubPageItem(R.string.device_owner_lock_screen_info, "", R.drawable.screen_lock_portrait_fill0) { localNavCtrl.navigate("LockScreenInfo") }
}
if(VERSION.SDK_INT >= 24 && context.isDeviceAdmin) {
SubPageItem(R.string.support_msg, "", R.drawable.chat_fill0) { localNavCtrl.navigate("SupportMsg") }
}
if(VERSION.SDK_INT >= 28 && (context.isDeviceOwner || context.isProfileOwner)) {
SubPageItem(R.string.transfer_ownership, "", R.drawable.admin_panel_settings_fill0) { localNavCtrl.navigate("TransformOwnership") }
}
Spacer(Modifier.padding(vertical = 30.dp))
}
}
private fun toggleDhizukuMode(status: Boolean, context: Context) {
val sharedPref = context.getSharedPreferences("data", Context.MODE_PRIVATE)
if(!status) {
sharedPref.edit().putBoolean("dhizuku", false).apply()
backToHomeStateFlow.value = true
return
}
if(!Dhizuku.init(context)) {
dhizukuErrorStatus.value = 1
return
}
if(Dhizuku.isPermissionGranted()) {
sharedPref.edit().putBoolean("dhizuku", true).apply()
backToHomeStateFlow.value = true
} else {
Dhizuku.requestPermission(object: DhizukuRequestPermissionListener() {
@Throws(RemoteException::class)
override fun onRequestPermission(grantResult: Int) {
if(grantResult == PackageManager.PERMISSION_GRANTED) {
sharedPref.edit().putBoolean("dhizuku", true).apply()
backToHomeStateFlow.value = true
} else {
dhizukuErrorStatus.value = 2
}
}
})
}
}
@SuppressLint("NewApi")
@Composable
private fun LockScreenInfo() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var infoText by remember { mutableStateOf(dpm.deviceOwnerLockScreenInfo?.toString() ?: "") }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Text(text = stringResource(R.string.device_owner_lock_screen_info), style = typography.headlineLarge)
OutlinedTextField(
value = infoText,
label = { Text(stringResource(R.string.device_owner_lock_screen_info)) },
onValueChange = { infoText = it },
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
)
Button(
onClick = {
focusMgr.clearFocus()
dpm.setDeviceOwnerLockScreenInfo(receiver,infoText)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = stringResource(R.string.apply))
}
Button(
onClick = {
focusMgr.clearFocus()
dpm.setDeviceOwnerLockScreenInfo(receiver,null)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = stringResource(R.string.reset))
}
}
}
@Composable
private fun DeviceAdmin() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var showDeactivateButton by remember { mutableStateOf(context.isDeviceAdmin) }
var deactivateDialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.device_admin), style = typography.headlineLarge)
Text(text = stringResource(if(context.isDeviceAdmin) R.string.activated else R.string.deactivated), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(showDeactivateButton) {
Button(
onClick = { deactivateDialog = true },
enabled = !context.isProfileOwner && !context.isDeviceOwner,
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError)
) {
Text(stringResource(R.string.deactivate))
}
}
AnimatedVisibility(!showDeactivateButton) {
Column {
Button(onClick = {activateDeviceAdmin(context, receiver) }, modifier = Modifier.fillMaxWidth()) {
Text(stringResource(R.string.activate_jump))
}
Spacer(Modifier.padding(vertical = 5.dp))
SelectionContainer {
Text(text = stringResource(R.string.activate_device_admin_command))
}
CopyTextButton(R.string.copy_command, stringResource(R.string.activate_device_admin_command))
}
}
}
if(deactivateDialog) {
val co = rememberCoroutineScope()
AlertDialog(
title = { Text(stringResource(R.string.deactivate)) },
onDismissRequest = { deactivateDialog = false },
dismissButton = {
TextButton(
onClick = { deactivateDialog = false }
) {
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = {
dpm.removeActiveAdmin(receiver)
co.launch{
delay(300)
deactivateDialog = false
showDeactivateButton = context.isDeviceAdmin
backToHomeStateFlow.value = !context.isDeviceAdmin
}
}
) {
Text(stringResource(R.string.confirm))
}
}
)
}
}
@Composable
private fun ProfileOwner() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
var showDeactivateButton by remember { mutableStateOf(context.isProfileOwner) }
var deactivateDialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.profile_owner), style = typography.headlineLarge)
Text(stringResource(if(context.isProfileOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT >= 24) {
AnimatedVisibility(showDeactivateButton) {
Button(
onClick = { deactivateDialog = true },
enabled = !dpm.isManagedProfile(receiver),
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError)
) {
Text(stringResource(R.string.deactivate))
}
}
}
AnimatedVisibility(!showDeactivateButton) {
Column {
SelectionContainer{
Text(text = stringResource(R.string.activate_profile_owner_command))
}
CopyTextButton(R.string.copy_command, stringResource(R.string.activate_profile_owner_command))
}
}
}
if(deactivateDialog && VERSION.SDK_INT >= 24) {
val co = rememberCoroutineScope()
AlertDialog(
title = { Text(stringResource(R.string.deactivate)) },
onDismissRequest = { deactivateDialog = false },
dismissButton = {
TextButton(
onClick = { deactivateDialog = false }
) {
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = {
dpm.clearProfileOwner(receiver)
co.launch{
delay(300)
deactivateDialog = false
showDeactivateButton = context.isProfileOwner
backToHomeStateFlow.value = !context.isProfileOwner
}
}
) {
Text(stringResource(R.string.confirm))
}
}
)
}
}
@Composable
private fun DeviceOwner() {
val context = LocalContext.current
val dpm = context.getDPM()
var showDeactivateButton by remember { mutableStateOf(context.isDeviceOwner) }
var deactivateDialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.device_owner), style = typography.headlineLarge)
Text(text = stringResource(if(context.isDeviceOwner) R.string.activated else R.string.deactivated), style = typography.titleLarge)
Spacer(Modifier.padding(vertical = 5.dp))
AnimatedVisibility(showDeactivateButton) {
Button(
onClick = { deactivateDialog = true },
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError)
) {
Text(text = stringResource(R.string.deactivate))
}
}
AnimatedVisibility(!showDeactivateButton) {
Column {
SelectionContainer{
Text(text = stringResource(R.string.activate_device_owner_command))
}
CopyTextButton(R.string.copy_command, stringResource(R.string.activate_device_owner_command))
}
}
}
if(deactivateDialog) {
val co = rememberCoroutineScope()
AlertDialog(
title = { Text(stringResource(R.string.deactivate)) },
onDismissRequest = { deactivateDialog = false },
dismissButton = {
TextButton(
onClick = { deactivateDialog = false }
) {
Text(stringResource(R.string.cancel))
}
},
confirmButton = {
TextButton(
onClick = {
dpm.clearDeviceOwnerApp(context.dpcPackageName)
co.launch{
delay(300)
deactivateDialog = false
showDeactivateButton = context.isDeviceOwner
backToHomeStateFlow.value = !context.isDeviceOwner
}
}
) {
Text(stringResource(R.string.confirm))
}
}
)
}
}
@Composable
fun DeviceInfo() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.device_info), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(VERSION.SDK_INT>=34 && (context.isDeviceOwner || dpm.isOrgProfile(receiver))) {
val financed = dpm.isDeviceFinanced
Text(stringResource(R.string.is_device_financed, financed))
}
Spacer(Modifier.padding(vertical = 2.dp))
if(VERSION.SDK_INT >= 33) {
val dpmRole = dpm.devicePolicyManagementRoleHolderPackage
Text(stringResource(R.string.dpmrh, if(dpmRole == null) stringResource(R.string.none) else ""))
if(dpmRole!=null) {
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState())) {
Text(text = dpmRole)
}
}
}
Spacer(Modifier.padding(vertical = 2.dp))
val encryptionStatus = mutableMapOf(
DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE to stringResource(R.string.es_inactive),
DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE to stringResource(R.string.es_active),
DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED to stringResource(R.string.es_unsupported)
)
if(VERSION.SDK_INT >= 23) { encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY] = stringResource(R.string.es_active_default_key) }
if(VERSION.SDK_INT >= 24) { encryptionStatus[DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER] = stringResource(R.string.es_active_per_user) }
Text(stringResource(R.string.encrypt_status_is)+encryptionStatus[dpm.storageEncryptionStatus])
Spacer(Modifier.padding(vertical = 2.dp))
if(VERSION.SDK_INT >= 28) {
Text(stringResource(R.string.support_device_id_attestation) + dpm.isDeviceIdAttestationSupported)
}
Spacer(Modifier.padding(vertical = 2.dp))
if (VERSION.SDK_INT >= 30) {
Text(stringResource(R.string.support_unique_device_attestation) + dpm.isUniqueDeviceAttestationSupported)
}
Spacer(Modifier.padding(vertical = 2.dp))
val adminList = dpm.activeAdmins
if(adminList!=null) {
var adminListText = ""
Text(text = stringResource(R.string.activated_device_admin, adminList.size))
var count = adminList.size
for(each in adminList) {
count -= 1
adminListText += "${each.packageName}/${each.className}"
if(count>0) {adminListText += "\n"}
}
SelectionContainer(modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp).horizontalScroll(rememberScrollState())) {
Text(text = adminListText)
}
}
}
}
@SuppressLint("NewApi")
@Composable
private fun OrgID() {
val context = LocalContext.current
val dpm = context.getDPM()
val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().padding(horizontal = 8.dp).verticalScroll(rememberScrollState())) {
var orgId by remember { mutableStateOf("") }
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.org_id), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = orgId, onValueChange = {orgId=it},
label = { Text(stringResource(R.string.org_id)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 2.dp))
AnimatedVisibility(orgId.length !in 6..64) {
Text(text = stringResource(R.string.length_6_to_64))
}
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
dpm.setOrganizationId(orgId)
Toast.makeText(context, R.string.success,Toast.LENGTH_SHORT).show()
},
enabled = orgId.length in 6..64,
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 5.dp))
Information{ Text(text = stringResource(R.string.get_specific_id_after_set_org_id)) }
}
}
@SuppressLint("NewApi")
@Composable
private fun SpecificID() {
val context = LocalContext.current
val dpm = context.getDPM()
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
val specificId = dpm.enrollmentSpecificId
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.enrollment_specific_id), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
if(specificId != "") {
SelectionContainer(modifier = Modifier.horizontalScroll(rememberScrollState())) { Text(specificId) }
CopyTextButton(R.string.copy, specificId)
}else{
Text(stringResource(R.string.require_set_org_id))
}
}
}
@SuppressLint("NewApi")
@Composable
private fun OrgName() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
var orgName by remember { mutableStateOf(try{dpm.getOrganizationName(receiver).toString() }catch(e:SecurityException) {""}) }
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.org_name), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = orgName, onValueChange = { orgName = it }, modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp),
label = { Text(stringResource(R.string.org_name)) },
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() })
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
focusMgr.clearFocus()
dpm.setOrganizationName(receiver,orgName)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.apply))
}
}
}
@SuppressLint("NewApi")
@Composable
private fun SupportMsg() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
var shortMsg by remember { mutableStateOf(dpm.getShortSupportMessage(receiver)?.toString() ?: "") }
var longMsg by remember { mutableStateOf(dpm.getLongSupportMessage(receiver)?.toString() ?: "") }
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.support_msg), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = shortMsg,
label = { Text(stringResource(R.string.short_support_msg)) },
onValueChange = { shortMsg = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 2.dp))
OutlinedTextField(
value = longMsg,
label = { Text(stringResource(R.string.long_support_msg)) },
onValueChange = { longMsg = it },
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
focusMgr.clearFocus()
dpm.setShortSupportMessage(receiver, shortMsg)
dpm.setLongSupportMessage(receiver, longMsg)
shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: ""
longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: ""
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = stringResource(R.string.apply))
}
Spacer(Modifier.padding(vertical = 1.dp))
Button(
onClick = {
focusMgr.clearFocus()
dpm.setShortSupportMessage(receiver, null)
dpm.setLongSupportMessage(receiver, null)
shortMsg = dpm.getShortSupportMessage(receiver)?.toString() ?: ""
longMsg = dpm.getLongSupportMessage(receiver)?.toString() ?: ""
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = stringResource(R.string.reset))
}
Spacer(Modifier.padding(vertical = 5.dp))
Information{ Text(text = stringResource(R.string.support_msg_desc)) }
Spacer(Modifier.padding(vertical = 30.dp))
}
}
@Composable
private fun DisableAccountManagement() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.disable_account_management), style = typography.headlineLarge)
Text(stringResource(R.string.unknown_effect))
var accountList by remember{ mutableStateOf("") }
val refreshList = {
val noManageAccount = dpm.accountTypesWithManagementDisabled
accountList = ""
if (noManageAccount != null) {
var count = noManageAccount.size
for(each in noManageAccount) { count -= 1; accountList += each; if(count>0) { accountList += "\n" } }
}
}
var inited by remember { mutableStateOf(false) }
if(!inited) { refreshList(); inited=true }
Spacer(Modifier.padding(vertical = 5.dp))
Text(text = if(accountList=="") stringResource(R.string.none) else accountList)
var inputText by remember{ mutableStateOf("") }
OutlinedTextField(
value = inputText,
onValueChange = { inputText = it },
label = { Text(stringResource(R.string.account_types_are)) },
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() })
)
Button(
onClick={
dpm.setAccountManagementDisabled(receiver, inputText, true)
refreshList()
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.add))
}
Button(
onClick={
dpm.setAccountManagementDisabled(receiver, inputText, false)
refreshList()
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.remove))
}
}
}
@SuppressLint("NewApi")
@Composable
private fun TransformOwnership() {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current
val focusRequester = FocusRequester()
Column(modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(horizontal = 8.dp)) {
var pkg by remember { mutableStateOf("") }
var cls by remember { mutableStateOf("") }
Spacer(Modifier.padding(vertical = 10.dp))
Text(text = stringResource(R.string.transfer_ownership), style = typography.headlineLarge)
Spacer(Modifier.padding(vertical = 5.dp))
Text(text = stringResource(R.string.transfer_ownership_desc))
Spacer(Modifier.padding(vertical = 5.dp))
OutlinedTextField(
value = pkg, onValueChange = { pkg = it }, label = { Text(stringResource(R.string.target_package_name)) },
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
keyboardActions = KeyboardActions(onNext = { focusRequester.requestFocus() })
)
Spacer(Modifier.padding(vertical = 2.dp))
OutlinedTextField(
value = cls, onValueChange = {cls = it }, label = { Text(stringResource(R.string.target_class_name)) },
modifier = Modifier.focusRequester(focusRequester).fillMaxWidth(),
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() })
)
Spacer(Modifier.padding(vertical = 5.dp))
Button(
onClick = {
try {
dpm.transferOwnership(receiver,ComponentName(pkg, cls),null)
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
}catch(e:IllegalArgumentException) {
Toast.makeText(context, R.string.failed, Toast.LENGTH_SHORT).show()
}
},
modifier = Modifier.fillMaxWidth()
) {
Text(stringResource(R.string.transfer))
}
Spacer(Modifier.padding(vertical = 30.dp))
}
}
private fun activateDeviceAdmin(inputContext:Context,inputComponent:ComponentName) {
try {
val intent = Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, inputComponent)
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, inputContext.getString(R.string.activate_device_admin_here))
addDeviceAdmin.launch(intent)
}catch(e:ActivityNotFoundException) {
Toast.makeText(inputContext, R.string.unsupported, Toast.LENGTH_SHORT).show()
}
}