mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
support transform ownership
This commit is contained in:
86
Guide.md
86
Guide.md
@@ -166,6 +166,16 @@ adb shell dpm remove-active-admin com.binbin.androidowner/com.binbin.androidowne
|
|||||||
|
|
||||||
提供支持的长消息不知道有啥用
|
提供支持的长消息不知道有啥用
|
||||||
|
|
||||||
|
### 转移所有权
|
||||||
|
|
||||||
|
需要Device owner或Profile owner
|
||||||
|
|
||||||
|
需要API28或以上
|
||||||
|
|
||||||
|
转移设备所有权到另外一个Device owner或Profile owner
|
||||||
|
|
||||||
|
目标应用必须是Device admin且支持被转移所有权
|
||||||
|
|
||||||
## 系统
|
## 系统
|
||||||
|
|
||||||
### 禁用相机
|
### 禁用相机
|
||||||
@@ -450,7 +460,7 @@ API34或以上将不能在系统用户中使用WipeData,如果要恢复出厂
|
|||||||
|
|
||||||
### 网络日志记录
|
### 网络日志记录
|
||||||
|
|
||||||
需要的权限:Device owner或Profile owner
|
需要的权限:Device owner或工作资料的Profile owner
|
||||||
|
|
||||||
需要API26或以上
|
需要API26或以上
|
||||||
|
|
||||||
@@ -476,22 +486,28 @@ API34或以上将不能在系统用户中使用WipeData,如果要恢复出厂
|
|||||||
|
|
||||||
## 工作资料
|
## 工作资料
|
||||||
|
|
||||||
工作资料是一种特殊的用户,使用`adb shell pm list user`命令可以看到工作资料
|
工作资料是一种特殊的用户,使用`adb shell pm list user`命令可以看到工作资料,工作资料的默认用户名是“工作资料”或“Work Profile”
|
||||||
|
|
||||||
### 创建工作资料
|
### 创建工作资料
|
||||||
|
|
||||||
设备上不能有Device owner或Profile owner
|
设备上不能有Device owner或Profile owner
|
||||||
|
|
||||||
只能有一个工作资料
|
一个设备只能有一个工作资料
|
||||||
|
|
||||||
选项:
|
选项:
|
||||||
|
|
||||||
- 跳过加密(需要API24或以上,没啥用)
|
- 跳过加密(需要API24或以上,没有实际作用)
|
||||||
|
|
||||||
创建后会跳转到工作资料中的Android owner,请立即按照指引激活工作资料
|
创建后会跳转到工作资料中的Android owner,请立即按照指引激活工作资料
|
||||||
|
|
||||||
创建后工作资料中的Android owner会成为Profile owner
|
创建后工作资料中的Android owner会成为Profile owner
|
||||||
|
|
||||||
|
在WearOS上创建工作资料会导致SystemUI停止运行一次。WearOS原生的启动器不支持工作资料,你需要使用第三方启动器(比如微软桌面)。你可以通过[ADB命令移除工作资料](#删除工作资料)
|
||||||
|
|
||||||
|
此外,不要作死给工作资料重置密码,不然你连输入密码的地方都没有
|
||||||
|
|
||||||
|
(只在原生WearOS4(AVD)上测试过)
|
||||||
|
|
||||||
### 由组织拥有的工作资料
|
### 由组织拥有的工作资料
|
||||||
|
|
||||||
需要API30或以上
|
需要API30或以上
|
||||||
@@ -527,8 +543,6 @@ dpm mark-profile-owner-on-organization-owned-device --user USER_ID com.binbin.an
|
|||||||
|
|
||||||
### 跨资料Intent过滤器
|
### 跨资料Intent过滤器
|
||||||
|
|
||||||
[安卓开发者:Intent](https://developer.android.google.cn/reference/kotlin/android/content/Intent)
|
|
||||||
|
|
||||||
需要的权限:工作资料的Profile owner
|
需要的权限:工作资料的Profile owner
|
||||||
|
|
||||||
默认情况下,工作资料中的应用不能打开个人应用,个人应用也不可以打开工作资料中的应用
|
默认情况下,工作资料中的应用不能打开个人应用,个人应用也不可以打开工作资料中的应用
|
||||||
@@ -551,6 +565,12 @@ dpm mark-profile-owner-on-organization-owned-device --user USER_ID com.binbin.an
|
|||||||
|
|
||||||
如果你的工作资料不是由组织拥有的,你可以打开安卓设置->安全->更多安全设置->设备管理器->带工作资料图标的Android owner->移除工作资料(非原生用户自己找)
|
如果你的工作资料不是由组织拥有的,你可以打开安卓设置->安全->更多安全设置->设备管理器->带工作资料图标的Android owner->移除工作资料(非原生用户自己找)
|
||||||
|
|
||||||
|
你也可以使用ADB命令移除工作资料(把USER_ID替换为工作资料的UserID)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
adb shell pm remove-user USER_ID
|
||||||
|
```
|
||||||
|
|
||||||
## 应用管理
|
## 应用管理
|
||||||
|
|
||||||
如果是工作资料,只能管理工作资料中的应用
|
如果是工作资料,只能管理工作资料中的应用
|
||||||
@@ -770,19 +790,33 @@ Profile owner无法禁用部分功能,工作资料中部分功能无效,wear
|
|||||||
|
|
||||||
## 用户管理
|
## 用户管理
|
||||||
|
|
||||||
|
用户(user)不是账号(account)
|
||||||
|
|
||||||
|
使用ADB查看所有用户:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
adb shell pm list users
|
||||||
|
```
|
||||||
|
|
||||||
|
用户名前面的数字就是UserID
|
||||||
|
|
||||||
### 用户信息
|
### 用户信息
|
||||||
|
|
||||||
当前用户的信息
|
用户已解锁:你能看到这个的时候一定解锁了
|
||||||
|
|
||||||
|
支持多用户:系统是否支持多用户。WearOS即使写着支持多用户,但不一定支持
|
||||||
|
|
||||||
系统用户:UserID为0的用户(需API23)
|
系统用户:UserID为0的用户(需API23)
|
||||||
|
|
||||||
|
管理员用户:可以创建、删除用户。一个设备可以有多个管理员用户(需API34)
|
||||||
|
|
||||||
无头系统用户:~~头被砍掉了~~ 系统用户运行着系统服务,但是没有分配给任何人使用,也不能切换到系统用户(需API31)
|
无头系统用户:~~头被砍掉了~~ 系统用户运行着系统服务,但是没有分配给任何人使用,也不能切换到系统用户(需API31)
|
||||||
|
|
||||||
可以登出:用户限制->[用户](#用户)->切换用户(需API28)
|
可以登出:功能未知,无论什么用户都不能登出
|
||||||
|
|
||||||
临时用户:临时用户登出后会被删除(需API28)
|
临时用户:临时用户登出后或重启后会被删除(需API28)
|
||||||
|
|
||||||
附属用户:运行Device owner的用户是附属于设备的用户,受管理用户可以设置附属用户ID以成为附属用户(开发中)
|
附属用户:详见[附属用户ID](#附属用户ID)
|
||||||
|
|
||||||
UserID:不是UID。系统用户的UserID为0,其他用户(包括工作资料)的UserID从10开始计算
|
UserID:不是UID。系统用户的UserID为0,其他用户(包括工作资料)的UserID从10开始计算
|
||||||
|
|
||||||
@@ -798,7 +832,7 @@ UserID:不是UID。系统用户的UserID为0,其他用户(包括工作资
|
|||||||
|
|
||||||
### 创建并管理用户
|
### 创建并管理用户
|
||||||
|
|
||||||
创建一个受管理用户
|
创建一个受管理用户,新用户的头像右下方会有公文包标志
|
||||||
|
|
||||||
需要Device owner和API24
|
需要Device owner和API24
|
||||||
|
|
||||||
@@ -808,6 +842,36 @@ UserID:不是UID。系统用户的UserID为0,其他用户(包括工作资
|
|||||||
- 临时用户(需API28)
|
- 临时用户(需API28)
|
||||||
- 启用所有系统应用(有些系统应用在新用户中是默认不启用的,比如谷歌手机上的YouTube)
|
- 启用所有系统应用(有些系统应用在新用户中是默认不启用的,比如谷歌手机上的YouTube)
|
||||||
|
|
||||||
|
创建后,Android owner会成为受管理用户中的Profile owner
|
||||||
|
|
||||||
|
这个功能在WearOS上使用会导致SystemUI停止运行一次,过几秒恢复正常。创建用户实际上成功了,回到Android owner后能看到新用户的序列号,`pm list users`也能看到新用户。如果切换到新用户,SystemUI无法使用,表现为黑屏(可以用ADB命令启动别的应用)。如果黑屏无法使用,ADB执行下面这个命令(把USER_ID替换成受管理用户的用户序列号)
|
||||||
|
|
||||||
|
```shell
|
||||||
|
adb shell pm remove-user --set-ephemeral-if-in-use USER_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
新用户会被设为临时用户,重启后临时用户会被删除并切换到主用户
|
||||||
|
|
||||||
|
(原生WearOS4(AVD)会出现这个问题,其他版本不知道有没有这个问题)
|
||||||
|
|
||||||
|
### 使用Intent创建用户
|
||||||
|
|
||||||
|
不需要任何权限,但也没啥用,建议Device owner创建并管理用户
|
||||||
|
|
||||||
|
可能会导致Android owner停止运行,但是停止运行后没log,所以不知道为什么无法创建
|
||||||
|
|
||||||
|
### 附属用户ID
|
||||||
|
|
||||||
|
需要Device owner或Profile owner(工作资料中的Profile owner虽然也能设置,但是没有实际作用)
|
||||||
|
|
||||||
|
附属用户ID是一个列表,列表中可以有多个不相同的ID,不考虑顺序
|
||||||
|
|
||||||
|
当Device owner创建并管理用户时,新的用户不是附属用户。Device owner设置和受管理用户完全相同的附属用户ID后,受管理用户成为附属于Device owner的用户
|
||||||
|
|
||||||
|
Device owner无论在何时都是附属于设备的用户
|
||||||
|
|
||||||
|
你可以在用户管理->[用户信息](#用户信息)查看当前用户是否附属用户
|
||||||
|
|
||||||
### 用户名
|
### 用户名
|
||||||
|
|
||||||
修改当前用户的用户名
|
修改当前用户的用户名
|
||||||
|
|||||||
@@ -522,6 +522,7 @@ fun DeviceControl(){
|
|||||||
TextField(
|
TextField(
|
||||||
value = reason, onValueChange = {reason=it},
|
value = reason, onValueChange = {reason=it},
|
||||||
label = {Text("原因")},
|
label = {Text("原因")},
|
||||||
|
enabled = !confirmed,
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
||||||
@@ -529,6 +530,7 @@ fun DeviceControl(){
|
|||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
focusMgr.clearFocus()
|
||||||
flag = 0
|
flag = 0
|
||||||
if(externalStorage){flag += WIPE_EXTERNAL_STORAGE}
|
if(externalStorage){flag += WIPE_EXTERNAL_STORAGE}
|
||||||
if(protectionData&&VERSION.SDK_INT>=22){flag += WIPE_RESET_PROTECTION_DATA}
|
if(protectionData&&VERSION.SDK_INT>=22){flag += WIPE_RESET_PROTECTION_DATA}
|
||||||
@@ -571,8 +573,10 @@ fun DeviceControl(){
|
|||||||
if(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
|
if(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
|
||||||
Text(text = "将会删除工作资料", style = bodyTextStyle)
|
Text(text = "将会删除工作资料", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
|
if(VERSION.SDK_INT>=34){
|
||||||
Text(text = "API34或以上将不能在系统用户中使用WipeData", style = bodyTextStyle)
|
Text(text = "API34或以上将不能在系统用户中使用WipeData", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Spacer(Modifier.padding(vertical = 30.dp))
|
Spacer(Modifier.padding(vertical = 30.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,16 +71,15 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
createUser = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
createUser = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
when(it.resultCode){
|
when(it.resultCode){
|
||||||
UserManager.USER_CREATION_FAILED_NO_MORE_USERS->Toast.makeText(applicationContext, "用户太多了", Toast.LENGTH_SHORT).show()
|
Activity.RESULT_OK->Toast.makeText(applicationContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
Activity.RESULT_CANCELED->Toast.makeText(applicationContext, "用户太多了", Toast.LENGTH_SHORT).show()
|
||||||
UserManager.USER_CREATION_FAILED_NOT_PERMITTED->Toast.makeText(applicationContext, "不是管理员用户", Toast.LENGTH_SHORT).show()
|
UserManager.USER_CREATION_FAILED_NOT_PERMITTED->Toast.makeText(applicationContext, "不是管理员用户", Toast.LENGTH_SHORT).show()
|
||||||
else->Toast.makeText(applicationContext, "成功", Toast.LENGTH_SHORT).show()
|
UserManager.USER_CREATION_FAILED_NO_MORE_USERS->Toast.makeText(applicationContext, "用户太多了", Toast.LENGTH_SHORT).show()
|
||||||
|
else->Toast.makeText(applicationContext, "创建用户结果未知", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createManagedProfile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
createManagedProfile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
when(it.resultCode){
|
if(it.resultCode==Activity.RESULT_CANCELED){Toast.makeText(applicationContext, "用户已取消", Toast.LENGTH_SHORT).show()}
|
||||||
Activity.RESULT_OK->Toast.makeText(applicationContext, "创建成功", Toast.LENGTH_SHORT).show()
|
|
||||||
Activity.RESULT_CANCELED->Toast.makeText(applicationContext, "用户已取消", Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
setContent {
|
setContent {
|
||||||
AndroidOwnerTheme {
|
AndroidOwnerTheme {
|
||||||
@@ -141,12 +140,8 @@ fun MyScaffold(){
|
|||||||
if(sharedPref.getBoolean("isWear",false)&&topBarName!=R.string.app_name){
|
if(sharedPref.getBoolean("isWear",false)&&topBarName!=R.string.app_name){
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
navCtrl.navigate("HomePage") {
|
|
||||||
popUpTo(
|
|
||||||
navCtrl.graph.findStartDestination().id
|
|
||||||
) { saveState = true }
|
|
||||||
}
|
|
||||||
focusMgr.clearFocus()
|
focusMgr.clearFocus()
|
||||||
|
navCtrl.navigateUp()
|
||||||
},
|
},
|
||||||
modifier = Modifier.size(35.dp),
|
modifier = Modifier.size(35.dp),
|
||||||
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
|
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ fun ManagedProfile() {
|
|||||||
Text("跳转至个人应用")
|
Text("跳转至个人应用")
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(!myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)&&!isDeviceOwner(myDpm)){
|
if(!myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)&&!isDeviceOwner(myDpm)&&!isProfileOwner(myDpm)){
|
||||||
Button(
|
Button(
|
||||||
onClick = { myContext.startActivity(Intent("com.binbin.androidowner.MAIN_ACTION")) }, modifier = Modifier.fillMaxWidth()
|
onClick = { myContext.startActivity(Intent("com.binbin.androidowner.MAIN_ACTION")) }, modifier = Modifier.fillMaxWidth()
|
||||||
){
|
){
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ fun Network(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)))){
|
||||||
Column(modifier = sections()){
|
Column(modifier = sections()){
|
||||||
Text(text = "收集网络日志", style = typography.titleLarge)
|
Text(text = "收集网络日志", style = typography.titleLarge)
|
||||||
Text(text = "功能开发中", style = bodyTextStyle)
|
Text(text = "功能开发中", style = bodyTextStyle)
|
||||||
|
|||||||
@@ -179,8 +179,8 @@ fun Password(){
|
|||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
val resetSuccess = myDpm.resetPasswordWithToken(myComponent,newPwd,myByteArray,resetPwdFlag)
|
val resetSuccess = myDpm.resetPasswordWithToken(myComponent,newPwd,myByteArray,resetPwdFlag)
|
||||||
if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show()
|
if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show();newPwd=""}
|
||||||
}else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
|
else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
|
||||||
confirmed=false
|
confirmed=false
|
||||||
},
|
},
|
||||||
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError),
|
colors = ButtonDefaults.buttonColors(containerColor = colorScheme.error, contentColor = colorScheme.onError),
|
||||||
@@ -193,8 +193,8 @@ fun Password(){
|
|||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
val resetSuccess = myDpm.resetPassword(newPwd,resetPwdFlag)
|
val resetSuccess = myDpm.resetPassword(newPwd,resetPwdFlag)
|
||||||
if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show()
|
if(resetSuccess){ Toast.makeText(myContext, "设置成功", Toast.LENGTH_SHORT).show();newPwd=""}
|
||||||
}else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
|
else{ Toast.makeText(myContext, "设置失败", Toast.LENGTH_SHORT).show() }
|
||||||
confirmed=false
|
confirmed=false
|
||||||
},
|
},
|
||||||
enabled = confirmed,
|
enabled = confirmed,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import androidx.compose.material3.TextField
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusDirection
|
||||||
import androidx.compose.ui.focus.FocusManager
|
import androidx.compose.ui.focus.FocusManager
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
@@ -32,6 +33,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.core.content.ContextCompat.startActivity
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -320,6 +322,41 @@ fun DpmPermissions(navCtrl:NavHostController){
|
|||||||
DeviceOwnerInfo(R.string.long_support_msg,R.string.long_support_msg_desc,R.string.message,focusManager,myContext,
|
DeviceOwnerInfo(R.string.long_support_msg,R.string.long_support_msg_desc,R.string.message,focusManager,myContext,
|
||||||
{myDpm.getLongSupportMessage(myComponent)},{content -> myDpm.setLongSupportMessage(myComponent,content)})
|
{myDpm.getLongSupportMessage(myComponent)},{content -> myDpm.setLongSupportMessage(myComponent,content)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(VERSION.SDK_INT>=28&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
var pkg by remember{mutableStateOf("")}
|
||||||
|
var cls by remember{mutableStateOf("")}
|
||||||
|
Text(text = "转移所有权", style = typography.titleLarge)
|
||||||
|
Text(text = "把Device owner或Profile owner权限转移到另一个应用。目标必须是Device admin", style = bodyTextStyle)
|
||||||
|
TextField(
|
||||||
|
value = pkg, onValueChange = {pkg = it}, label = {Text("目标包名")},
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp),
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions(onNext = {focusManager.moveFocus(FocusDirection.Down)})
|
||||||
|
)
|
||||||
|
TextField(
|
||||||
|
value = cls, onValueChange = {cls = it}, label = {Text("目标类名")},
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp),
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions(onDone = {focusManager.clearFocus()})
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
try {
|
||||||
|
myDpm.transferOwnership(myComponent,ComponentName(pkg, cls),null)
|
||||||
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
}catch(e:IllegalArgumentException){
|
||||||
|
Toast.makeText(myContext, "失败", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("转移")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(isWear&&(myDpm.isAdminActive(myComponent)||isProfileOwner(myDpm)||isDeviceOwner(myDpm))){
|
if(isWear&&(myDpm.isAdminActive(myComponent)||isProfileOwner(myDpm)||isDeviceOwner(myDpm))){
|
||||||
Column(modifier = sections(), horizontalAlignment = Alignment.CenterHorizontally) {
|
Column(modifier = sections(), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
Button(
|
Button(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageInstaller.*
|
import android.content.pm.PackageInstaller.*
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
|
import android.os.PersistableBundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
||||||
@@ -15,6 +16,22 @@ class MyDeviceAdminReceiver : DeviceAdminReceiver() {
|
|||||||
super.onEnabled(context, intent)
|
super.onEnabled(context, intent)
|
||||||
Toast.makeText(context, "已启用", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "已启用", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onTransferOwnershipComplete(context: Context, bundle: PersistableBundle?) {
|
||||||
|
super.onTransferOwnershipComplete(context, bundle)
|
||||||
|
if(bundle!=null){
|
||||||
|
Toast.makeText(context,"转移控制权完毕,附加内容长度:${bundle.size()}",Toast.LENGTH_SHORT).show()
|
||||||
|
Log.d("TransferOwnerShip",bundle.toString())
|
||||||
|
}else{
|
||||||
|
Toast.makeText(context,"转移控制权完毕,无附加内容}",Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProfileProvisioningComplete(context: Context, intent: Intent) {
|
||||||
|
super.onProfileProvisioningComplete(context, intent)
|
||||||
|
Toast.makeText(context, "创建工作资料完成", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("UnsafeProtectedBroadcastReceiver")
|
@SuppressLint("UnsafeProtectedBroadcastReceiver")
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
super.onReceive(context, intent)
|
super.onReceive(context, intent)
|
||||||
|
|||||||
@@ -49,11 +49,9 @@ fun UserManage() {
|
|||||||
Column(modifier = sections()) {
|
Column(modifier = sections()) {
|
||||||
Text(text = "用户信息", style = typography.titleLarge,color = colorScheme.onPrimaryContainer)
|
Text(text = "用户信息", style = typography.titleLarge,color = colorScheme.onPrimaryContainer)
|
||||||
Text("用户已解锁:${UserManagerCompat.isUserUnlocked(myContext)}",style = bodyTextStyle)
|
Text("用户已解锁:${UserManagerCompat.isUserUnlocked(myContext)}",style = bodyTextStyle)
|
||||||
if(VERSION.SDK_INT>=24){
|
if(VERSION.SDK_INT>=24){ Text("支持多用户:${UserManager.supportsMultipleUsers()}",style = bodyTextStyle) }
|
||||||
Text("支持多用户:${UserManager.supportsMultipleUsers()}",style = bodyTextStyle)
|
if(VERSION.SDK_INT>=23){ Text(text = "系统用户:${userManager.isSystemUser}", style = bodyTextStyle) }
|
||||||
if(isWear&&UserManager.supportsMultipleUsers()){Text(text = "实际上手表可能不支持", style = typography.bodyMedium, color = colorScheme.error)}
|
if(VERSION.SDK_INT>=34){ Text(text = "管理员用户:${userManager.isAdminUser}", style = bodyTextStyle) }
|
||||||
}
|
|
||||||
if(VERSION.SDK_INT>=23){Text(text = "系统用户:${userManager.isSystemUser}")}
|
|
||||||
if(VERSION.SDK_INT>=31){ Text(text = "无头系统用户: ${UserManager.isHeadlessSystemUserMode()}",style = bodyTextStyle) }
|
if(VERSION.SDK_INT>=31){ Text(text = "无头系统用户: ${UserManager.isHeadlessSystemUserMode()}",style = bodyTextStyle) }
|
||||||
Spacer(Modifier.padding(vertical = if(isWear){2.dp}else{5.dp}))
|
Spacer(Modifier.padding(vertical = if(isWear){2.dp}else{5.dp}))
|
||||||
if (VERSION.SDK_INT >= 28) {
|
if (VERSION.SDK_INT >= 28) {
|
||||||
@@ -140,7 +138,6 @@ fun UserManage() {
|
|||||||
onClick = {
|
onClick = {
|
||||||
focusMgr.clearFocus()
|
focusMgr.clearFocus()
|
||||||
if(myDpm.switchUser(myComponent,userHandleById)){
|
if(myDpm.switchUser(myComponent,userHandleById)){
|
||||||
focusMgr.clearFocus()
|
|
||||||
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
}else{
|
}else{
|
||||||
Toast.makeText(myContext, "失败", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "失败", Toast.LENGTH_SHORT).show()
|
||||||
@@ -200,7 +197,6 @@ fun UserManage() {
|
|||||||
onValueChange = {userName=it},
|
onValueChange = {userName=it},
|
||||||
label = {Text("用户名")},
|
label = {Text("用户名")},
|
||||||
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
|
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp),
|
||||||
enabled = isDeviceOwner(myDpm),
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
|
||||||
)
|
)
|
||||||
@@ -223,6 +219,7 @@ fun UserManage() {
|
|||||||
) {
|
) {
|
||||||
Text("创建(Owner)")
|
Text("创建(Owner)")
|
||||||
}
|
}
|
||||||
|
if(UserManager.supportsMultipleUsers()&&(VERSION.SDK_INT<34||(VERSION.SDK_INT>=34&&userManager.isAdminUser))){
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
val intent = UserManager.createUserCreationIntent(userName,null,null,null)
|
val intent = UserManager.createUserCreationIntent(userName,null,null,null)
|
||||||
@@ -233,6 +230,7 @@ fun UserManage() {
|
|||||||
Text("创建(Intent)")
|
Text("创建(Intent)")
|
||||||
}
|
}
|
||||||
Text(text = "尽量用Device owner模式创建,Intent模式可能没有效果", style = bodyTextStyle)
|
Text(text = "尽量用Device owner模式创建,Intent模式可能没有效果", style = bodyTextStyle)
|
||||||
|
}
|
||||||
if(newUserHandle!=null){ Text(text = "新用户的序列号:${userManager.getSerialNumberForUser(newUserHandle)}", style = bodyTextStyle) }
|
if(newUserHandle!=null){ Text(text = "新用户的序列号:${userManager.getSerialNumberForUser(newUserHandle)}", style = bodyTextStyle) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -288,6 +286,7 @@ fun UserManage() {
|
|||||||
) {
|
) {
|
||||||
Text("应用")
|
Text("应用")
|
||||||
}
|
}
|
||||||
|
Text(text = "如果多用户,附属用户ID相同时可以让其他用户附属于主用户", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,4 +12,5 @@
|
|||||||
<set-global-proxy/>
|
<set-global-proxy/>
|
||||||
<disable-keyguard-features/>
|
<disable-keyguard-features/>
|
||||||
</uses-policies>
|
</uses-policies>
|
||||||
|
<support-transfer-ownership />
|
||||||
</device-admin>
|
</device-admin>
|
||||||
Reference in New Issue
Block a user