mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
lock task features
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_INPUT_METHODS"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_CREDENTIALS"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_APPS_CONTROL"/>
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES"/>
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"/>
|
||||||
<application
|
<application
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.content.Context
|
|||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -25,9 +26,9 @@ import androidx.compose.ui.res.painterResource
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
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.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import java.lang.IllegalArgumentException
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DeviceControl(){
|
fun DeviceControl(){
|
||||||
@@ -201,6 +202,126 @@ fun DeviceControl(){
|
|||||||
Text(text = "Wifi安全等级需API33", modifier = Modifier.padding(vertical = 3.dp))
|
Text(text = "Wifi安全等级需API33", modifier = Modifier.padding(vertical = 3.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(VERSION.SDK_INT>=28&&isDeviceOwner(myDpm)){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
val lockTaskPolicyList = mutableListOf(
|
||||||
|
LOCK_TASK_FEATURE_NONE,
|
||||||
|
LOCK_TASK_FEATURE_SYSTEM_INFO,
|
||||||
|
LOCK_TASK_FEATURE_NOTIFICATIONS,
|
||||||
|
LOCK_TASK_FEATURE_HOME,
|
||||||
|
LOCK_TASK_FEATURE_OVERVIEW,
|
||||||
|
LOCK_TASK_FEATURE_GLOBAL_ACTIONS,
|
||||||
|
LOCK_TASK_FEATURE_KEYGUARD
|
||||||
|
)
|
||||||
|
var sysInfo by remember{mutableStateOf(false)}
|
||||||
|
var notifications by remember{mutableStateOf(false)}
|
||||||
|
var home by remember{mutableStateOf(false)}
|
||||||
|
var overview by remember{mutableStateOf(false)}
|
||||||
|
var globalAction by remember{mutableStateOf(false)}
|
||||||
|
var keyGuard by remember{mutableStateOf(false)}
|
||||||
|
var blockAct by remember{mutableStateOf(false)}
|
||||||
|
if(VERSION.SDK_INT>=30){lockTaskPolicyList.add(LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK)}
|
||||||
|
val refreshFeature = {
|
||||||
|
var calculate = myDpm.getLockTaskFeatures(myComponent)
|
||||||
|
if(VERSION.SDK_INT>=30&&calculate-lockTaskPolicyList[7]>=0){blockAct=true;calculate-=lockTaskPolicyList[7]}
|
||||||
|
if(calculate-lockTaskPolicyList[6]>=0){keyGuard=true;calculate-=lockTaskPolicyList[6]}
|
||||||
|
if(calculate-lockTaskPolicyList[5]>=0){globalAction=true;calculate-=lockTaskPolicyList[5]}
|
||||||
|
if(calculate-lockTaskPolicyList[4]>=0){overview=true;calculate-=lockTaskPolicyList[4]}
|
||||||
|
if(calculate-lockTaskPolicyList[3]>=0){home=true;calculate-=lockTaskPolicyList[3]}
|
||||||
|
if(calculate-lockTaskPolicyList[2]>=0){notifications=true;calculate-=lockTaskPolicyList[2]}
|
||||||
|
if(calculate-lockTaskPolicyList[1]>=0){sysInfo=true;calculate-=lockTaskPolicyList[1]}
|
||||||
|
}
|
||||||
|
Text(text = "锁定任务模式", style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
|
||||||
|
var inited by remember{mutableStateOf(false)}
|
||||||
|
var custom by remember{mutableStateOf(false)}
|
||||||
|
if(!inited){ refreshFeature();custom=myDpm.getLockTaskFeatures(myComponent)!=0;inited=true }
|
||||||
|
Text(text = "在锁定任务模式下:", style = bodyTextStyle)
|
||||||
|
RadioButtonItem("禁用全部",{!custom},{custom=false})
|
||||||
|
RadioButtonItem("自定义",{custom},{custom=true})
|
||||||
|
AnimatedVisibility(custom) {
|
||||||
|
Column {
|
||||||
|
CheckBoxItem("允许状态栏信息",{sysInfo},{sysInfo=!sysInfo})
|
||||||
|
CheckBoxItem("允许通知",{notifications},{notifications=!notifications})
|
||||||
|
CheckBoxItem("允许返回主屏幕",{home},{home=!home})
|
||||||
|
CheckBoxItem("允许打开后台应用概览",{overview},{overview=!overview})
|
||||||
|
CheckBoxItem("允许全局行为(比如长按电源键对话框)",{globalAction},{globalAction=!globalAction})
|
||||||
|
CheckBoxItem("允许锁屏(如果没有选择此项,即使有密码也不会锁屏)",{keyGuard},{keyGuard=!keyGuard})
|
||||||
|
if(VERSION.SDK_INT>=30){ CheckBoxItem("阻止启动未允许的应用",{blockAct},{blockAct=!blockAct}) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
onClick = {
|
||||||
|
var result = lockTaskPolicyList[0]
|
||||||
|
if(custom){
|
||||||
|
if(blockAct&&VERSION.SDK_INT>=30){result+=lockTaskPolicyList[7]}
|
||||||
|
if(keyGuard){result+=lockTaskPolicyList[6]}
|
||||||
|
if(globalAction){result+=lockTaskPolicyList[5]}
|
||||||
|
if(overview){result+=lockTaskPolicyList[4]}
|
||||||
|
if(home){result+=lockTaskPolicyList[3]}
|
||||||
|
if(notifications){result+=lockTaskPolicyList[2]}
|
||||||
|
if(sysInfo){result+=lockTaskPolicyList[1]}
|
||||||
|
}
|
||||||
|
myDpm.setLockTaskFeatures(myComponent,result)
|
||||||
|
refreshFeature()
|
||||||
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text("应用")
|
||||||
|
}
|
||||||
|
Spacer(Modifier.padding(vertical = 4.dp))
|
||||||
|
val whitelist = myDpm.getLockTaskPackages(myComponent).toMutableList()
|
||||||
|
var listText by remember{mutableStateOf("")}
|
||||||
|
var inputPkg by remember{mutableStateOf("")}
|
||||||
|
val refreshWhitelist = {
|
||||||
|
listText=""
|
||||||
|
var currentItem = whitelist.size
|
||||||
|
for(each in whitelist){
|
||||||
|
currentItem-=1
|
||||||
|
listText += each
|
||||||
|
if(currentItem>0){listText += "\n"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
refreshWhitelist()
|
||||||
|
Text(text = "白名单应用", style = typography.titleLarge)
|
||||||
|
if(listText!=""){ Text(listText) }else{ Text(("无")) }
|
||||||
|
TextField(
|
||||||
|
value = inputPkg,
|
||||||
|
onValueChange = {inputPkg=it},
|
||||||
|
label = {Text("包名")},
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
whitelist.add(inputPkg)
|
||||||
|
myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray())
|
||||||
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
refreshWhitelist()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("加入白名单")
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
if(inputPkg in whitelist){
|
||||||
|
whitelist.remove(inputPkg)
|
||||||
|
myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray())
|
||||||
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
}else{
|
||||||
|
Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
refreshWhitelist()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("从白名单中移除")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=29&&isDeviceOwner(myDpm)){
|
if(VERSION.SDK_INT>=29&&isDeviceOwner(myDpm)){
|
||||||
Column(modifier = sections()){
|
Column(modifier = sections()){
|
||||||
Text(text = "私人DNS", style = typography.titleLarge)
|
Text(text = "私人DNS", style = typography.titleLarge)
|
||||||
@@ -245,6 +366,8 @@ fun DeviceControl(){
|
|||||||
Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show()
|
||||||
}catch(e:IllegalArgumentException){
|
}catch(e:IllegalArgumentException){
|
||||||
Toast.makeText(myContext, "无效主机名", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "无效主机名", Toast.LENGTH_SHORT).show()
|
||||||
|
}catch(e:SecurityException){
|
||||||
|
Toast.makeText(myContext, "安全错误", Toast.LENGTH_SHORT).show()
|
||||||
}finally {
|
}finally {
|
||||||
status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)]
|
status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,13 @@ import android.annotation.SuppressLint
|
|||||||
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.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -34,12 +38,21 @@ import androidx.navigation.compose.currentBackStackEntryAsState
|
|||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.binbin.androidowner.ui.theme.AndroidOwnerTheme
|
import com.binbin.androidowner.ui.theme.AndroidOwnerTheme
|
||||||
|
|
||||||
|
/*lateinit var getOtaPackage: ActivityResultLauncher<Intent>
|
||||||
|
var installOta = false
|
||||||
|
lateinit var otaUri:Uri*/
|
||||||
|
|
||||||
@ExperimentalMaterial3Api
|
@ExperimentalMaterial3Api
|
||||||
class MainActivity : ComponentActivity() {
|
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)
|
||||||
|
/*otaUri = Uri.EMPTY
|
||||||
|
getOtaPackage = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
val data = it.data?.data
|
||||||
|
installOta = true
|
||||||
|
otaUri = data ?: Uri.EMPTY
|
||||||
|
}*/
|
||||||
setContent {
|
setContent {
|
||||||
AndroidOwnerTheme {
|
AndroidOwnerTheme {
|
||||||
MyScaffold()
|
MyScaffold()
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.binbin.androidowner
|
package com.binbin.androidowner
|
||||||
|
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
|
import android.app.admin.DevicePolicyManager.InstallSystemUpdateCallback
|
||||||
import android.app.admin.SystemUpdateInfo
|
import android.app.admin.SystemUpdateInfo
|
||||||
import android.app.admin.SystemUpdatePolicy
|
import android.app.admin.SystemUpdatePolicy
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build.VERSION
|
import android.os.Build.VERSION
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
@@ -23,6 +26,7 @@ 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.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SysUpdatePolicy(){
|
fun SysUpdatePolicy(){
|
||||||
@@ -30,21 +34,24 @@ fun SysUpdatePolicy(){
|
|||||||
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)
|
||||||
val focusMgr = LocalFocusManager.current
|
val focusMgr = LocalFocusManager.current
|
||||||
|
val sharedPref = myContext.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
|
val bodyTextStyle = if(isWear){ typography.bodyMedium}else{typography.bodyLarge}
|
||||||
Column {
|
Column {
|
||||||
if(VERSION.SDK_INT>=26){
|
if(VERSION.SDK_INT>=26&&isDeviceOwner(myDpm)){
|
||||||
|
val sysUpdateInfo = myDpm.getPendingSystemUpdate(myComponent)
|
||||||
Column(modifier = sections()) {
|
Column(modifier = sections()) {
|
||||||
val sysUpdateInfo = if(isDeviceOwner(myDpm)){myDpm.getPendingSystemUpdate(myComponent)}else{null}
|
|
||||||
if(sysUpdateInfo!=null){
|
if(sysUpdateInfo!=null){
|
||||||
Text("Update first available: ${Date(sysUpdateInfo.receivedTime)}")
|
Text(text = "Update first available: ${Date(sysUpdateInfo.receivedTime)}", style = bodyTextStyle)
|
||||||
Text("Hash code: ${sysUpdateInfo.hashCode()}")
|
Text(text = "Hash code: ${sysUpdateInfo.hashCode()}", style = bodyTextStyle)
|
||||||
val securityStateDesc = when(sysUpdateInfo.securityPatchState){
|
val securityStateDesc = when(sysUpdateInfo.securityPatchState){
|
||||||
SystemUpdateInfo.SECURITY_PATCH_STATE_UNKNOWN->"SECURITY_PATCH_STATE_UNKNOWN"
|
SystemUpdateInfo.SECURITY_PATCH_STATE_UNKNOWN->"SECURITY_PATCH_STATE_UNKNOWN"
|
||||||
SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE->"SECURITY_PATCH_STATE_TRUE"
|
SystemUpdateInfo.SECURITY_PATCH_STATE_TRUE->"SECURITY_PATCH_STATE_TRUE"
|
||||||
else->"SECURITY_PATCH_STATE_FALSE"
|
else->"SECURITY_PATCH_STATE_FALSE"
|
||||||
}
|
}
|
||||||
Text("Security patch state: $securityStateDesc")
|
Text(text = "Security patch state: $securityStateDesc", style = bodyTextStyle)
|
||||||
}else{
|
}else{
|
||||||
Text("暂无更新信息")
|
Text(text = "暂无系统更新", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +87,7 @@ fun SysUpdatePolicy(){
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.padding(vertical = 3.dp))
|
Spacer(Modifier.padding(vertical = 3.dp))
|
||||||
Text("请输入一天中的分钟(0~1440)")
|
Text(text = "请输入一天中的分钟(0~1440)", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
val policy =
|
val policy =
|
||||||
when(selectedPolicy){
|
when(selectedPolicy){
|
||||||
@@ -97,5 +104,43 @@ fun SysUpdatePolicy(){
|
|||||||
Text("应用")
|
Text("应用")
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
/*if(VERSION.SDK_INT>=29){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
var resultUri by remember{mutableStateOf(otaUri)}
|
||||||
|
Text(text = "安装系统更新", style = typography.titleLarge)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val getUri = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
|
getUri.setType("application/zip")
|
||||||
|
getUri.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
getOtaPackage.launch(getUri)
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm)
|
||||||
|
) {
|
||||||
|
Text("选择OTA包")
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {resultUri = otaUri},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm)
|
||||||
|
) {
|
||||||
|
Text("查看OTA包详情")
|
||||||
|
}
|
||||||
|
Text("URI: $resultUri")
|
||||||
|
if(installOta){
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val sysUpdateExecutor = Executors.newCachedThreadPool()
|
||||||
|
val sysUpdateCallback:InstallSystemUpdateCallback = InstallSystemUpdateCallback
|
||||||
|
myDpm.installSystemUpdate(myComponent,resultUri,sysUpdateExecutor,sysUpdateCallback)
|
||||||
|
},
|
||||||
|
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm)
|
||||||
|
){
|
||||||
|
Text("安装")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user