mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-27 04:16:00 +00:00
massive work profile features
This commit is contained in:
@@ -58,7 +58,6 @@
|
|||||||
|
|
||||||
### 即将加入的功能
|
### 即将加入的功能
|
||||||
|
|
||||||
- Managed Profile,工作资料和多用户相关
|
|
||||||
- ~~应用管理:安装/卸载应用~~(暂不考虑)
|
- ~~应用管理:安装/卸载应用~~(暂不考虑)
|
||||||
- 应用管理:包选择器(目前只能手动输入包名)
|
- 应用管理:包选择器(目前只能手动输入包名)
|
||||||
- 应用管理:应用权限选择器
|
- 应用管理:应用权限选择器
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_KEYGUARD"/>
|
||||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
|
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIPE_DATA"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_ACROSS_USERS"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_RESET_PASSWORD"/>
|
||||||
@@ -16,6 +15,7 @@
|
|||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_RUNTIME_PERMISSIONS"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_ORGANIZATION_IDENTITY"/>
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_PROFILE_INTERACTION"/>
|
||||||
<application
|
<application
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
@@ -24,7 +24,6 @@
|
|||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:theme="@style/Theme.AndroidOwner"
|
android:theme="@style/Theme.AndroidOwner"
|
||||||
android:enableOnBackInvokedCallback="true"
|
android:enableOnBackInvokedCallback="true"
|
||||||
android:allowNativeHeapPointerTagging="true"
|
|
||||||
tools:targetApi="34">
|
tools:targetApi="34">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@@ -37,6 +36,7 @@
|
|||||||
<action android:name="android.app.action.PROVISION_MANAGED_PROFILE"/>
|
<action android:name="android.app.action.PROVISION_MANAGED_PROFILE"/>
|
||||||
<action android:name="android.app.action.MANAGED_PROFILE_PROVISIONED"/>
|
<action android:name="android.app.action.MANAGED_PROFILE_PROVISIONED"/>
|
||||||
<action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
|
<action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
|
||||||
|
<action android:name="com.binbin.androidowner.MAIN_ACTION"/>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|||||||
@@ -36,11 +36,13 @@ import androidx.compose.ui.platform.LocalFocusManager
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.ContextCompat.startActivity
|
import androidx.core.content.ContextCompat.startActivity
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
private var credentialList = mutableSetOf<String>()
|
private var credentialList = mutableSetOf<String>()
|
||||||
|
private var crossProfilePkg = mutableSetOf<String>()
|
||||||
@Composable
|
@Composable
|
||||||
fun ApplicationManage(){
|
fun ApplicationManage(){
|
||||||
val myContext = LocalContext.current
|
val myContext = LocalContext.current
|
||||||
@@ -75,6 +77,9 @@ fun ApplicationManage(){
|
|||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
|
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))){
|
if(VERSION.SDK_INT>=24&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
||||||
AppManageItem(
|
AppManageItem(
|
||||||
R.string.suspend,R.string.place_holder,
|
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<String>
|
||||||
|
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)){
|
if(VERSION.SDK_INT>=34&&isDeviceOwner(myDpm)){
|
||||||
var policy:PackagePolicy?
|
var policy:PackagePolicy?
|
||||||
var policyType by remember{mutableIntStateOf(-1)}
|
var policyType by remember{mutableIntStateOf(-1)}
|
||||||
|
|||||||
@@ -22,9 +22,7 @@ import androidx.compose.material.icons.outlined.ArrowBack
|
|||||||
import androidx.compose.material.icons.outlined.Home
|
import androidx.compose.material.icons.outlined.Home
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -97,6 +95,9 @@ fun MyScaffold(){
|
|||||||
val focusMgr = LocalFocusManager.current
|
val focusMgr = LocalFocusManager.current
|
||||||
val navCtrl = rememberNavController()
|
val navCtrl = rememberNavController()
|
||||||
val backStackEntry by navCtrl.currentBackStackEntryAsState()
|
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(
|
val topBarNameMap = mapOf(
|
||||||
"HomePage" to R.string.app_name,
|
"HomePage" to R.string.app_name,
|
||||||
"DeviceControl" to R.string.device_ctrl,
|
"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(
|
NavHost(
|
||||||
navController = navCtrl,
|
navController = navCtrl,
|
||||||
startDestination = "HomePage",
|
startDestination = "HomePage",
|
||||||
@@ -162,7 +166,7 @@ fun MyScaffold(){
|
|||||||
){
|
){
|
||||||
composable(route = "HomePage", content = { HomePage(navCtrl)})
|
composable(route = "HomePage", content = { HomePage(navCtrl)})
|
||||||
composable(route = "DeviceControl", content = { DeviceControl()})
|
composable(route = "DeviceControl", content = { DeviceControl()})
|
||||||
composable(route = "ManagedProfile", content = {ManagedProfile(navCtrl)})
|
composable(route = "ManagedProfile", content = {ManagedProfile()})
|
||||||
composable(route = "Permissions", content = { DpmPermissions(navCtrl)})
|
composable(route = "Permissions", content = { DpmPermissions(navCtrl)})
|
||||||
composable(route = "ApplicationManage", content = { ApplicationManage()})
|
composable(route = "ApplicationManage", content = { ApplicationManage()})
|
||||||
composable(route = "UserRestriction", content = { UserRestriction()})
|
composable(route = "UserRestriction", content = { UserRestriction()})
|
||||||
@@ -170,7 +174,9 @@ fun MyScaffold(){
|
|||||||
composable(route = "Password", content = { Password()})
|
composable(route = "Password", content = { Password()})
|
||||||
composable(route = "AppSetting", content = { AppSetting(navCtrl)})
|
composable(route = "AppSetting", content = { AppSetting(navCtrl)})
|
||||||
composable(route = "Network", content = {Network()})
|
composable(route = "Network", content = {Network()})
|
||||||
|
composable(route = "ActivateManagedProfile", content = {ActivateManagedProfile(navCtrl)})
|
||||||
}
|
}
|
||||||
|
if(!inited&&jumpToActivateProfile){navCtrl.navigate("ActivateManagedProfile");inited=true}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
package com.binbin.androidowner
|
package com.binbin.androidowner
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager
|
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.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.content.pm.PackageInstaller
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Parcelable
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextField
|
import androidx.compose.material3.TextField
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
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,7 +34,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ManagedProfile(navCtrl:NavHostController){
|
fun ManagedProfile() {
|
||||||
val myContext = LocalContext.current
|
val myContext = LocalContext.current
|
||||||
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||||
val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java)
|
val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java)
|
||||||
@@ -41,37 +43,67 @@ fun ManagedProfile(navCtrl:NavHostController){
|
|||||||
val isWear = sharedPref.getBoolean("isWear",false)
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
val bodyTextStyle = if(isWear){ typography.bodyMedium}else{ typography.bodyLarge}
|
val bodyTextStyle = if(isWear){ typography.bodyMedium}else{ typography.bodyLarge}
|
||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())){
|
Column(modifier = Modifier.verticalScroll(rememberScrollState())){
|
||||||
|
|
||||||
Column(modifier = sections()){
|
Column(modifier = sections()){
|
||||||
Text(text = "信息", style = typography.titleLarge)
|
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(VERSION.SDK_INT>=24){
|
||||||
if(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
|
if(isProfileOwner(myDpm)&&myDpm.isManagedProfile(myComponent)){
|
||||||
Text(text = "已是工作资料")
|
Text(text = "已是工作资料")
|
||||||
}else{
|
}else{
|
||||||
Text(text = "可以创建工作资料:${myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)}", style = bodyTextStyle)
|
Text(text = "可以创建工作资料:${myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE)}", style = bodyTextStyle)
|
||||||
}
|
|
||||||
}
|
|
||||||
if(isDeviceOwner(myDpm)){
|
if(isDeviceOwner(myDpm)){
|
||||||
Text(text = "Device owner不能创建工作资料", style = bodyTextStyle)
|
Text(text = "Device owner不能创建工作资料", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT<24||(VERSION.SDK_INT>=24&&myDpm.isProvisioningAllowed(ACTION_PROVISION_MANAGED_PROFILE))){
|
}
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT>=30){
|
||||||
|
Text(text = "由组织拥有的工作资料:${myDpm.isOrganizationOwnedDeviceWithManagedProfile}", style = bodyTextStyle)
|
||||||
|
}
|
||||||
|
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)}
|
var skipEncrypt by remember{mutableStateOf(false)}
|
||||||
if(VERSION.SDK_INT>=24){CheckBoxItem("跳过加密",{skipEncrypt},{skipEncrypt=!skipEncrypt})}
|
if(VERSION.SDK_INT>=24){CheckBoxItem("跳过加密",{skipEncrypt},{skipEncrypt=!skipEncrypt})}
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
val intent = Intent(ACTION_PROVISION_MANAGED_PROFILE)
|
val intent = Intent(ACTION_PROVISION_MANAGED_PROFILE)
|
||||||
if(VERSION.SDK_INT>=23){
|
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{
|
}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>=24){intent.putExtra(EXTRA_PROVISIONING_SKIP_ENCRYPTION,skipEncrypt)}
|
||||||
if(VERSION.SDK_INT>=33){intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_ALLOW_OFFLINE,true)}
|
if(VERSION.SDK_INT>=33){intent.putExtra(EXTRA_PROVISIONING_ALLOW_OFFLINE,true)}
|
||||||
createManagedProfile.launch(intent)
|
createManagedProfile.launch(intent)
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
@@ -79,17 +111,20 @@ fun ManagedProfile(navCtrl:NavHostController){
|
|||||||
Text("创建")
|
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("")}
|
var time by remember{mutableStateOf("")}
|
||||||
time = myDpm.getManagedProfileMaximumTimeOff(myComponent).toString()
|
time = myDpm.getManagedProfileMaximumTimeOff(myComponent).toString()
|
||||||
Text(text = "资料关闭时间", style = typography.titleLarge)
|
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(
|
TextField(
|
||||||
value = time, onValueChange = {time=it}, modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp),
|
value = time, onValueChange = {time=it}, modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp),
|
||||||
label = {Text("时间(ms)")},
|
label = {Text("时间(ms)")},
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()})
|
||||||
)
|
)
|
||||||
Text(text = "不能少于72小时")
|
Text(text = "不能少于72小时", style = bodyTextStyle)
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
myDpm.setManagedProfileMaximumTimeOff(myComponent,time.toLong())
|
myDpm.setManagedProfileMaximumTimeOff(myComponent,time.toLong())
|
||||||
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
}
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text("应用")
|
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))
|
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("激活")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ fun Password(){
|
|||||||
}else{ Toast.makeText(myContext, "清除失败", Toast.LENGTH_SHORT).show() }
|
}else{ Toast.makeText(myContext, "清除失败", Toast.LENGTH_SHORT).show() }
|
||||||
},
|
},
|
||||||
modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.32F)},
|
modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.32F)},
|
||||||
enabled = isDeviceOwner(myDpm)
|
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm)
|
||||||
) {
|
) {
|
||||||
Text("清除")
|
Text("清除")
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ fun Password(){
|
|||||||
Toast.makeText(myContext, "失败(安全异常)", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "失败(安全异常)", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
enabled = isDeviceOwner(myDpm),
|
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm),
|
||||||
modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.47F)}
|
modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.47F)}
|
||||||
) {
|
) {
|
||||||
Text("设置")
|
Text("设置")
|
||||||
@@ -129,7 +129,7 @@ fun Password(){
|
|||||||
}catch(e:NullPointerException){ Toast.makeText(myContext, "请先设置令牌", Toast.LENGTH_SHORT).show() }
|
}catch(e:NullPointerException){ Toast.makeText(myContext, "请先设置令牌", Toast.LENGTH_SHORT).show() }
|
||||||
}else{ 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)}
|
modifier = if(isWear){Modifier}else{Modifier.fillMaxWidth(0.88F)}
|
||||||
) {
|
) {
|
||||||
Text("激活")
|
Text("激活")
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.platform.LocalFocusManager
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
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.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
|
||||||
@@ -223,12 +222,9 @@ fun DpmPermissions(navCtrl:NavHostController){
|
|||||||
Text(text = "设备唯一标识码", style = typography.titleLarge,color = titleColor)
|
Text(text = "设备唯一标识码", style = typography.titleLarge,color = titleColor)
|
||||||
Text("(恢复出厂设置不变)",style=bodyTextStyle)
|
Text("(恢复出厂设置不变)",style=bodyTextStyle)
|
||||||
if(specificId!=""){
|
if(specificId!=""){
|
||||||
Text(specificId)
|
SelectionContainer{ Text(specificId, style = bodyTextStyle) }
|
||||||
Button(onClick = {myDpm.setOrganizationId(specificId)}) {
|
|
||||||
Text("设置为组织ID")
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
Text("你的设备不支持",style=bodyTextStyle)
|
Text("需要设置组织ID",style=bodyTextStyle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -249,6 +245,7 @@ fun DpmPermissions(navCtrl:NavHostController){
|
|||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
focusManager.clearFocus()
|
||||||
myDpm.setOrganizationName(myComponent,orgName)
|
myDpm.setOrganizationName(myComponent,orgName)
|
||||||
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ private data class Restriction(
|
|||||||
fun UserRestriction(){
|
fun UserRestriction(){
|
||||||
val myContext = LocalContext.current
|
val myContext = LocalContext.current
|
||||||
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||||
|
val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java)
|
||||||
var internetVisible by remember{ mutableStateOf(false) }
|
var internetVisible by remember{ mutableStateOf(false) }
|
||||||
var connectivityVisible by remember{ mutableStateOf(false) }
|
var connectivityVisible by remember{ mutableStateOf(false) }
|
||||||
var applicationVisible by remember{ mutableStateOf(false) }
|
var applicationVisible by remember{ mutableStateOf(false) }
|
||||||
@@ -53,13 +54,16 @@ fun UserRestriction(){
|
|||||||
val isWear = sharedPref.getBoolean("isWear",false)
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
val bodyTextStyle = if(isWear){typography.bodyMedium}else{typography.bodyLarge}
|
val bodyTextStyle = if(isWear){typography.bodyMedium}else{typography.bodyLarge}
|
||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState()), horizontalAlignment = Alignment.CenterHorizontally){
|
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){
|
if(VERSION.SDK_INT<24){
|
||||||
Text(text = "所有的用户限制都需要API24,你的设备低于API24,无法使用。", style = bodyTextStyle, color = colorScheme.error)
|
Text(text = "所有的用户限制都需要API24,你的设备低于API24,无法使用。", style = bodyTextStyle, color = colorScheme.error)
|
||||||
}
|
}
|
||||||
if(isProfileOwner(myDpm)){
|
if(isProfileOwner(myDpm)){
|
||||||
Text(text = "Profile owner无法使用部分功能", style = bodyTextStyle)
|
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){
|
if(isWear){
|
||||||
Text(text = "部分功能在手表上无效", style = typography.bodyMedium)
|
Text(text = "部分功能在手表上无效", style = typography.bodyMedium)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user