set keepUninstalledPkgs and userIcon

This commit is contained in:
BinTianqi
2024-02-13 18:03:59 +08:00
parent 599f6c06bb
commit 9042fa2472
10 changed files with 221 additions and 85 deletions

View File

@@ -345,9 +345,11 @@ MTE: Memory Tagging Extension内存标记拓展[安卓开发者MTE](htt
或者清除所有用户证书 或者清除所有用户证书
### 安全日志 ### 安全日志&&重启前安全日志
需要的权限Device owner 需要的权限Device owner或由组织拥有的工作资料的Profile owner
如果被Device owner使用设备上不能有非附属用户否则不会有输出
需要API24或以上 需要API24或以上
@@ -462,6 +464,10 @@ API34或以上将不能在系统用户中使用WipeData如果要恢复出厂
需要的权限Device owner或工作资料的Profile owner 需要的权限Device owner或工作资料的Profile owner
工作资料中使用此功能只会记录工作资料的网络日志
如果被Device owner使用设备上不能有非附属用户
需要API26或以上 需要API26或以上
功能开发中 功能开发中
@@ -673,7 +679,17 @@ adb shell pm list permissions
需要的权限Device owner或Profile owner 需要的权限Device owner或Profile owner
设置许可的无障碍应用和输入法 无障碍应用:强制启用无障碍应用
输入法:强制启用输入法,但是不强制用户使用输入法
### 保持卸载的应用
需要Device owner
需要API28或以上
作用未知
### 清除应用存储 ### 清除应用存储
@@ -878,6 +894,16 @@ Device owner无论在何时都是附属于设备的用户
需要Device owner或Profile owner 需要Device owner或Profile owner
### 用户图标
选择一个图片并设置为当前用户的图标
需要Device owner或Profile owner
需要API23或以上
尽量选择一个正方形的图片,分辨率不要太大,以免产生问题
### 用户会话开始/结束消息 ### 用户会话开始/结束消息
用户会话开始消息:切换到非系统用户时的消息 用户会话开始消息:切换到非系统用户时的消息
@@ -892,13 +918,13 @@ Device owner无论在何时都是附属于设备的用户
### 密码信息 ### 密码信息
当前密码复杂度:参考要求密码复杂度 当前密码复杂度:参考[密码复杂度要求](#密码复杂度要求)需要API29或以上
密码达到要求:当前密码复杂度是否达到了要求的密码复杂度 密码达到要求:当前密码复杂度是否达到了要求的密码复杂度
密码已错误次数你能看到这个数字的时候这个数字一定是0 密码已错误次数你能看到这个数字的时候这个数字一定是0
个人与工作应用密码一致需要是工作资料的Profile owner 个人与工作应用密码一致需要是工作资料的Profile owner需要API28或以上
### 密码重置令牌 ### 密码重置令牌

View File

@@ -13,9 +13,9 @@
### 缺点 ### 缺点
不支持一些功能。如果追求功能齐全,谷歌官方的 [TestDPC](https://github.com/googlesamples/android-testdpc) 可能更适合你 功能不完整。如果追求功能齐全,谷歌官方的 [TestDPC](https://github.com/googlesamples/android-testdpc) 可能更适合你
### 功能简介 ### 功能
适配了一些预见式返回动画需安卓13或14可能不太稳定如果有问题请向我反馈 适配了一些预见式返回动画需安卓13或14可能不太稳定如果有问题请向我反馈
@@ -27,12 +27,7 @@
- 用户管理 - 用户管理
- 密码与锁屏 - 密码与锁屏
所有功能的详细介绍请看 [用户指南](Guide.md) [用户指南](Guide.md)(一定要看,应用里只有功能的简单介绍)
### 这个应用十分危险!!!
在使用各个功能之前,请仔细阅读相应的说明。红色的按钮一定要谨慎使用!
如果操作不慎,可能会意外地丢失数据或者让你无法解锁你的设备!
### 正在开发的功能 ### 正在开发的功能

View File

@@ -11,8 +11,8 @@ android {
applicationId = "com.binbin.androidowner" applicationId = "com.binbin.androidowner"
minSdk = 21 minSdk = 21
targetSdk = 34 targetSdk = 34
versionCode = 14 versionCode = 15
versionName = "3.1" versionName = "3.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables { vectorDrawables {

View File

@@ -47,6 +47,9 @@ import java.util.concurrent.Executors
private var credentialList = mutableSetOf<String>() private var credentialList = mutableSetOf<String>()
private var crossProfilePkg = mutableSetOf<String>() private var crossProfilePkg = mutableSetOf<String>()
private var keepUninstallPkg = mutableListOf<String>()
private var permittedIme = mutableListOf<String>()
private var permittedAccessibility = mutableListOf<String>()
@Composable @Composable
fun ApplicationManage(){ fun ApplicationManage(){
val myContext = LocalContext.current val myContext = LocalContext.current
@@ -218,7 +221,6 @@ fun ApplicationManage(){
var inputPermission by remember{mutableStateOf("android.permission.")} var inputPermission by remember{mutableStateOf("android.permission.")}
var currentState by remember{mutableStateOf(grantState[myDpm.getPermissionGrantState(myComponent,pkgName,inputPermission)])} var currentState by remember{mutableStateOf(grantState[myDpm.getPermissionGrantState(myComponent,pkgName,inputPermission)])}
Text(text = "权限管理", style = typography.titleLarge) Text(text = "权限管理", style = typography.titleLarge)
Text(text = "查看系统支持的权限adb shell pm list permissions", style = bodyTextStyle)
OutlinedTextField( OutlinedTextField(
value = inputPermission, value = inputPermission,
label = { Text("权限")}, label = { Text("权限")},
@@ -258,6 +260,7 @@ fun ApplicationManage(){
Text("由用户决定") Text("由用户决定")
} }
Text(text ="设为允许或拒绝后,用户不能改变状态", style = bodyTextStyle) Text(text ="设为允许或拒绝后,用户不能改变状态", style = bodyTextStyle)
if(VERSION.SDK_INT>=31){Text(text = "可以修改传感器相关权限:${myDpm.canAdminGrantSensorsPermissions()}", style = bodyTextStyle)}
} }
} }
@@ -413,85 +416,140 @@ fun ApplicationManage(){
if(isProfileOwner(myDpm)||isDeviceOwner(myDpm)){ if(isProfileOwner(myDpm)||isDeviceOwner(myDpm)){
Column(modifier = sections()) { Column(modifier = sections()) {
Text(text = "许可的无障碍应用", style = typography.titleLarge,color = colorScheme.onPrimaryContainer) Text(text = "许可的无障碍应用", style = typography.titleLarge,color = colorScheme.onPrimaryContainer)
var list = mutableListOf("")
var listText by remember{ mutableStateOf("") } var listText by remember{ mutableStateOf("") }
val refreshList = { val refreshList = {
list = myDpm.getPermittedAccessibilityServices(myComponent) ?: mutableListOf("")
listText = "" listText = ""
var count = list.size var count = permittedAccessibility.size
for(eachAccessibility in list) { for(eachAccessibility in permittedAccessibility){ count-=1; listText+=eachAccessibility; if(count>0){listText+="\n"} }
count -= 1
listText += eachAccessibility
if(count>0) { listText += "\n" }
}
} }
var inited by remember{mutableStateOf(false)} var inited by remember{mutableStateOf(false)}
if(!inited){refreshList(); inited=true} if(!inited){
val getList = myDpm.getPermittedAccessibilityServices(myComponent)
if(getList!=null){ permittedAccessibility = getList }
refreshList(); inited=true
}
Text(text = if(listText!=""){listText}else{""}, style = bodyTextStyle) Text(text = if(listText!=""){listText}else{""}, style = bodyTextStyle)
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween){ Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween){
Button( Button(
onClick = { onClick = { permittedAccessibility.add(pkgName); refreshList()},
focusMgr.clearFocus()
list.plus(pkgName)
Toast.makeText(myContext, if(myDpm.setPermittedAccessibilityServices(myComponent,list)){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
refreshList()
},
modifier = Modifier.fillMaxWidth(0.49F) modifier = Modifier.fillMaxWidth(0.49F)
) { ) {
Text("添加") Text("添加")
} }
Button( Button(
onClick = { onClick = { permittedAccessibility.remove(pkgName); refreshList() },
focusMgr.clearFocus()
list.remove(pkgName)
Toast.makeText(myContext, if(myDpm.setPermittedAccessibilityServices(myComponent,list)){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
refreshList()
},
modifier = Modifier.fillMaxWidth(0.96F) modifier = Modifier.fillMaxWidth(0.96F)
) { ) {
Text("移除") Text("移除")
} }
} }
Button(
onClick = {
focusMgr.clearFocus()
Toast.makeText(myContext, if(myDpm.setPermittedAccessibilityServices(myComponent, permittedAccessibility)){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
val getList = myDpm.getPermittedAccessibilityServices(myComponent)
if(getList!=null){ permittedAccessibility = getList }
refreshList()
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "应用")
}
} }
} }
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){ if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
Column(modifier = sections()) { Column(modifier = sections()) {
Text(text = "许可的输入法", style = typography.titleLarge,color = colorScheme.onPrimaryContainer) Text(text = "许可的输入法", style = typography.titleLarge,color = colorScheme.onPrimaryContainer)
var imeList = mutableListOf<String>()
var imeListText by remember{ mutableStateOf("") } var imeListText by remember{ mutableStateOf("") }
val refreshList = { val refreshList = {
if(myDpm.getPermittedInputMethods(myComponent)!=null){ imeList = myDpm.getPermittedInputMethods(myComponent)!! }
imeListText = "" imeListText = ""
for(eachIme in imeList){ imeListText += "$eachIme \n" } for(eachIme in permittedIme){ imeListText += "$eachIme \n" }
} }
var inited by remember{mutableStateOf(false)} var inited by remember{mutableStateOf(false)}
if(!inited){refreshList();inited=true} if(!inited){
val getList = myDpm.getPermittedInputMethods(myComponent)
if(getList!=null){ permittedIme = getList }
refreshList();inited=true
}
Text(text = if(imeListText!=""){imeListText}else{""}, style = bodyTextStyle) Text(text = if(imeListText!=""){imeListText}else{""}, style = bodyTextStyle)
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween){ Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween){
Button( Button(
onClick = { onClick = { permittedIme.add(pkgName); refreshList() },
focusMgr.clearFocus()
imeList.plus(pkgName)
Toast.makeText(myContext, if(myDpm.setPermittedInputMethods(myComponent, imeList)){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
refreshList()
},
modifier = Modifier.fillMaxWidth(0.49F) modifier = Modifier.fillMaxWidth(0.49F)
) { ) {
Text("添加") Text("添加")
} }
Button( Button(
onClick = { onClick = { permittedIme.remove(pkgName); refreshList()},
focusMgr.clearFocus()
imeList.remove(pkgName)
Toast.makeText(myContext, if(myDpm.setPermittedInputMethods(myComponent, imeList)){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
refreshList()
},
modifier = Modifier.fillMaxWidth(0.96F) modifier = Modifier.fillMaxWidth(0.96F)
) { ) {
Text("移除") Text("移除")
} }
} }
Button(
onClick = {
Toast.makeText(myContext, if(myDpm.setPermittedInputMethods(myComponent, permittedIme)){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
val getList = myDpm.getPermittedInputMethods(myComponent)
if(getList!=null){ permittedIme = getList }
refreshList()
},
modifier = Modifier.fillMaxWidth()
) {
Text("应用")
}
}
}
if(VERSION.SDK_INT>=28&&isDeviceOwner(myDpm)){
Column(modifier = sections()){
Text(text = "保持卸载的应用", style = typography.titleLarge)
Text(text = "作用未知", style = bodyTextStyle)
var listText by remember{mutableStateOf("")}
val refresh = {
listText = ""
var count = keepUninstallPkg.size
for(each in keepUninstallPkg){ count-=1; listText+=each; if(count>0){listText+="\n"} }
}
var inited by remember{mutableStateOf(false)}
if(!inited){
val getList = myDpm.getKeepUninstalledPackages(myComponent)
if(getList!=null){ keepUninstallPkg = getList }
refresh(); inited=true
}
Text(text = if(listText==""){""}else{listText}, style = bodyTextStyle)
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){
Button(
onClick = {
keepUninstallPkg.add(pkgName)
refresh()
},
modifier = Modifier.fillMaxWidth(0.49F)
){
Text("添加")
}
Button(
onClick = {
keepUninstallPkg.remove(pkgName)
refresh()
},
modifier = Modifier.fillMaxWidth(0.96F)
){
Text("移除")
}
}
Button(
onClick = {
focusMgr.clearFocus()
myDpm.setKeepUninstalledPackages(myComponent, keepUninstallPkg)
val getList = myDpm.getKeepUninstalledPackages(myComponent)
if(getList!=null){ keepUninstallPkg = getList }
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth()
){
Text("应用")
}
} }
} }
@@ -509,7 +567,7 @@ fun ApplicationManage(){
myDpm.clearApplicationUserData(myComponent,pkgName,executor,onClear) myDpm.clearApplicationUserData(myComponent,pkgName,executor,onClear)
}, },
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm), enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm),
modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp) modifier = Modifier.fillMaxWidth().padding(horizontal = 10.dp)
) { ) {
Text("清除应用存储") Text("清除应用存储")
} }
@@ -584,10 +642,14 @@ fun ApplicationManage(){
} }
Button( Button(
onClick = { onClick = {
if(apkUri!=null){
val intent = Intent(Intent.ACTION_INSTALL_PACKAGE) val intent = Intent(Intent.ACTION_INSTALL_PACKAGE)
intent.setData(apkUri) intent.setData(apkUri)
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
myContext.startActivity(intent) myContext.startActivity(intent)
}else{
Toast.makeText(myContext, "请先选择APK", Toast.LENGTH_SHORT).show()
}
}, },
modifier = Modifier.fillMaxWidth(0.96F) modifier = Modifier.fillMaxWidth(0.96F)
) { ) {

View File

@@ -485,16 +485,31 @@ fun DeviceControl(){
onClick = { onClick = {
val log = myDpm.retrieveSecurityLogs(myComponent) val log = myDpm.retrieveSecurityLogs(myComponent)
if(log!=null){ if(log!=null){
for(i in log){ Log.d("NetLog",i.toString()) } for(i in log){ Log.d("SecureLog",i.toString()) }
Toast.makeText(myContext,"已输出至Log",Toast.LENGTH_SHORT).show() Toast.makeText(myContext,"已输出至Log",Toast.LENGTH_SHORT).show()
}else{ }else{
Log.d("NetLog","") Log.d("Secure5Log","")
Toast.makeText(myContext,"",Toast.LENGTH_SHORT).show() Toast.makeText(myContext,"日志",Toast.LENGTH_SHORT).show()
} }
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Text("收集") Text("安全日志")
}
Button(
onClick = {
val log = myDpm.retrievePreRebootSecurityLogs(myComponent)
if(log!=null){
for(i in log){ Log.d("SecureLog",i.toString()) }
Toast.makeText(myContext,"已输出至Log",Toast.LENGTH_SHORT).show()
}else{
Log.d("SecureLog","")
Toast.makeText(myContext,"无日志",Toast.LENGTH_SHORT).show()
}
},
modifier = Modifier.fillMaxWidth()
) {
Text("重启前安全日志")
} }
} }
} }

View File

@@ -34,7 +34,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@@ -50,7 +49,9 @@ lateinit var getCaCert: ActivityResultLauncher<Intent>
lateinit var createUser:ActivityResultLauncher<Intent> lateinit var createUser:ActivityResultLauncher<Intent>
lateinit var createManagedProfile:ActivityResultLauncher<Intent> lateinit var createManagedProfile:ActivityResultLauncher<Intent>
lateinit var getApk:ActivityResultLauncher<Intent> lateinit var getApk:ActivityResultLauncher<Intent>
lateinit var apkUri: Uri lateinit var getUserIcon:ActivityResultLauncher<Intent>
var userIconUri:Uri? = null
var apkUri: Uri? = null
var caCert = byteArrayOf() var caCert = byteArrayOf()
@ExperimentalMaterial3Api @ExperimentalMaterial3Api
@@ -58,10 +59,13 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
getUserIcon = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
userIconUri = it.data?.data
if(userIconUri==null){ Toast.makeText(applicationContext, "空URI", Toast.LENGTH_SHORT).show() }
}
getApk = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { getApk = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val uri = it.data?.data apkUri = it.data?.data
if(uri!=null){ apkUri = uri } if(apkUri==null){ Toast.makeText(applicationContext, "空URI", Toast.LENGTH_SHORT).show() }
else{ Toast.makeText(applicationContext, "空URI", Toast.LENGTH_SHORT).show() }
} }
getCaCert = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { getCaCert = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
uriToStream(applicationContext,it.data?.data){stream-> uriToStream(applicationContext,it.data?.data){stream->

View File

@@ -80,7 +80,7 @@ fun Password(){
} }
val pwdFailedAttempts = myDpm.currentFailedPasswordAttempts val pwdFailedAttempts = myDpm.currentFailedPasswordAttempts
Text(text = "密码已错误次数:$pwdFailedAttempts",style=bodyTextStyle) Text(text = "密码已错误次数:$pwdFailedAttempts",style=bodyTextStyle)
if(VERSION.SDK_INT>=28&&(myDpm.isManagedProfile(myComponent)||myDpm.isProfileOwnerApp("com.binbin.androidowner"))){ if(VERSION.SDK_INT>=28&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
val unifiedPwd = myDpm.isUsingUnifiedPassword(myComponent) val unifiedPwd = myDpm.isUsingUnifiedPassword(myComponent)
Text("个人与工作应用密码一致:$unifiedPwd",style=bodyTextStyle) Text("个人与工作应用密码一致:$unifiedPwd",style=bodyTextStyle)
} }
@@ -137,7 +137,6 @@ fun Password(){
} }
if(isWear){ Text(text = "(可以水平滚动)",style=typography.bodyMedium) } if(isWear){ Text(text = "(可以水平滚动)",style=typography.bodyMedium) }
Text("没有密码时会自动激活令牌",style=bodyTextStyle) Text("没有密码时会自动激活令牌",style=bodyTextStyle)
Text("有可能无法设置密码重置令牌,因机而异",style=bodyTextStyle)
} }
} }
Column( Column(

View File

@@ -20,10 +20,10 @@ class MyDeviceAdminReceiver : DeviceAdminReceiver() {
override fun onTransferOwnershipComplete(context: Context, bundle: PersistableBundle?) { override fun onTransferOwnershipComplete(context: Context, bundle: PersistableBundle?) {
super.onTransferOwnershipComplete(context, bundle) super.onTransferOwnershipComplete(context, bundle)
if(bundle!=null){ if(bundle!=null){
Toast.makeText(context,"转移控制权完毕,附加内容长度:${bundle.size()}",Toast.LENGTH_SHORT).show() Toast.makeText(context,"转移所有权完毕,附加内容长度:${bundle.size()}",Toast.LENGTH_SHORT).show()
Log.d("TransferOwnerShip",bundle.toString()) Log.d("TransferOwnerShip",bundle.toString())
}else{ }else{
Toast.makeText(context,"转移控制权完毕,无附加内容}",Toast.LENGTH_SHORT).show() Toast.makeText(context,"转移所有权完毕,无附加内容}",Toast.LENGTH_SHORT).show()
} }
} }

View File

@@ -70,7 +70,7 @@ fun AppSetting(navCtrl:NavHostController){
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable { shareLink(myContext, "https://github.com/BinTianqi/AndroidOwner/Guide.md") } .clickable { shareLink(myContext, "https://github.com/BinTianqi/AndroidOwner/blob/master/Guide.md") }
.padding(start = 8.dp, bottom = 4.dp) .padding(start = 8.dp, bottom = 4.dp)
){ ){
Icon( Icon(

View File

@@ -3,9 +3,12 @@ package com.binbin.androidowner
import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Build.VERSION import android.os.Build.VERSION
import android.os.UserHandle import android.os.UserHandle
import android.os.UserManager import android.os.UserManager
import android.provider.MediaStore
import android.widget.Toast import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@@ -32,6 +35,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.os.UserManagerCompat import androidx.core.os.UserManagerCompat
var affiliationID = mutableSetOf<String>() var affiliationID = mutableSetOf<String>()
@Composable @Composable
fun UserManage() { fun UserManage() {
@@ -290,31 +294,62 @@ fun UserManage() {
} }
} }
UserSessionMessage("用户名","用户名",true,myDpm,myContext,{null},{msg -> myDpm.setProfileName(myComponent, msg.toString())}) UserSessionMessage("用户名", "用户名", true, {null}) {msg-> myDpm.setProfileName(myComponent, msg.toString())}
if(VERSION.SDK_INT>=23&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
Column(modifier = sections()){
var getContent by remember{mutableStateOf(false)}
Text(text = "用户图标", style = typography.titleLarge)
Text(text = "尽量选择正方形的图片,以免产生问题", style = bodyTextStyle)
CheckBoxItem("使用文件选择器而不是相册",{getContent},{getContent=!getContent})
Button(
onClick = {
val intent = Intent(if(getContent){Intent.ACTION_GET_CONTENT}else{Intent.ACTION_PICK})
if(getContent){intent.addCategory(Intent.CATEGORY_OPENABLE)}
intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
getUserIcon.launch(intent)
},
modifier = Modifier.fillMaxWidth()
) {
Text("选择图片...")
}
Button(
onClick = {
if(userIconUri!=null){
uriToStream(myContext, userIconUri){stream ->
val bitmap = BitmapFactory.decodeStream(stream)
myDpm.setUserIcon(myComponent,bitmap)
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
}
}else{
Toast.makeText(myContext, "请先选择图片", Toast.LENGTH_SHORT).show()
}
},
modifier = Modifier.fillMaxWidth()
) {
Text("应用")
}
}
}
if(VERSION.SDK_INT>=28){ if(VERSION.SDK_INT>=28){
UserSessionMessage("用户会话开始消息","消息",false,myDpm,myContext,{myDpm.getStartUserSessionMessage(myComponent)},{msg -> myDpm.setStartUserSessionMessage(myComponent,msg)}) UserSessionMessage("用户会话开始消息", "消息", false, {myDpm.getStartUserSessionMessage(myComponent)}) {msg-> myDpm.setStartUserSessionMessage(myComponent, msg)}
UserSessionMessage("用户会话结束消息","消息",false,myDpm,myContext,{myDpm.getEndUserSessionMessage(myComponent)},{msg -> myDpm.setEndUserSessionMessage(myComponent,msg)}) UserSessionMessage("用户会话结束消息", "消息", false, {myDpm.getEndUserSessionMessage(myComponent)}) {msg-> myDpm.setEndUserSessionMessage(myComponent, msg)}
} }
Spacer(Modifier.padding(vertical = 30.dp)) Spacer(Modifier.padding(vertical = 30.dp))
} }
} }
@Composable @Composable
private fun UserSessionMessage( private fun UserSessionMessage(text:String, textField:String, profileOwner:Boolean, get: ()->CharSequence?, setMsg:(msg: CharSequence?)->Unit){
text:String,
textField:String,
profileOwner:Boolean,
myDpm:DevicePolicyManager,
myContext: Context,
get:()->CharSequence?,
setMsg:(msg:CharSequence?)->Unit
){
Column( Column(
modifier = sections() modifier = sections()
) { ) {
val myContext = LocalContext.current
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var msg by remember{ mutableStateOf(if(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&profileOwner)){ if(get()==null){""}else{get().toString()} }else{""}) } var msg by remember{ mutableStateOf(if(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&profileOwner)){ if(get()==null){""}else{get().toString()} }else{""}) }
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE) val sharedPref = myContext.getSharedPreferences("data", Context.MODE_PRIVATE)
val isWear = sharedPref.getBoolean("isWear",false) val isWear = sharedPref.getBoolean("isWear",false)
Text(text = text, style = typography.titleLarge, color = colorScheme.onPrimaryContainer) Text(text = text, style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
TextField( TextField(