try using shizuku to provision

This commit is contained in:
BinTianqi
2024-02-24 20:28:08 +08:00
parent b555747f89
commit 77233bec0d
12 changed files with 371 additions and 110 deletions

View File

@@ -18,6 +18,7 @@
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
<uses-sdk tools:overrideLibrary="rikka.shizuku.provider,rikka.shizuku.api,rikka.shizuku.shared,rikka.shizuku.aidl"/>
<application
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
@@ -72,5 +73,12 @@
<action android:name="com.binbin.androidowner.PKG_INSTALL_RESULT"/>
</intent-filter>
</receiver>
<provider
android:name="rikka.shizuku.ShizukuProvider"
android:authorities="${applicationId}.shizuku"
android:enabled="true"
android:exported="true"
android:multiprocess="false"
android:permission="android.permission.INTERACT_ACROSS_USERS_FULL" />
</application>
</manifest>

View File

@@ -0,0 +1,26 @@
#!/system/bin/sh
BASEDIR=$(dirname "$0")
DEX="$BASEDIR"/rish_shizuku.dex
if [ ! -f "$DEX" ]; then
echo "Cannot find $DEX, please check the tutorial in Shizuku app"
exit 1
fi
if [ $(getprop ro.build.version.sdk) -ge 34 ]; then
if [ -w $DEX ]; then
echo "On Android 14+, app_process cannot load writable dex."
echo "Attempting to remove the write permission..."
echo "上面那两行是Shizuku的提示可以忽略"
echo ""
chmod 400 $DEX
fi
if [ -w $DEX ]; then
echo "Cannot remove the write permission of $DEX."
echo "You can copy to file to terminal app's private directory (/data/data/<package>, so that remove write permission is possible"
exit 1
fi
fi
[ -z "$RISH_APPLICATION_ID" ] && export RISH_APPLICATION_ID="com.binbin.androidowner"
/system/bin/app_process -Djava.class.path="$DEX" /system/bin --nice-name=rish rikka.shizuku.shell.ShizukuShellLoader "$@"

Binary file not shown.

View File

