diff --git a/Guide.md b/Guide.md index 38f6191..1874a79 100644 --- a/Guide.md +++ b/Guide.md @@ -374,10 +374,14 @@ MTE: Memory Tagging Extension(内存标记拓展)[安卓开发者:MTE](htt - WipeData - WipeDevice(需要API34或以上,需要Device owner或由组织拥有的工作资料的Profile owner) -如果在受管理用户中使用,会清除那个用户的数据 +恢复出厂原因:需要API28或以上,只有WipeData能用 + +如果在受管理用户中使用,会清除那个用户的数据并跳转到主用户 如果在工作资料中使用,会删除工作资料 +API34或以上将不能在系统用户中使用WipeData,如果要恢复出厂设置,请使用WipeDevice + ## 网络 这个页面需要API24或以上才能进入 @@ -541,6 +545,12 @@ dpm mark-profile-owner-on-organization-owned-device --user USER_ID com.binbin.an 设置组织ID后才能在“权限”页面查看设备唯一标识码,不同的组织ID会有不同的设备唯一标识码 +### 删除工作资料 + +你可以使用 [恢复出厂设置](#恢复出厂设置) 来删除工作资料 + +如果你的工作资料不是由组织拥有的,你可以打开安卓设置->安全->更多安全设置->设备管理器->带工作资料图标的Android owner->移除工作资料(非原生用户自己找) + ## 应用管理 如果是工作资料,只能管理工作资料中的应用 @@ -723,7 +733,7 @@ Profile owner无法禁用部分功能,工作资料中部分功能无效,wear ### 媒体 - (28) 调整亮度 -- (28) 修改屏幕超时(仍可以在密码与锁屏中设置[屏幕超时](#屏幕超时)) +- (28) 修改屏幕超时(仍可以在密码与锁屏中设置[屏幕超时](#最大屏幕超时时间)) - (28) 息屏显示 (AMOLED) - 调整音量 - 取消麦克风静音 @@ -732,7 +742,7 @@ Profile owner无法禁用部分功能,工作资料中部分功能无效,wear ### 用户 -- 添加用户(仍可以在用户管理中[创建用户](#创建用户)) +- 添加用户(仍可以在用户管理中[创建用户](#创建并管理用户)) - 移除用户(仍可以在用户管理中[移除用户](#用户操作)) - (28) 切换用户 - (24) 修改用户头像 @@ -846,7 +856,7 @@ UserID:不是UID。系统用户的UserID为0,其他用户(包括工作资 选项: -- 开机时不要求输入密码(**危险!**一旦设置,只能通过恢复出厂设置来取消) +- 开机时不要求输入密码( **危险!** 一旦设置,只能通过恢复出厂设置来取消) - 不允许其他设备管理员重置密码直至用户输入一次密码 方法: diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c771b3b..ffea19d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -58,7 +58,7 @@ dependencies { implementation(platform("androidx.compose:compose-bom:2023.08.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") - implementation("androidx.compose.ui:ui-tooling-preview") + debugImplementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.material3:material3:1.1.2") implementation("androidx.navigation:navigation-compose:2.7.6") testImplementation("junit:junit:4.13.2") diff --git a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt index f652bb7..3e50038 100644 --- a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt +++ b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt @@ -6,6 +6,7 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.os.Build.VERSION +import android.os.UserManager import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity @@ -41,6 +42,7 @@ fun DeviceControl(){ val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java) val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) val isWear = sharedPref.getBoolean("isWear",false) + val userManager = myContext.getSystemService(Context.USER_SERVICE) as UserManager val bodyTextStyle = if(isWear){typography.bodyMedium}else{typography.bodyLarge} val focusMgr = LocalFocusManager.current Column(modifier = Modifier.verticalScroll(rememberScrollState()).navigationBarsPadding()) { @@ -467,7 +469,7 @@ fun DeviceControl(){ } } - if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){ + if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||(VERSION.SDK_INT>=30&&isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile))){ Column(modifier = sections()){ Text(text = "收集安全日志", style = typography.titleLarge) Text(text = "功能开发中", style = bodyTextStyle) @@ -504,18 +506,36 @@ fun DeviceControl(){ Column(modifier = sections(if(isSystemInDarkTheme()){ colorScheme.errorContainer }else{ colorScheme.errorContainer.copy(alpha = 0.6F) })) { var flag by remember{ mutableIntStateOf(0) } var confirmed by remember{ mutableStateOf(false) } + var externalStorage by remember{mutableStateOf(false)} + var protectionData by remember{mutableStateOf(false)} + var euicc by remember{mutableStateOf(false)} + var silent by remember{mutableStateOf(false)} + var reason by remember{mutableStateOf("")} Text(text = "清除数据",style = typography.titleLarge,modifier = Modifier.padding(6.dp),color = colorScheme.onErrorContainer) - RadioButtonItem("默认",{flag==0},{flag=0}, colorScheme.onErrorContainer) - RadioButtonItem("清除外部存储",{flag==WIPE_EXTERNAL_STORAGE},{flag=WIPE_EXTERNAL_STORAGE}, colorScheme.onErrorContainer) + CheckBoxItem("清除外部存储",{externalStorage},{externalStorage=!externalStorage}, colorScheme.onErrorContainer) if(VERSION.SDK_INT>=22&&isDeviceOwner(myDpm)){ - RadioButtonItem("清除受保护的数据",{flag==WIPE_RESET_PROTECTION_DATA},{flag=WIPE_RESET_PROTECTION_DATA}, colorScheme.onErrorContainer) + CheckBoxItem("清除受保护的数据",{protectionData},{protectionData=!protectionData}, colorScheme.onErrorContainer) + } + if(VERSION.SDK_INT>=28){ CheckBoxItem("清除eUICC",{euicc},{euicc=!euicc}, colorScheme.onErrorContainer) } + if(VERSION.SDK_INT>=29){ CheckBoxItem("静默清除",{silent},{silent=!silent}, colorScheme.onErrorContainer) } + AnimatedVisibility(!silent&&VERSION.SDK_INT>=28) { + TextField( + value = reason, onValueChange = {reason=it}, + label = {Text("原因")}, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), + modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp) + ) } - if(VERSION.SDK_INT>=28){ RadioButtonItem("清除eUICC",{flag==WIPE_EUICC},{flag=WIPE_EUICC}, colorScheme.onErrorContainer) } - if(VERSION.SDK_INT>=29){ RadioButtonItem("WIPE_SILENTLY",{flag==WIPE_SILENTLY},{flag=WIPE_SILENTLY}, colorScheme.onErrorContainer) } - Text(text = "清空数据的不能是系统用户",color = colorScheme.onErrorContainer, - style = if(!sharedPref.getBoolean("isWear",false)){typography.bodyLarge}else{typography.bodyMedium}) Button( - onClick = {confirmed=!confirmed}, + onClick = { + flag = 0 + if(externalStorage){flag += WIPE_EXTERNAL_STORAGE} + if(protectionData&&VERSION.SDK_INT>=22){flag += WIPE_RESET_PROTECTION_DATA} + if(euicc&&VERSION.SDK_INT>=28){flag += WIPE_EUICC} + if(silent&&VERSION.SDK_INT>=29){flag += WIPE_SILENTLY} + confirmed=!confirmed + }, colors = ButtonDefaults.buttonColors( containerColor = if(confirmed){ colorScheme.primary }else{ colorScheme.error }, contentColor = if(confirmed){ colorScheme.onPrimary }else{ colorScheme.onError } @@ -527,23 +547,20 @@ fun DeviceControl(){ } Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween) { Button( - onClick = {myDpm.wipeData(flag)}, - colors = ButtonDefaults.buttonColors( - containerColor = colorScheme.error, - contentColor = colorScheme.onError - ), - enabled = confirmed, - modifier = Modifier.fillMaxWidth(if(VERSION.SDK_INT>=34){0.49F}else{1F}) + onClick = { + if(VERSION.SDK_INT>=28){myDpm.wipeData(flag,reason)} + else{myDpm.wipeData(flag)} + }, + colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError), + enabled = confirmed&&(VERSION.SDK_INT<34||(VERSION.SDK_INT>=34&&!userManager.isSystemUser)), + modifier = Modifier.fillMaxWidth(if(VERSION.SDK_INT >= 34&&(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile))){0.49F}else{1F}) ) { Text("WipeData") } - if (VERSION.SDK_INT >= 34) { + if (VERSION.SDK_INT >= 34&&(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile))) { Button( onClick = {myDpm.wipeDevice(flag)}, - colors = ButtonDefaults.buttonColors( - containerColor = colorScheme.error, - contentColor = colorScheme.onError - ), + colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError), enabled = confirmed, modifier = Modifier.fillMaxWidth(0.96F) ) { @@ -552,8 +569,9 @@ fun DeviceControl(){ } } if(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){ - Text("将会删除工作资料") + Text(text = "将会删除工作资料", style = bodyTextStyle) } + Text(text = "API34或以上将不能在系统用户中使用WipeData", style = bodyTextStyle) } Spacer(Modifier.padding(vertical = 30.dp)) } diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt index 607823f..6e2a124 100644 --- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt +++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt @@ -171,7 +171,7 @@ fun MyScaffold(){ composable(route = "Permissions", content = { DpmPermissions(navCtrl)}) composable(route = "ApplicationManage", content = { ApplicationManage()}) composable(route = "UserRestriction", content = { UserRestriction()}) - composable(route = "UserManage", content = { UserManage(navCtrl)}) + composable(route = "UserManage", content = { UserManage()}) composable(route = "Password", content = { Password()}) composable(route = "AppSetting", content = { AppSetting(navCtrl)}) composable(route = "Network", content = {Network()}) diff --git a/app/src/main/java/com/binbin/androidowner/Password.kt b/app/src/main/java/com/binbin/androidowner/Password.kt index e32fc9b..aa31047 100644 --- a/app/src/main/java/com/binbin/androidowner/Password.kt +++ b/app/src/main/java/com/binbin/androidowner/Password.kt @@ -167,7 +167,7 @@ fun Password(){ }else{ Toast.makeText(myContext, "需要4位密码", Toast.LENGTH_SHORT).show() } }, enabled = isDeviceOwner(myDpm) || isProfileOwner(myDpm) || myDpm.isAdminActive(myComponent), - modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.3F)}, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( containerColor = if(confirmed){ colorScheme.primary }else{ colorScheme.error }, contentColor = if(confirmed){ colorScheme.onPrimary }else{ colorScheme.onError } @@ -185,7 +185,7 @@ fun Password(){ }, colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError), enabled = confirmed&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm)), - modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.42F)} + modifier = Modifier.fillMaxWidth() ) { Text("使用令牌重置密码") } @@ -199,7 +199,7 @@ fun Password(){ }, enabled = confirmed, colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError), - modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.9F)} + modifier = Modifier.fillMaxWidth() ) { Text("重置密码(弃用)") } diff --git a/app/src/main/java/com/binbin/androidowner/Permissions.kt b/app/src/main/java/com/binbin/androidowner/Permissions.kt index 0930166..be2ed10 100644 --- a/app/src/main/java/com/binbin/androidowner/Permissions.kt +++ b/app/src/main/java/com/binbin/androidowner/Permissions.kt @@ -309,10 +309,12 @@ fun DpmPermissions(navCtrl:NavHostController){ } } } - - if((isDeviceOwner(myDpm)||isProfileOwner(myDpm))&&VERSION.SDK_INT>=24){ + + if(VERSION.SDK_INT>=24&&isDeviceOwner(myDpm)){ DeviceOwnerInfo(R.string.owner_lockscr_info,R.string.place_holder,R.string.owner_lockscr_info,focusManager,myContext, {myDpm.deviceOwnerLockScreenInfo},{content -> myDpm.setDeviceOwnerLockScreenInfo(myComponent,content)}) + } + if((isDeviceOwner(myDpm)||isProfileOwner(myDpm))&&VERSION.SDK_INT>=24){ DeviceOwnerInfo(R.string.support_msg,R.string.support_msg_desc,R.string.message,focusManager,myContext, {myDpm.getShortSupportMessage(myComponent)},{content -> myDpm.setShortSupportMessage(myComponent,content)}) DeviceOwnerInfo(R.string.long_support_msg,R.string.long_support_msg_desc,R.string.message,focusManager,myContext, diff --git a/app/src/main/java/com/binbin/androidowner/Receiver.kt b/app/src/main/java/com/binbin/androidowner/Receiver.kt index ba7aa5e..8ae7aa4 100644 --- a/app/src/main/java/com/binbin/androidowner/Receiver.kt +++ b/app/src/main/java/com/binbin/androidowner/Receiver.kt @@ -18,11 +18,20 @@ class MyDeviceAdminReceiver : DeviceAdminReceiver() { @SuppressLint("UnsafeProtectedBroadcastReceiver") override fun onReceive(context: Context, intent: Intent) { super.onReceive(context, intent) - if(VERSION.SDK_INT>=26){ - DeviceAdminReceiver().onNetworkLogsAvailable(context,intent,1234567890,20) - DeviceAdminReceiver().onSecurityLogsAvailable(context,intent) - } } + + override fun onNetworkLogsAvailable(context: Context, intent: Intent, batchToken: Long, networkLogsCount: Int) { + super.onNetworkLogsAvailable(context, intent, batchToken, networkLogsCount) + Toast.makeText(context,"可以收集网络日志",Toast.LENGTH_SHORT).show() + Log.e("","网络日志可用") + } + + override fun onSecurityLogsAvailable(context: Context, intent: Intent) { + super.onSecurityLogsAvailable(context, intent) + Toast.makeText(context,"可以收集安全日志",Toast.LENGTH_SHORT).show() + Log.e("","安全日志可用") + } + override fun onDisableRequested(context: Context, intent: Intent): CharSequence { Toast.makeText(context, "撤销授权", Toast.LENGTH_SHORT).show() return "这是取消时的提示" diff --git a/app/src/main/java/com/binbin/androidowner/Setting.kt b/app/src/main/java/com/binbin/androidowner/Setting.kt index fc6787c..5b92c07 100644 --- a/app/src/main/java/com/binbin/androidowner/Setting.kt +++ b/app/src/main/java/com/binbin/androidowner/Setting.kt @@ -5,16 +5,11 @@ import android.content.Intent import android.net.Uri import android.os.Build.VERSION import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.Switch import androidx.compose.material3.Text @@ -23,10 +18,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController @Composable @@ -65,7 +57,7 @@ fun AppSetting(navCtrl:NavHostController){ Column( modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 12.dp) ) { - Text(text = "关于", style = typography.headlineSmall, color = MaterialTheme.colorScheme.onPrimaryContainer) + Text(text = "关于", style = typography.headlineSmall, color = colorScheme.onPrimaryContainer) Text(text = "使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备", style = bodyTextStyle) Spacer(Modifier.padding(vertical = 4.dp)) Text(text = "这个应用只在AOSP和LineageOS上测试过,不确保每个功能都在其它系统可用,尤其是国内的魔改系统。", style = bodyTextStyle) @@ -74,6 +66,21 @@ fun AppSetting(navCtrl:NavHostController){ Spacer(Modifier.padding(vertical = 2.dp)) Text(text = "安卓版本越高,支持的功能越多", style = bodyTextStyle) } + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .fillMaxWidth() + .clickable { shareLink(myContext, "https://github.com/BinTianqi/AndroidOwner/Guide.md") } + .padding(start = 8.dp, bottom = 4.dp) + ){ + Icon( + painter = painterResource(id = R.drawable.open_in_new), + contentDescription = null, + modifier = Modifier.padding(start = 6.dp, end = 10.dp), + tint = colorScheme.primary + ) + Text(text = "使用教程", style = typography.titleLarge, color = colorScheme.onPrimaryContainer, modifier = Modifier.padding(bottom = 2.dp)) + } Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier @@ -85,15 +92,9 @@ fun AppSetting(navCtrl:NavHostController){ painter = painterResource(id = R.drawable.open_in_new), contentDescription = null, modifier = Modifier.padding(start = 6.dp, end = 10.dp), - tint = MaterialTheme.colorScheme.primary + tint = colorScheme.primary ) - Column { - Text(text = "源代码", fontSize = 18.sp, fontWeight = FontWeight.SemiBold) - if(!isWear){ - Text(text = "https://github.com/BinTianqi/AndroidOwner", color = MaterialTheme.colorScheme.onPrimaryContainer) - Text(text = "欢迎提交issue、给小星星") - } - } + Text(text = "源代码", style = typography.titleLarge, color = colorScheme.onPrimaryContainer, modifier = Modifier.padding(bottom = 2.dp)) } } Spacer(Modifier.padding(vertical = 30.dp)) diff --git a/app/src/main/java/com/binbin/androidowner/User.kt b/app/src/main/java/com/binbin/androidowner/User.kt index 001dac3..4d1517b 100644 --- a/app/src/main/java/com/binbin/androidowner/User.kt +++ b/app/src/main/java/com/binbin/androidowner/User.kt @@ -3,7 +3,6 @@ package com.binbin.androidowner import android.app.admin.DevicePolicyManager import android.content.ComponentName import android.content.Context -import android.content.Intent import android.os.Build.VERSION import android.os.UserHandle import android.os.UserManager @@ -32,10 +31,10 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.core.os.UserManagerCompat -import androidx.navigation.NavHostController +var affiliationID = mutableSetOf() @Composable -fun UserManage(navCtrl:NavHostController){ +fun UserManage() { Column( modifier = Modifier.verticalScroll(rememberScrollState()) ) { @@ -237,6 +236,61 @@ fun UserManage(navCtrl:NavHostController){ if(newUserHandle!=null){ Text(text = "新用户的序列号:${userManager.getSerialNumberForUser(newUserHandle)}", style = bodyTextStyle) } } } + if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){ + Column(modifier = sections()){ + var input by remember{mutableStateOf("")} + var list by remember{mutableStateOf("")} + val refresh = { + list = "" + var count = affiliationID.size + for(item in affiliationID){ count-=1; list+=item; if(count>0){list+="\n"} } + } + var inited by remember{mutableStateOf(false)} + if(!inited){affiliationID = myDpm.getAffiliationIds(myComponent);refresh();inited=true} + Text(text = "附属用户ID", style = typography.titleLarge) + TextField( + value = input, + onValueChange = {input = it}, + label = {Text("ID")}, + modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp), + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}) + ) + Text(text = if(list==""){"无"}else{list}, style = bodyTextStyle) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ + Button( + onClick = { affiliationID.add(input); refresh() }, + modifier = Modifier.fillMaxWidth(0.49F) + ){ + Text("添加") + } + Button( + onClick = { affiliationID.remove(input); refresh() }, + modifier = Modifier.fillMaxWidth(0.96F) + ){ + Text("移除") + } + } + Button( + onClick = { + if("" in affiliationID) { + Toast.makeText(myContext, "有空字符串", Toast.LENGTH_SHORT).show() + }else if(affiliationID.isEmpty()){ + Toast.makeText(myContext, "不能为空", Toast.LENGTH_SHORT).show() + }else{ + myDpm.setAffiliationIds(myComponent, affiliationID) + affiliationID = myDpm.getAffiliationIds(myComponent) + refresh() + Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + } + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("应用") + } + } + } + UserSessionMessage("用户名","用户名",true,myDpm,myContext,{null},{msg -> myDpm.setProfileName(myComponent, msg.toString())}) if(VERSION.SDK_INT>=28){ UserSessionMessage("用户会话开始消息","消息",false,myDpm,myContext,{myDpm.getStartUserSessionMessage(myComponent)},{msg -> myDpm.setStartUserSessionMessage(myComponent,msg)}) @@ -312,17 +366,6 @@ private fun userOperationResultCode(result:Int): String { } } -private fun createWorkProfile(myContext: Context) { - val intent = Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE) - if(VERSION.SDK_INT>=23){ - intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, ComponentName(myContext,MyDeviceAdminReceiver::class.java)) - } - intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, myContext.packageName) - if (VERSION.SDK_INT >= 33) { intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_ALLOW_OFFLINE,true) } - intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,"hello") - myContext.startActivity(intent) -} - fun getCurrentUserId(): Int { try { val uh = UserHandle::class.java.getDeclaredMethod("myUserId")