From d3e36e445b60e1333e1a55948c17f70449117c10 Mon Sep 17 00:00:00 2001 From: BinTianqi <1220958406@qq.com> Date: Fri, 9 Feb 2024 17:05:45 +0800 Subject: [PATCH] massive work profile features --- Readme.md | 1 - app/src/main/AndroidManifest.xml | 4 +- .../binbin/androidowner/ApplicationManage.kt | 81 +++++++ .../com/binbin/androidowner/MainActivity.kt | 14 +- .../com/binbin/androidowner/ManagedProfile.kt | 215 +++++++++++++++--- .../java/com/binbin/androidowner/Password.kt | 6 +- .../com/binbin/androidowner/Permissions.kt | 9 +- .../com/binbin/androidowner/UserRestrict.kt | 6 +- 8 files changed, 284 insertions(+), 52 deletions(-) diff --git a/Readme.md b/Readme.md index d9d690a..e3d44e9 100644 --- a/Readme.md +++ b/Readme.md @@ -58,7 +58,6 @@ ### 即将加入的功能 -- Managed Profile,工作资料和多用户相关 - ~~应用管理:安装/卸载应用~~(暂不考虑) - 应用管理:包选择器(目前只能手动输入包名) - 应用管理:应用权限选择器 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f4e968e..933dcf7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,7 +3,6 @@ xmlns:tools="http://schemas.android.com/tools"> - @@ -16,6 +15,7 @@ + + diff --git a/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt b/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt index 874920f..5a5873b 100644 --- a/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt +++ b/app/src/main/java/com/binbin/androidowner/ApplicationManage.kt @@ -36,11 +36,13 @@ 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.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat.startActivity import java.util.concurrent.Executors private var credentialList = mutableSetOf() +private var crossProfilePkg = mutableSetOf() @Composable fun ApplicationManage(){ val myContext = LocalContext.current @@ -75,6 +77,9 @@ fun ApplicationManage(){ keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}) ) } + if(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){ + Text(text = "作用域: 工作资料", style = bodyTextStyle, textAlign = TextAlign.Center,modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)) + } if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){ AppManageItem( R.string.suspend,R.string.place_holder, @@ -242,6 +247,82 @@ fun ApplicationManage(){ } } + if(VERSION.SDK_INT>=30&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){ + Column(modifier = sections()){ + Text(text = "跨资料应用", style = typography.titleLarge) + var list by remember{mutableStateOf("")} + val refresh = { + crossProfilePkg = myDpm.getCrossProfilePackages(myComponent) + list = "" + var count = crossProfilePkg.size + for(each in crossProfilePkg){ count-=1; list+=each; if(count>0){list+="\n"} } + } + var inited by remember{mutableStateOf(false)} + if(!inited){refresh();inited=true} + Text(text = if(list!=""){list}else{"无"}, style = bodyTextStyle) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ + Button( + onClick = { + if(pkgName!=""){crossProfilePkg.add(pkgName)} + myDpm.setCrossProfilePackages(myComponent, crossProfilePkg) + refresh() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ) { + Text("添加") + } + Button( + onClick = { + if(pkgName!=""){crossProfilePkg.remove(pkgName)} + myDpm.setCrossProfilePackages(myComponent, crossProfilePkg) + refresh() + }, + modifier = Modifier.fillMaxWidth(0.96F) + ) { + Text("移除") + } + } + } + } + + if(isProfileOwner(myDpm)){ + Column(modifier = sections()){ + var pkgList: MutableList + var list by remember{mutableStateOf("")} + val refresh = { + pkgList = myDpm.getCrossProfileWidgetProviders(myComponent) + list = "" + var count = pkgList.size + for(each in pkgList){ count-=1; list+=each; if(count>0){list+="\n"}} + } + var inited by remember{mutableStateOf(false)} + if(!inited){refresh();inited=true} + Text(text = "跨资料微件", style = typography.titleLarge) + Text(text = "(跨资料桌面小部件提供者)", style = bodyTextStyle) + Text(text = if(list!=""){list}else{"无"}, style = bodyTextStyle) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ + Button( + onClick = { + if(pkgName!=""){myDpm.addCrossProfileWidgetProvider(myComponent,pkgName)} + refresh() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ){ + Text("添加") + } + Button( + onClick = { + if(pkgName!=""){myDpm.removeCrossProfileWidgetProvider(myComponent,pkgName)} + refresh() + }, + modifier = Modifier.fillMaxWidth(0.96F) + ){ + Text("移除") + } + } + } + } + if(VERSION.SDK_INT>=34&&isDeviceOwner(myDpm)){ var policy:PackagePolicy? var policyType by remember{mutableIntStateOf(-1)} diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt index 9f052ed..1bd8c7c 100644 --- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt +++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt @@ -22,9 +22,7 @@ import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.Home import androidx.compose.material3.* import androidx.compose.material3.MaterialTheme.typography -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Stable -import androidx.compose.runtime.getValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -97,6 +95,9 @@ fun MyScaffold(){ val focusMgr = LocalFocusManager.current val navCtrl = rememberNavController() val backStackEntry by navCtrl.currentBackStackEntryAsState() + val myContext = LocalContext.current + val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java) val topBarNameMap = mapOf( "HomePage" to R.string.app_name, "DeviceControl" to R.string.device_ctrl, @@ -155,6 +156,9 @@ fun MyScaffold(){ } } ) { + val profileInited = sharedPref.getBoolean("ManagedProfileActivated",false) + var inited by remember{mutableStateOf(false)} + val jumpToActivateProfile = !profileInited&&isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isManagedProfile(myComponent))) NavHost( navController = navCtrl, startDestination = "HomePage", @@ -162,7 +166,7 @@ fun MyScaffold(){ ){ composable(route = "HomePage", content = { HomePage(navCtrl)}) composable(route = "DeviceControl", content = { DeviceControl()}) - composable(route = "ManagedProfile", content = {ManagedProfile(navCtrl)}) + composable(route = "ManagedProfile", content = {ManagedProfile()}) composable(route = "Permissions", content = { DpmPermissions(navCtrl)}) composable(route = "ApplicationManage", content = { ApplicationManage()}) composable(route = "UserRestriction", content = { UserRestriction()}) @@ -170,7 +174,9 @@ fun MyScaffold(){ composable(route = "Password", content = { Password()}) composable(route = "AppSetting", content = { AppSetting(navCtrl)}) composable(route = "Network", content = {Network()}) + composable(route = "ActivateManagedProfile", content = {ActivateManagedProfile(navCtrl)}) } + if(!inited&&jumpToActivateProfile){navCtrl.navigate("ActivateManagedProfile");inited=true} } } diff --git a/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt b/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt index dee21e6..6431243 100644 --- a/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt +++ b/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt @@ -1,28 +1,30 @@ package com.binbin.androidowner import android.app.admin.DevicePolicyManager -import android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE +import android.app.admin.DevicePolicyManager.* import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.IntentFilter +import android.content.pm.PackageInstaller import android.os.Build.VERSION -import android.os.Bundle -import android.os.Parcelable import android.widget.Toast import androidx.activity.ComponentActivity -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.typography +import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.* +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalFocusManager @@ -32,7 +34,7 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController @Composable -fun ManagedProfile(navCtrl:NavHostController){ +fun ManagedProfile() { val myContext = LocalContext.current val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java) @@ -41,37 +43,67 @@ fun ManagedProfile(navCtrl:NavHostController){ val isWear = sharedPref.getBoolean("isWear",false) val bodyTextStyle = if(isWear){ typography.bodyMedium}else{ typography.bodyLarge} Column(modifier = Modifier.verticalScroll(rememberScrollState())){ + Column(modifier = sections()){ Text(text = "信息", style = typography.titleLarge) - if(VERSION.SDK_INT>=30){ - Text(text = "由组织拥有的工作资料:${myDpm.isOrganizationOwnedDeviceWithManagedProfile}", style = bodyTextStyle) - } - } - Column(modifier = sections()) { - Text(text = "工作资料", style = typography.titleLarge) if(VERSION.SDK_INT>=24){ if(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){ Text(text = "已是工作资料") }else{ Text(text = "可以创建工作资料:${myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)}", style = bodyTextStyle) + if(isDeviceOwner(myDpm)){ + Text(text = "Device owner不能创建工作资料", style = bodyTextStyle) + } } } - if(isDeviceOwner(myDpm)){ - Text(text = "Device owner不能创建工作资料", style = bodyTextStyle) + if(VERSION.SDK_INT>=30){ + Text(text = "由组织拥有的工作资料:${myDpm.isOrganizationOwnedDeviceWithManagedProfile}", style = bodyTextStyle) } - if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))){ + if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent))){ + Button( + onClick = { myContext.startActivity(Intent("com.binbin.androidowner.MAIN_ACTION")) }, modifier = Modifier.fillMaxWidth() + ){ + Text("跳转至个人应用") + } + }else{ + if(!myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)){ + Button( + onClick = { myContext.startActivity(Intent("com.binbin.androidowner.MAIN_ACTION")) }, modifier = Modifier.fillMaxWidth() + ){ + Text("跳转至工作资料") + } + } + } + } + + if(VERSION.SDK_INT>=30&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)&&!myDpm.isOrganizationOwnedDeviceWithManagedProfile){ + Column(modifier = sections(colorScheme.tertiaryContainer)){ + Text("成为组织拥有的工作资料") + Text(text = "首先在“用户管理”中查看UserID,然后使用ADB执行下面这条命令", style = bodyTextStyle) + SelectionContainer { + Text( + text = "adb shell “dpm mark-profile-owner-on-organization-owned-device --user USER_ID com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver”", + color = colorScheme.onTertiaryContainer, style = bodyTextStyle + ) + } + Text(text = "把上面命令中的USER_ID替换成你的UserID", style = bodyTextStyle) + } + } + if(!isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)))){ + Column(modifier = sections()) { + Text(text = "工作资料", style = typography.titleLarge) var skipEncrypt by remember{mutableStateOf(false)} if(VERSION.SDK_INT>=24){CheckBoxItem("跳过加密",{skipEncrypt},{skipEncrypt=!skipEncrypt})} Button( onClick = { val intent = Intent(ACTION_PROVISION_MANAGED_PROFILE) if(VERSION.SDK_INT>=23){ - intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,myComponent) + intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,myComponent) }else{ - intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,"com.binbin.androidowner") + intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,"com.binbin.androidowner") } - if(VERSION.SDK_INT>=24){intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION,skipEncrypt)} - if(VERSION.SDK_INT>=33){intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_ALLOW_OFFLINE,true)} + if(VERSION.SDK_INT>=24){intent.putExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION,skipEncrypt)} + if(VERSION.SDK_INT>=33){intent.putExtra(EXTRA_PROVISIONING_ALLOW_OFFLINE,true)} createManagedProfile.launch(intent) }, modifier = Modifier.fillMaxWidth() @@ -79,17 +111,20 @@ fun ManagedProfile(navCtrl:NavHostController){ Text("创建") } } - if(isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isManagedProfile(myComponent)))){ - Button( - onClick = { - myDpm.setProfileEnabled(myComponent) - navCtrl.navigateUp() - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() - }, - modifier = Modifier.fillMaxWidth() - ) { - Text(text = "激活") - } + } + + if(VERSION.SDK_INT>=30&&isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile){ + Row(modifier = sections(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically){ + var suspended by remember{mutableStateOf(false)} + suspended = myDpm.getPersonalAppsSuspendedReasons(myComponent)!=PERSONAL_APPS_NOT_SUSPENDED + Text(text = "挂起个人应用", style = typography.titleLarge) + Switch( + checked = suspended, + onCheckedChange ={ + myDpm.setPersonalAppsSuspended(myComponent,!suspended) + suspended = myDpm.getPersonalAppsSuspendedReasons(myComponent)!=PERSONAL_APPS_NOT_SUSPENDED + } + ) } } @@ -98,25 +133,135 @@ fun ManagedProfile(navCtrl:NavHostController){ var time by remember{mutableStateOf("")} time = myDpm.getManagedProfileMaximumTimeOff(myComponent).toString() Text(text = "资料关闭时间", style = typography.titleLarge) - Text(text = "工作资料处于关闭状态的时间达到该限制后会停用个人应用,0为无限制(单位:毫秒)", style = bodyTextStyle) + Text(text = "工作资料处于关闭状态的时间达到该限制后会挂起个人应用,0为无限制", style = bodyTextStyle) + Text(text = "个人应用已经因此挂起:${myDpm.getPersonalAppsSuspendedReasons(myComponent)==PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT}") TextField( value = time, onValueChange = {time=it}, modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp), label = {Text("时间(ms)")}, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}) ) - Text(text = "不能少于72小时") + Text(text = "不能少于72小时", style = bodyTextStyle) Button( onClick = { myDpm.setManagedProfileMaximumTimeOff(myComponent,time.toLong()) Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() - } + }, + modifier = Modifier.fillMaxWidth() ) { Text("应用") } } } + if(isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isManagedProfile(myComponent)))){ + Column(modifier = sections()){ + var action by remember{mutableStateOf("")} + Text(text = "Intent过滤器", style = typography.titleLarge) + TextField( + value = action, onValueChange = {action = it}, + label = {Text("Action")}, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), + modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp) + ) + Button( + onClick = { + myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter(action), FLAG_PARENT_CAN_ACCESS_MANAGED) + Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("添加(工作到个人)") + } + Button( + onClick = { + myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter(action), FLAG_MANAGED_CAN_ACCESS_PARENT) + Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth() + ) { + Text("添加(个人到工作)") + } + Button( + onClick = { + myDpm.clearCrossProfileIntentFilters(myComponent) + myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_MANAGED_CAN_ACCESS_PARENT) + myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_PARENT_CAN_ACCESS_MANAGED) + Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth() + ){ + Text("清除所有过滤器") + } + } + } + + if(VERSION.SDK_INT>=31&&(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent))){ + Column(modifier = sections()){ + var orgId by remember{mutableStateOf("")} + Text(text = "组织ID", style = typography.titleLarge) + TextField( + value = orgId, onValueChange = {orgId=it}, + label = {Text("组织ID")}, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done), + keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), + modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp) + ) + AnimatedVisibility(orgId.length !in 6..64) { + Text(text = "长度应在6~64个字符之间", style = bodyTextStyle) + } + Button( + onClick = { + myDpm.setOrganizationId(orgId) + Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show() + }, + enabled = orgId.length in 6..64, + modifier = Modifier.fillMaxWidth() + ){ + Text("应用") + } + Text(text = "设置组织ID后才能获取设备唯一标识码", style = bodyTextStyle) + } + } + + if(isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isManagedProfile(myComponent)))){ + Column(modifier = sections(colorScheme.tertiaryContainer)){ + Text(text = "提示", style = typography.titleLarge) + SelectionContainer { + Text( + text = "安装应用的Action是android.intent.action.INSTALL_PACKAGE,需配合android.intent.action.VIEW使用", + style = bodyTextStyle, color = colorScheme.onTertiaryContainer + ) + } + } + } + Spacer(Modifier.padding(vertical = 30.dp)) } } + +@Composable +fun ActivateManagedProfile(navCtrl: NavHostController){ + val myContext = LocalContext.current + val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java) + val sharedPref = myContext.getSharedPreferences("data", Context.MODE_PRIVATE) + myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_MANAGED_CAN_ACCESS_PARENT) + myDpm.addCrossProfileIntentFilter(myComponent, IntentFilter("com.binbin.androidowner.MAIN_ACTION"), FLAG_PARENT_CAN_ACCESS_MANAGED) + Column(modifier = Modifier.verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally){ + Text(text = "激活工作资料", style = typography.titleLarge) + Text(text = "你还没有激活工作资料,请立即激活") + Button( + onClick = { + myDpm.setProfileEnabled(myComponent) + navCtrl.popBackStack("HomePage",false) + sharedPref.edit().putBoolean("ManagedProfileActivated",true).apply() + Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() + }, + modifier = Modifier.fillMaxWidth().padding(8.dp) + ) { + Text("激活") + } + } +} diff --git a/app/src/main/java/com/binbin/androidowner/Password.kt b/app/src/main/java/com/binbin/androidowner/Password.kt index 106a468..f57db9e 100644 --- a/app/src/main/java/com/binbin/androidowner/Password.kt +++ b/app/src/main/java/com/binbin/androidowner/Password.kt @@ -99,7 +99,7 @@ fun Password(){ }else{ Toast.makeText(myContext, "清除失败", Toast.LENGTH_SHORT).show() } }, modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.32F)}, - enabled = isDeviceOwner(myDpm) + enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm) ) { Text("清除") } @@ -116,7 +116,7 @@ fun Password(){ Toast.makeText(myContext, "失败(安全异常)", Toast.LENGTH_SHORT).show() } }, - enabled = isDeviceOwner(myDpm), + enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm), modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.47F)} ) { Text("设置") @@ -129,7 +129,7 @@ fun Password(){ }catch(e:NullPointerException){ Toast.makeText(myContext, "请先设置令牌", Toast.LENGTH_SHORT).show() } }else{ Toast.makeText(myContext, "已经激活", Toast.LENGTH_SHORT).show() } }, - enabled = isDeviceOwner(myDpm), + enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm), modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.88F)} ) { Text("激活") diff --git a/app/src/main/java/com/binbin/androidowner/Permissions.kt b/app/src/main/java/com/binbin/androidowner/Permissions.kt index 74b6dea..7c602cf 100644 --- a/app/src/main/java/com/binbin/androidowner/Permissions.kt +++ b/app/src/main/java/com/binbin/androidowner/Permissions.kt @@ -28,7 +28,6 @@ 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.compose.ui.unit.sp import androidx.core.content.ContextCompat.startActivity @@ -223,12 +222,9 @@ fun DpmPermissions(navCtrl:NavHostController){ Text(text = "设备唯一标识码", style = typography.titleLarge,color = titleColor) Text("(恢复出厂设置不变)",style=bodyTextStyle) if(specificId!=""){ - Text(specificId) - Button(onClick = {myDpm.setOrganizationId(specificId)}) { - Text("设置为组织ID") - } + SelectionContainer{ Text(specificId, style = bodyTextStyle) } }else{ - Text("你的设备不支持",style=bodyTextStyle) + Text("需要设置组织ID",style=bodyTextStyle) } } } @@ -249,6 +245,7 @@ fun DpmPermissions(navCtrl:NavHostController){ ) Button( onClick = { + focusManager.clearFocus() myDpm.setOrganizationName(myComponent,orgName) Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() }, diff --git a/app/src/main/java/com/binbin/androidowner/UserRestrict.kt b/app/src/main/java/com/binbin/androidowner/UserRestrict.kt index 1c7e422..3007479 100644 --- a/app/src/main/java/com/binbin/androidowner/UserRestrict.kt +++ b/app/src/main/java/com/binbin/androidowner/UserRestrict.kt @@ -43,6 +43,7 @@ private data class Restriction( fun UserRestriction(){ val myContext = LocalContext.current val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager + val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java) var internetVisible by remember{ mutableStateOf(false) } var connectivityVisible by remember{ mutableStateOf(false) } var applicationVisible by remember{ mutableStateOf(false) } @@ -53,13 +54,16 @@ fun UserRestriction(){ val isWear = sharedPref.getBoolean("isWear",false) val bodyTextStyle = if(isWear){typography.bodyMedium}else{typography.bodyLarge} Column(modifier = Modifier.verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally){ - Text(text = "打开开关后会禁用对应的功能",modifier = Modifier.padding(3.dp), style = bodyTextStyle) + Text(text = "打开开关后会禁用对应的功能",style = bodyTextStyle) if(VERSION.SDK_INT<24){ Text(text = "所有的用户限制都需要API24,你的设备低于API24,无法使用。", style = bodyTextStyle, color = colorScheme.error) } if(isProfileOwner(myDpm)){ Text(text = "Profile owner无法使用部分功能", style = bodyTextStyle) } + if(isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isManagedProfile(myComponent)))){ + Text(text = "工作资料中部分功能无效", style = bodyTextStyle) + } if(isWear){ Text(text = "部分功能在手表上无效", style = typography.bodyMedium) }