diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index c097f3a..1bcefe2 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -11,8 +11,8 @@ android {
applicationId = "com.binbin.androidowner"
minSdk = 21
targetSdk = 34
- versionCode = 11
- versionName = "2.4"
+ versionCode = 12
+ versionName = "2.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2dd96ac..f4e968e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,6 +15,7 @@
+
=24&&isDeviceOwner(myDpm)){
+ if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
val isSuspended: Boolean = try{ myDpm.isPackageSuspended(myComponent,pkgName) }
catch(e:NameNotFoundException){ false }
catch(w:NameNotFoundException){ false }
@@ -472,7 +472,6 @@ private fun AppManageItem(
val myDpm = LocalContext.current.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val focusMgr = LocalFocusManager.current
var isEnabled by remember{ mutableStateOf(false) }
- if(isDeviceOwner(myDpm)|| isProfileOwner(myDpm)){ isEnabled = getMethod() }
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
if(!sharedPref.getBoolean("isWear",false)){
Row(
diff --git a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt
index 9b225b5..710ae27 100644
--- a/app/src/main/java/com/binbin/androidowner/DeviceControl.kt
+++ b/app/src/main/java/com/binbin/androidowner/DeviceControl.kt
@@ -492,7 +492,7 @@ fun DeviceControl(){
Text(text = "清除数据",style = typography.titleLarge,modifier = Modifier.padding(6.dp),color = colorScheme.onErrorContainer)
RadioButtonItem("默认",{flag==0},{flag=0}, colorScheme.onErrorContainer)
RadioButtonItem("WIPE_EXTERNAL_STORAGE",{flag==WIPE_EXTERNAL_STORAGE},{flag=WIPE_EXTERNAL_STORAGE}, colorScheme.onErrorContainer)
- if(VERSION.SDK_INT>=22){
+ if(VERSION.SDK_INT>=22&&isDeviceOwner(myDpm)){
RadioButtonItem("WIPE_RESET_PROTECTION_DATA",{flag==WIPE_RESET_PROTECTION_DATA},{flag=WIPE_RESET_PROTECTION_DATA}, colorScheme.onErrorContainer)
}
if(VERSION.SDK_INT>=28){ RadioButtonItem("WIPE_EUICC",{flag==WIPE_EUICC},{flag=WIPE_EUICC}, colorScheme.onErrorContainer) }
@@ -533,6 +533,9 @@ fun DeviceControl(){
}
}
}
+ if(VERSION.SDK_INT>=24&&isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
+ Text("将会删除工作资料")
+ }
}
Spacer(Modifier.padding(vertical = 30.dp))
}
diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt
index 05995e4..9f052ed 100644
--- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt
+++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt
@@ -23,6 +23,7 @@ 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.ui.Alignment
import androidx.compose.ui.Modifier
@@ -100,6 +101,7 @@ fun MyScaffold(){
"HomePage" to R.string.app_name,
"DeviceControl" to R.string.device_ctrl,
"Network" to R.string.network,
+ "ManagedProfile" to R.string.work_profile,
"Permissions" to R.string.permission,
"UserManage" to R.string.user_manage,
"ApplicationManage" to R.string.app_manage,
@@ -160,6 +162,7 @@ fun MyScaffold(){
){
composable(route = "HomePage", content = { HomePage(navCtrl)})
composable(route = "DeviceControl", content = { DeviceControl()})
+ composable(route = "ManagedProfile", content = {ManagedProfile(navCtrl)})
composable(route = "Permissions", content = { DpmPermissions(navCtrl)})
composable(route = "ApplicationManage", content = { ApplicationManage()})
composable(route = "UserRestriction", content = { UserRestriction()})
@@ -216,6 +219,7 @@ fun HomePage(navCtrl:NavHostController){
}
HomePageItem(R.string.device_ctrl, R.drawable.mobile_phone_fill0, "DeviceControl", navCtrl)
if(VERSION.SDK_INT>=26){HomePageItem(R.string.network, R.drawable.wifi_fill0, "Network",navCtrl)}
+ HomePageItem(R.string.work_profile, R.drawable.work_fill0, "ManagedProfile",navCtrl)
HomePageItem(R.string.app_manage, R.drawable.apps_fill0, "ApplicationManage", navCtrl)
HomePageItem(R.string.user_restrict, R.drawable.manage_accounts_fill0, "UserRestriction", navCtrl)
HomePageItem(R.string.user_manage,R.drawable.account_circle_fill0,"UserManage",navCtrl)
@@ -311,6 +315,7 @@ fun isProfileOwner(dpm:DevicePolicyManager): Boolean {
@SuppressLint("ModifierFactoryExtensionFunction", "ComposableModifierFactory")
@Composable
+@Stable
fun sections(bgColor:Color=MaterialTheme.colorScheme.primaryContainer):Modifier{
val backgroundColor = if(isSystemInDarkTheme()){bgColor.copy(0.4F)}else{bgColor.copy(0.6F)}
return if(!LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE).getBoolean("isWear",false)){
diff --git a/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt b/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt
new file mode 100644
index 0000000..dee21e6
--- /dev/null
+++ b/app/src/main/java/com/binbin/androidowner/ManagedProfile.kt
@@ -0,0 +1,122 @@
+package com.binbin.androidowner
+
+import android.app.admin.DevicePolicyManager
+import android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+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.foundation.rememberScrollState
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme.typography
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.runtime.*
+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 androidx.navigation.NavHostController
+
+@Composable
+fun ManagedProfile(navCtrl:NavHostController){
+ 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", Context.MODE_PRIVATE)
+ 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(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))){
+ 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)
+ }else{
+ intent.putExtra(DevicePolicyManager.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)}
+ createManagedProfile.launch(intent)
+ },
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ 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){
+ Column(modifier = sections()){
+ var time by remember{mutableStateOf("")}
+ time = myDpm.getManagedProfileMaximumTimeOff(myComponent).toString()
+ Text(text = "资料关闭时间", style = typography.titleLarge)
+ Text(text = "工作资料处于关闭状态的时间达到该限制后会停用个人应用,0为无限制(单位:毫秒)", style = bodyTextStyle)
+ 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小时")
+ Button(
+ onClick = {
+ myDpm.setManagedProfileMaximumTimeOff(myComponent,time.toLong())
+ Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
+ }
+ ) {
+ Text("应用")
+ }
+ }
+ }
+
+ Spacer(Modifier.padding(vertical = 30.dp))
+ }
+}
diff --git a/app/src/main/java/com/binbin/androidowner/Permissions.kt b/app/src/main/java/com/binbin/androidowner/Permissions.kt
index a849181..74b6dea 100644
--- a/app/src/main/java/com/binbin/androidowner/Permissions.kt
+++ b/app/src/main/java/com/binbin/androidowner/Permissions.kt
@@ -28,6 +28,7 @@ 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
@@ -160,6 +161,7 @@ fun DpmPermissions(navCtrl:NavHostController){
if(!isda){
Text(text = "使用此命令也会激活Device Admin", style = bodyTextStyle)
}
+ Text(text = "成为Device owner后将不能新建工作资料", style = bodyTextStyle)
}
}
if(isDeviceOwner(myDpm)|| isProfileOwner(myDpm)||myDpm.isAdminActive(myComponent)){
@@ -175,8 +177,6 @@ fun DpmPermissions(navCtrl:NavHostController){
modifier = sections()
) {
Text(text = "设备信息", style = typography.titleLarge,color = titleColor)
- val orgDevice = myDpm.isOrganizationOwnedDeviceWithManagedProfile
- Text("由组织拥有的受管理资料设备:$orgDevice",style=bodyTextStyle)
if(VERSION.SDK_INT>=34&&(isDeviceOwner(myDpm)||(isProfileOwner(myDpm)&&myDpm.isOrganizationOwnedDeviceWithManagedProfile))){
val financed = myDpm.isDeviceFinanced
Text("企业资产 : $financed",style=bodyTextStyle)
@@ -186,9 +186,7 @@ fun DpmPermissions(navCtrl:NavHostController){
Text("设备策略管理器角色:${if(dpmRole==null){"null"}else{""}}",style=bodyTextStyle)
if(dpmRole!=null){
Row(modifier = Modifier.fillMaxWidth().horizontalScroll(rememberScrollState())){
- SelectionContainer {
- Text(dpmRole)
- }
+ SelectionContainer { Text(dpmRole) }
}
}
}
@@ -234,6 +232,33 @@ fun DpmPermissions(navCtrl:NavHostController){
}
}
}
+
+ if((VERSION.SDK_INT>=26&&isDeviceOwner(myDpm))||(VERSION.SDK_INT>=24&&isProfileOwner(myDpm))){
+ Column(modifier = sections()){
+ var orgName by remember{
+ mutableStateOf(
+ if(myDpm.getOrganizationName(myComponent).toString()=="null"){ "" }else{ myDpm.getOrganizationName(myComponent).toString() }
+ )
+ }
+ Text(text = "组织名称", style = typography.titleLarge)
+ TextField(
+ value = orgName, onValueChange = {orgName=it}, modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp),
+ label = {Text("组织名称")},
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
+ keyboardActions = KeyboardActions(onDone = {focusManager.clearFocus()})
+ )
+ Button(
+ onClick = {
+ myDpm.setOrganizationName(myComponent,orgName)
+ Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
+ },
+ modifier = Modifier.fillMaxWidth()
+ ){
+ Text("应用")
+ }
+ }
+ }
+
if(isDeviceOwner(myDpm) || isProfileOwner(myDpm)){
Column(modifier = sections()) {
Text(text = "不受控制的账号类型", style = typography.titleLarge,color = titleColor)
@@ -267,12 +292,16 @@ fun DpmPermissions(navCtrl:NavHostController){
keyboardActions = KeyboardActions(onDone = {focusManager.clearFocus()})
)
Row(modifier = Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceBetween){
- Button(onClick={focusManager.clearFocus()
- myDpm.setAccountManagementDisabled(myComponent,inputText,true)
- noManageAccount=myDpm.accountTypesWithManagementDisabled
- refreshList()
- },modifier = Modifier.fillMaxWidth(0.49f)){
- Text("列表")
+ Button(
+ onClick={
+ focusManager.clearFocus()
+ myDpm.setAccountManagementDisabled(myComponent,inputText,true)
+ noManageAccount=myDpm.accountTypesWithManagementDisabled
+ refreshList()
+ },
+ modifier = Modifier.fillMaxWidth(0.49f)
+ ){
+ Text("添加")
}
Button(
onClick={focusManager.clearFocus()
@@ -282,7 +311,7 @@ fun DpmPermissions(navCtrl:NavHostController){
},
modifier = Modifier.fillMaxWidth(0.96F)
){
- Text("从列表中移除")
+ Text("移除")
}
}
}
@@ -370,7 +399,7 @@ fun DeviceOwnerInfo(
fm.clearFocus()
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
},
- modifier = if(isWear){Modifier.fillMaxWidth(0.48F)}else{Modifier.fillMaxWidth(0.6F)}
+ modifier = if(isWear){Modifier.fillMaxWidth(0.49F)}else{Modifier.fillMaxWidth(0.6F)}
) {
Text(text = "应用")
}
@@ -381,7 +410,7 @@ fun DeviceOwnerInfo(
fm.clearFocus()
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
},
- modifier = Modifier.fillMaxWidth(0.95F)
+ modifier = Modifier.fillMaxWidth(0.96F)
) {
Text(text = "重置")
}
diff --git a/app/src/main/java/com/binbin/androidowner/User.kt b/app/src/main/java/com/binbin/androidowner/User.kt
index f73c0a2..6fee3b8 100644
--- a/app/src/main/java/com/binbin/androidowner/User.kt
+++ b/app/src/main/java/com/binbin/androidowner/User.kt
@@ -192,43 +192,6 @@ fun UserManage(navCtrl:NavHostController){
}
}
- Column(modifier = sections()) {
- Text(text = "工作资料", style = typography.titleLarge)
- if(VERSION.SDK_INT>=24){Text(text = "可以创建工作资料:${myDpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)}", style = bodyTextStyle)}
- if(isDeviceOwner(myDpm)){Text(text = "Device owner不能创建工作资料", style = bodyTextStyle)}
- if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE))){
- var skipEncrypt by remember{mutableStateOf(false)}
- if(VERSION.SDK_INT>=24){CheckBoxItem("跳过加密",{skipEncrypt},{skipEncrypt=!skipEncrypt})}
- Button(
- onClick = {
- val intent = Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)
- if(VERSION.SDK_INT>=23){
- intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,myComponent)
- }else{
- intent.putExtra(DevicePolicyManager.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)}
- createManagedProfile.launch(intent)
- },
- modifier = Modifier.fillMaxWidth()
- ) {
- Text("创建")
- }
- }
- if(isProfileOwner(myDpm)){
- Button(
- onClick = {
- myDpm.setProfileEnabled(myComponent)
- Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
- },
- modifier = Modifier.fillMaxWidth()
- ) {
- Text(text = "启用")
- }
- }
- }
-
if(VERSION.SDK_INT>=24){
Column(modifier = sections()) {
var userName by remember{ mutableStateOf("") }
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8033fe6..4c1e85e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -122,4 +122,5 @@
网络
功能开发中
WiFi锁定
+ 工作资料