@@ -40,6 +40,7 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.binbin.androidowner.ui.theme.AndroidOwnerTheme
import rikka.shizuku.Shizuku
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
@@ -56,9 +57,22 @@ var caCert = byteArrayOf()
@ExperimentalMaterial3Api
class MainActivity : ComponentActivity() {
override fun onDestroy() {
super.onDestroy()
if(VERSION.SDK_INT>=24){
Shizuku.removeBinderReceivedListener(ShizukuUtil.binderReceivedListener)
Shizuku.removeBinderDeadListener(ShizukuUtil.binderDeadListener)
Shizuku.removeRequestPermissionResultListener(ShizukuUtil.requestPermissionListener)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
WindowCompat.setDecorFitsSystemWindows(window, false)
super.onCreate(savedInstanceState)
if(VERSION.SDK_INT>=24){
Shizuku.addBinderReceivedListenerSticky(ShizukuUtil.binderReceivedListener)
Shizuku.addBinderDeadListener(ShizukuUtil.binderDeadListener)
Shizuku.addRequestPermissionResultListener(ShizukuUtil.requestPermissionListener)
}
getUserIcon = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
userIconUri = it.data?.data
if(userIconUri==null){ Toast.makeText(applicationContext, "空URI", Toast.LENGTH_SHORT).show() }
@@ -90,6 +104,7 @@ class MainActivity : ComponentActivity() {
MyScaffold()
}
}
deleteRish(applicationContext)
}
}
@@ -112,7 +127,8 @@ fun MyScaffold(){
"ApplicationManage" to R.string.app_manage,
"UserRestriction" to R.string.user_restrict,
"Password" to R.string.password,
"AppSetting" to R.string.setting
"AppSetting" to R.string.setting,
"ShizukuActivate" to R.string.shizuku_activate
)
val topBarName = topBarNameMap[backStackEntry?.destination?.route]?: R.string.app_name
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
@@ -175,6 +191,7 @@ fun MyScaffold(){
composable(route = "AppSetting", content = { AppSetting(navCtrl)})
composable(route = "Network", content = {Network()})
composable(route = "ActivateManagedProfile", content = {ActivateManagedProfile(navCtrl)})
composable(route = "ShizukuActivate", content = {ShizukuActivate()})
}
if(!inited&&jumpToActivateProfile){navCtrl.navigate("ActivateManagedProfile");inited=true}
}
@@ -322,13 +339,14 @@ fun isProfileOwner(dpm:DevicePolicyManager): Boolean {
@SuppressLint("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
@Composable
@Stable
fun sections(bgColor:Color=MaterialTheme.colorScheme.primaryContainer):Modifier{
fun sections(bgColor:Color=MaterialTheme.colorScheme.primaryContainer,onClick:()->Unit={},clickable:Boolean=false):Modifier{
val backgroundColor = if(isSystemInDarkTheme()){bgColor.copy(0.3F)}else{bgColor.copy(0.8F)}
return if(!LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE).getBoolean("isWear",false)){
Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 4.dp)
.clip(RoundedCornerShape(14.dp))
.clickable(onClick=onClick, enabled = clickable)
.background(color = backgroundColor)
.padding(vertical = 10.dp, horizontal = 10.dp)
}else{
@@ -336,6 +354,7 @@ fun sections(bgColor:Color=MaterialTheme.colorScheme.primaryContainer):Modifier{
.fillMaxWidth()
.padding(horizontal = 3.dp, vertical = 3.dp)
.clip(RoundedCornerShape(10.dp))
.clickable(onClick=onClick, enabled = clickable)
.background(color = backgroundColor)
.padding(vertical = 2.dp, horizontal = 3.dp)
}

View File

@@ -91,7 +91,7 @@ fun ManagedProfile() {
Text(text = "把上面命令中的USER_ID替换成你的UserID", style = bodyTextStyle)
}
}
if(!isProfileOwner(myDpm)&&(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)))){
if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))){
Column(modifier = sections()) {
Text(text = "工作资料", style = typography.titleLarge, color = titleColor)
var skipEncrypt by remember{mutableStateOf(false)}

View File

@@ -15,12 +15,11 @@ 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.ButtonDefaults
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowRight
import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -51,6 +50,13 @@ fun DpmPermissions(navCtrl:NavHostController){
modifier = Modifier.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = sections(onClick = {navCtrl.navigate("ShizukuActivate")}, clickable = true),
horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically
){
Text(text = "Shizuku", style = typography.titleLarge, color = titleColor)
Icon(imageVector = Icons.Default.KeyboardArrowRight,contentDescription = null, tint = colorScheme.onPrimaryContainer)
}
if(!myDpm.isAdminActive(myComponent)&&isWear){
Button(onClick = { activateDeviceAdmin(myContext,myComponent) },modifier = Modifier.padding(horizontal = 3.dp).fillMaxWidth()) {
Text("激活Device admin")
@@ -81,97 +87,70 @@ fun DpmPermissions(navCtrl:NavHostController){
}
}
}
if(!isda){
Column(
modifier = sections(colorScheme.tertiaryContainer.copy(alpha = 0.8F)),
horizontalAlignment = Alignment.Start
if(!isda&&!isDeviceOwner(myDpm)&&!isProfileOwner(myDpm)){
SelectionContainer(modifier = sections(colorScheme.tertiaryContainer)){
Text("激活命令:\nadb shell dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
color = colorScheme.onTertiaryContainer, style = bodyTextStyle)
}
}
if(!isDeviceOwner(myDpm)){
Row(
modifier = sections(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
SelectionContainer {
Text("adb shell dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
color = colorScheme.onTertiaryContainer, style = bodyTextStyle)
Column {
Text(text = "Profile Owner", fontSize = if(!isWear){22.sp}else{20.sp},color = titleColor)
Text(if(isProfileOwner(myDpm)){"已激活"}else{"未激活"})
}
Text(text = "或者进入设置(原生安卓) -> 安全 -> 更多安全设置 -> 设备管理应用 -> Android Owner", style = bodyTextStyle)
}
}
Row(
modifier = sections(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(text = "Profile Owner", fontSize = if(!isWear){22.sp}else{20.sp},color = titleColor)
Text(if(isProfileOwner(myDpm)){"已激活"}else{"未激活"})
}
if(isProfileOwner(myDpm)&&VERSION.SDK_INT>=24&&!isWear){
Button(
onClick = {
myDpm.clearProfileOwner(myComponent)
navCtrl.navigateUp()
if(isProfileOwner(myDpm)&&VERSION.SDK_INT>=24&&!isWear){
Button(
onClick = {
myDpm.clearProfileOwner(myComponent)
navCtrl.navigateUp()
}
) {
Text("撤销")
}
) {
Text("撤销")
}
}
}
if(!isProfileOwner(myDpm)){
Column(
modifier = sections(colorScheme.tertiaryContainer.copy(alpha = 0.8F)),
horizontalAlignment = Alignment.Start
) {
if(!isDeviceOwner(myDpm)){
SelectionContainer {
Text("adb shell dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
color = colorScheme.onTertiaryContainer, style = bodyTextStyle)
}
Text(text = "Device owner和Profile owner不能同时存在强烈建议激活Device owner", style = bodyTextStyle)
}
if(isDeviceOwner(myDpm)){
Text(text = "Device owner创建其他用户后这个应用会成为新用户的Profile owner", style = bodyTextStyle)
}
}
}
Row(
modifier = sections(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(text = "Device Owner", fontSize = if(!isWear){22.sp}else{20.sp},color = titleColor)
Text(if(isDeviceOwner(myDpm)){"已激活"}else{"未激活"})
}
if(isDeviceOwner(myDpm)&&!isWear){
Button(
onClick = {
myDpm.clearDeviceOwnerApp("com.binbin.androidowner")
navCtrl.navigateUp()
}
) {
Text("撤销")
}
}
}
if(!isDeviceOwner(myDpm)&&!isProfileOwner(myDpm)){
Column(
modifier = sections(colorScheme.tertiaryContainer.copy(alpha = 0.8F)),
horizontalAlignment = Alignment.Start
) {
SelectionContainer {
Text(text = "adb shell dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
SelectionContainer(modifier = sections(colorScheme.tertiaryContainer)){
Text("激活命令:\nadb shell dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
color = colorScheme.onTertiaryContainer, style = bodyTextStyle)
}
if(!isda){
Text(text = "使用此命令也会激活Device Admin", style = bodyTextStyle)
}
Text(text = "成为Device owner后将不能新建工作资料", style = bodyTextStyle)
}
}
if(isDeviceOwner(myDpm)|| isProfileOwner(myDpm)||myDpm.isAdminActive(myComponent)){
Text(
text = "注意!在这里撤销权限不会清除配置。比如:被停用的应用会保持停用状态",
color = colorScheme.onErrorContainer,
modifier = sections(colorScheme.errorContainer.copy(alpha = 0.8F)),
style = bodyTextStyle
)
if(!isProfileOwner(myDpm)){
Row(
modifier = sections(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(text = "Device Owner", fontSize = if(!isWear){22.sp}else{20.sp},color = titleColor)
Text(if(isDeviceOwner(myDpm)){"已激活"}else{"未激活"})
}
if(isDeviceOwner(myDpm)&&!isWear){
Button(
onClick = {
myDpm.clearDeviceOwnerApp("com.binbin.androidowner")
navCtrl.navigateUp()
}
) {
Text("撤销")
}
}
}
}
if(!isDeviceOwner(myDpm)&&!isProfileOwner(myDpm)){
SelectionContainer(modifier = sections(colorScheme.tertiaryContainer)){
Text(text = "激活命令:\nadb shell dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
color = colorScheme.onTertiaryContainer, style = bodyTextStyle)
}
}
if(VERSION.SDK_INT>=30){
Column(
@@ -453,3 +432,7 @@ fun activateDeviceAdmin(inputContext:Context,inputComponent:ComponentName){
Toast.makeText(inputContext,"不支持",Toast.LENGTH_SHORT).show()
}
}
fun activateShizuku(){
}

View File

@@ -0,0 +1,200 @@
package com.binbin.androidowner
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.content.Context.MODE_PRIVATE
import android.content.pm.PackageManager
import android.os.Binder
import android.os.Build.VERSION
import android.os.UserManager
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.compose.foundation.horizontalScroll
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.material.icons.Icons
import androidx.compose.material.icons.rounded.Warning
import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
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
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import org.apache.commons.io.IOUtils
import rikka.shizuku.Shizuku
import java.io.BufferedReader
import java.io.ByteArrayInputStream
import java.io.File
import java.io.InputStreamReader
@Composable
fun ShizukuActivate(){
val myContext = LocalContext.current
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java)
val focusMgr = LocalFocusManager.current
val sharedPref = LocalContext.current.getSharedPreferences("data", MODE_PRIVATE)
val isWear = sharedPref.getBoolean("isWear",false)
val bodyTextStyle = if(isWear){ typography.bodyMedium }else{ typography.bodyLarge }
val filesDir = myContext.filesDir
Column(modifier = Modifier.verticalScroll(rememberScrollState())){
var outputText by remember{mutableStateOf("")}
if(VERSION.SDK_INT>=30&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
Row(modifier = sections(colorScheme.errorContainer), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically){
Icon(imageVector = Icons.Rounded.Warning, contentDescription = null, tint = colorScheme.onErrorContainer)
Text(text = "暂不支持在工作资料中使用Shizuku", style = bodyTextStyle, color = colorScheme.onErrorContainer)
}
}
Button(onClick = {outputText=checkPermission()}, enabled = VERSION.SDK_INT>=24, modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
Text(text = "检查权限")
}
Column(modifier = sections()){
Text(text = "激活", style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
Button(
onClick = {
extractRish(myContext)
outputText = executeCommand("sh rish.sh", "dpm set-active-admin com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver", null, filesDir)
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Device admin")
}
Button(
onClick = {
extractRish(myContext)
outputText = executeCommand("sh rish.sh", "dpm set-profile-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver", null, filesDir)
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Profile owner")
}
Button(
onClick = {
extractRish(myContext)
outputText = executeCommand("sh rish.sh", "dpm set-device-owner com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver", null, filesDir)
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Device owner")
}
}
if(VERSION.SDK_INT>=30&&!myDpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)){
Column(modifier = sections()){
Text(text = "组织拥有工作资料", style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
Text(text = "请输入工作资料的UserID", style = bodyTextStyle)
var inputUserID by remember{mutableStateOf("")}
OutlinedTextField(
value = inputUserID, onValueChange = {inputUserID=it},
label = {Text("UserID")},
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)
)
Button(
onClick = {
extractRish(myContext)
outputText = executeCommand(
"sh rish.sh",
"dpm mark-profile-owner-on-organization-owned-device --user $inputUserID com.binbin.androidowner/com.binbin.androidowner.MyDeviceAdminReceiver",
null, filesDir
)
if(myDpm.isOrganizationOwnedDeviceWithManagedProfile){
Toast.makeText(myContext,"成功",Toast.LENGTH_SHORT).show()
}
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "激活")
}
}
}
Button(
onClick = {
extractRish(myContext)
outputText = executeCommand("sh rish.sh", "pwd", null, filesDir)
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "test")
}
SelectionContainer(modifier = Modifier.padding(3.dp)){
Text(text = outputText, style = bodyTextStyle, softWrap = false, modifier = Modifier.horizontalScroll(rememberScrollState()))
}
Spacer(Modifier.padding(vertical = 30.dp))
}
}
fun extractRish(myContext:Context){
val assetsMgr = myContext.assets
val fileList = myContext.fileList()
if("rish.sh" !in fileList){
val shInput = assetsMgr.open("rish.sh")
val shOutput = myContext.openFileOutput("rish.sh",MODE_PRIVATE)
IOUtils.copy(shInput,shOutput)
shOutput.close()
}
if("rish_shizuku.dex" !in fileList){
val dexInput = assetsMgr.open("rish_shizuku.dex")
val dexOutput = myContext.openFileOutput("rish_shizuku.dex",MODE_PRIVATE)
IOUtils.copy(dexInput,dexOutput)
dexOutput.close()
}
}
fun deleteRish(myContext: Context){
myContext.deleteFile("rish.sh")
myContext.deleteFile("rish_shizuku.dex")
}
private fun checkPermission():String {
if(Shizuku.isPreV11()) {
return "有可能不支持v11以下的Shizuku\n你仍然可以尝试使用这些功能"
}else{
try {
if(Shizuku.checkSelfPermission()==PackageManager.PERMISSION_GRANTED) {
val permission = when(Shizuku.getUid()){
0->"Root"
2000->"Shell"
else->"未知权限"
}
return "Shizuku v${Shizuku.getVersion()}\n已授权($permission)"
} else if(Shizuku.shouldShowRequestPermissionRationale()) {
return "用户拒绝"
} else {
Shizuku.requestPermission(0)
}
} catch(e: Throwable) {
return "服务未启动"
}
}
return "未知"
}
fun executeCommand(command: String, subCommand:String, env: Array<String>?, dir:File): String {
val output = StringBuilder()
try {
val tunnel = ByteArrayInputStream(subCommand.toByteArray())
val process = Runtime.getRuntime().exec(command,env,dir)
val outputStream = process.outputStream
IOUtils.copy(tunnel,outputStream)
outputStream.close()
process.waitFor()
val reader = BufferedReader(InputStreamReader(process.inputStream))
var line: String
while(reader.readLine().also {line = it}!=null) { output.append(line+"\n") }
} catch(e: Exception) {
e.printStackTrace()
}
return output.toString()
}

View File

@@ -0,0 +1,16 @@
package com.binbin.androidowner;
import android.content.pm.PackageManager;
import android.util.Log;
import rikka.shizuku.Shizuku;
public class ShizukuUtil {
private static void onRequestPermissionsResult(int requestCode, int grantResult) {
boolean granted = PackageManager.PERMISSION_GRANTED == grantResult;
Log.d("ShizukuUtil","RequestCode: "+requestCode);
Log.d("ShizukuUtil","GrantState: "+granted);
}
static final Shizuku.OnRequestPermissionResultListener requestPermissionListener = ShizukuUtil::onRequestPermissionsResult;
static final Shizuku.OnBinderReceivedListener binderReceivedListener = () -> Log.d("ShizukuUtil","Binder received");
static final Shizuku.OnBinderDeadListener binderDeadListener = () -> Log.e("ShizukuUtil","Binder dead");
}

View File

@@ -5,30 +5,26 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.os.Binder
import android.os.Build.VERSION
import android.os.UserHandle
import android.os.UserManager
import android.provider.MediaStore
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
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.Checkbox
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
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.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
@@ -67,7 +63,7 @@ fun UserManage() {
Text(text = "附属用户: ${myDpm.isAffiliatedUser}",style = bodyTextStyle)
}
Spacer(Modifier.padding(vertical = if(isWear){2.dp}else{5.dp}))
Text(text = "当前UserID${getCurrentUserId()}",style = bodyTextStyle)
Text(text = "当前UserID${Binder.getCallingUid()/100000}",style = bodyTextStyle)
Text(text = "当前用户序列号:${userManager.getSerialNumberForUser(android.os.Process.myUserHandle())}",style = bodyTextStyle)
}
@@ -381,13 +377,3 @@ private fun userOperationResultCode(result:Int): String {
else->"未知"
}
}
fun getCurrentUserId(): Int {
try {
val uh = UserHandle::class.java.getDeclaredMethod("myUserId")
uh.isAccessible = true
val userId = uh.invoke(null)
if (userId is Int) { return userId }
} catch (ignored: Exception) { }
return -1
}

View File

@@ -115,4 +115,5 @@
<string name="developing">功能开发中</string>
<string name="wifi_lockdown">WiFi锁定</string>
<string name="work_profile">工作资料</string>
<string name="shizuku_activate">Shizuku</string>
</resources>