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)
}