mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-23 19:15:58 +00:00
Add a separate Network page
This commit is contained in:
@@ -13,10 +13,12 @@
|
|||||||
适配了一些预见式返回动画(需安卓13或14),可能不太稳定,如果有问题请向我反馈
|
适配了一些预见式返回动画(需安卓13或14),可能不太稳定,如果有问题请向我反馈
|
||||||
|
|
||||||
- 设备控制
|
- 设备控制
|
||||||
|
- 重启、锁屏
|
||||||
- 禁用相机
|
- 禁用相机
|
||||||
- 禁止截屏
|
- 禁止截屏
|
||||||
- 全局静音
|
- 全局静音
|
||||||
- 关闭USB信号(需设备支持)
|
- 关闭USB信号(需设备支持)
|
||||||
|
- 设置时间
|
||||||
- 管理系统更新策略
|
- 管理系统更新策略
|
||||||
- 清除数据
|
- 清除数据
|
||||||
- 管理应用
|
- 管理应用
|
||||||
@@ -49,9 +51,9 @@
|
|||||||
### 即将加入的功能
|
### 即将加入的功能
|
||||||
|
|
||||||
- Managed Profile,工作资料和多用户相关
|
- Managed Profile,工作资料和多用户相关
|
||||||
- 应用管理--安装/卸载应用
|
- ~~应用管理:安装/卸载应用~~(暂不考虑)
|
||||||
- 应用管理--包选择器(目前只能手动输入包名)
|
- 应用管理:包选择器(目前只能手动输入包名)
|
||||||
- 用户管理--用户选择器(目前只能手动输入序列号)
|
- 用户管理:用户选择器(目前只能手动输入序列号)
|
||||||
|
|
||||||
### 许可证
|
### 许可证
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ android {
|
|||||||
applicationId = "com.binbin.androidowner"
|
applicationId = "com.binbin.androidowner"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 10
|
versionCode = 11
|
||||||
versionName = "2.3"
|
versionName = "2.4"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<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_SYSTEM_UPDATES"/>
|
||||||
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"/>
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_LOCK_TASK"/>
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_WIFI"/>
|
||||||
<application
|
<application
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
|||||||
@@ -2,10 +2,8 @@ package com.binbin.androidowner
|
|||||||
|
|
||||||
import android.app.admin.DevicePolicyManager
|
import android.app.admin.DevicePolicyManager
|
||||||
import android.app.admin.DevicePolicyManager.*
|
import android.app.admin.DevicePolicyManager.*
|
||||||
import android.app.admin.WifiSsidPolicy
|
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.wifi.WifiSsid
|
|
||||||
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
|
||||||
@@ -82,21 +80,11 @@ fun DeviceControl(){
|
|||||||
{myDpm.getBluetoothContactSharingDisabled(myComponent)},{b -> myDpm.setBluetoothContactSharingDisabled(myComponent,b)}
|
{myDpm.getBluetoothContactSharingDisabled(myComponent)},{b -> myDpm.setBluetoothContactSharingDisabled(myComponent,b)}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
|
||||||
DeviceCtrlItem(R.string.network_logging,R.string.no_effect,R.drawable.wifi_fill0,
|
|
||||||
{myDpm.isNetworkLoggingEnabled(myComponent)},{b -> myDpm.setNetworkLoggingEnabled(myComponent,b) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if(VERSION.SDK_INT>=24&&isDeviceOwner(myDpm)){
|
if(VERSION.SDK_INT>=24&&isDeviceOwner(myDpm)){
|
||||||
DeviceCtrlItem(R.string.secure_logging,R.string.no_effect,R.drawable.description_fill0,
|
DeviceCtrlItem(R.string.secure_logging,R.string.no_effect,R.drawable.description_fill0,
|
||||||
{myDpm.isSecurityLoggingEnabled(myComponent)},{b -> myDpm.setSecurityLoggingEnabled(myComponent,b) }
|
{myDpm.isSecurityLoggingEnabled(myComponent)},{b -> myDpm.setSecurityLoggingEnabled(myComponent,b) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT>=33&&isDeviceOwner(myDpm)){
|
|
||||||
DeviceCtrlItem(R.string.preferential_network_service,R.string.no_effect,R.drawable.globe_fill0,
|
|
||||||
{myDpm.isPreferentialNetworkServiceEnabled},{b -> myDpm.isPreferentialNetworkServiceEnabled = b}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if(VERSION.SDK_INT>=30&&isDeviceOwner(myDpm)){
|
if(VERSION.SDK_INT>=30&&isDeviceOwner(myDpm)){
|
||||||
DeviceCtrlItem(R.string.common_criteria_mode,R.string.common_criteria_mode_desc,R.drawable.security_fill0,
|
DeviceCtrlItem(R.string.common_criteria_mode,R.string.common_criteria_mode_desc,R.drawable.security_fill0,
|
||||||
{myDpm.isCommonCriteriaModeEnabled(myComponent)},{b -> myDpm.setCommonCriteriaModeEnabled(myComponent,b)}
|
{myDpm.isCommonCriteriaModeEnabled(myComponent)},{b -> myDpm.setCommonCriteriaModeEnabled(myComponent,b)}
|
||||||
@@ -156,11 +144,6 @@ fun DeviceControl(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT<24){ Text(text = "重启和WiFi Mac需要API24",modifier=Modifier.fillMaxWidth(), textAlign = TextAlign.Center, style = bodyTextStyle) }
|
|
||||||
if(VERSION.SDK_INT>=24){
|
|
||||||
val wifimac = try { myDpm.getWifiMacAddress(myComponent).toString() }catch(e:SecurityException){ "没有权限" }
|
|
||||||
Text(text = "WiFi MAC: $wifimac",modifier=Modifier.fillMaxWidth(), textAlign = TextAlign.Center,style=bodyTextStyle)
|
|
||||||
}
|
|
||||||
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
if(isDeviceOwner(myDpm)||isProfileOwner(myDpm)){
|
||||||
Button(
|
Button(
|
||||||
onClick = {myDpm.uninstallAllUserCaCerts(myComponent);Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()},
|
onClick = {myDpm.uninstallAllUserCaCerts(myComponent);Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()},
|
||||||
@@ -173,7 +156,7 @@ fun DeviceControl(){
|
|||||||
Column(modifier = sections()){
|
Column(modifier = sections()){
|
||||||
Text(text = "修改时间", style = typography.titleLarge)
|
Text(text = "修改时间", style = typography.titleLarge)
|
||||||
var inputTime by remember{mutableStateOf("")}
|
var inputTime by remember{mutableStateOf("")}
|
||||||
Text(text = "从epoch(1970/1/1 00:00:00 UTC)到现在(毫秒)")
|
Text(text = "从Epoch(1970/1/1 00:00:00 UTC)到你想设置的时间(毫秒)", style = bodyTextStyle)
|
||||||
TextField(
|
TextField(
|
||||||
value = inputTime,
|
value = inputTime,
|
||||||
label = { Text("时间(ms)")},
|
label = { Text("时间(ms)")},
|
||||||
@@ -236,29 +219,6 @@ fun DeviceControl(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=33){
|
|
||||||
Column(modifier = sections()){
|
|
||||||
var selectedWifiSecLevel by remember{mutableIntStateOf(myDpm.minimumRequiredWifiSecurityLevel)}
|
|
||||||
Text(text = "要求最小WiFi安全等级", style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
|
|
||||||
RadioButtonItem("开放", {selectedWifiSecLevel==WIFI_SECURITY_OPEN}, {selectedWifiSecLevel= WIFI_SECURITY_OPEN})
|
|
||||||
RadioButtonItem("WEP, WPA(2)-PSK", {selectedWifiSecLevel==WIFI_SECURITY_PERSONAL}, {selectedWifiSecLevel= WIFI_SECURITY_PERSONAL})
|
|
||||||
RadioButtonItem("WPA-EAP", {selectedWifiSecLevel==WIFI_SECURITY_ENTERPRISE_EAP}, {selectedWifiSecLevel= WIFI_SECURITY_ENTERPRISE_EAP})
|
|
||||||
RadioButtonItem("WPA3-192bit", {selectedWifiSecLevel==WIFI_SECURITY_ENTERPRISE_192}, {selectedWifiSecLevel= WIFI_SECURITY_ENTERPRISE_192})
|
|
||||||
Button(
|
|
||||||
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm),
|
|
||||||
onClick = {
|
|
||||||
myDpm.minimumRequiredWifiSecurityLevel=selectedWifiSecLevel
|
|
||||||
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
){
|
|
||||||
Text("应用")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
Text(text = "Wifi安全等级需API33", modifier = Modifier.padding(vertical = 3.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=28&&isDeviceOwner(myDpm)){
|
if(VERSION.SDK_INT>=28&&isDeviceOwner(myDpm)){
|
||||||
Column(modifier = sections()){
|
Column(modifier = sections()){
|
||||||
val lockTaskPolicyList = mutableListOf(
|
val lockTaskPolicyList = mutableListOf(
|
||||||
@@ -335,6 +295,7 @@ fun DeviceControl(){
|
|||||||
var listText by remember{mutableStateOf("")}
|
var listText by remember{mutableStateOf("")}
|
||||||
var inputPkg by remember{mutableStateOf("")}
|
var inputPkg by remember{mutableStateOf("")}
|
||||||
val refreshWhitelist = {
|
val refreshWhitelist = {
|
||||||
|
inputPkg=""
|
||||||
listText=""
|
listText=""
|
||||||
var currentItem = whitelist.size
|
var currentItem = whitelist.size
|
||||||
for(each in whitelist){
|
for(each in whitelist){
|
||||||
@@ -354,18 +315,18 @@ fun DeviceControl(){
|
|||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp)
|
||||||
)
|
)
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
focusMgr.clearFocus()
|
focusMgr.clearFocus()
|
||||||
whitelist.add(inputPkg)
|
whitelist.add(inputPkg)
|
||||||
myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray())
|
myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray())
|
||||||
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
inputPkg=""
|
|
||||||
refreshWhitelist()
|
refreshWhitelist()
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth(0.49F)
|
||||||
) {
|
) {
|
||||||
Text("加入白名单")
|
Text("添加")
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
@@ -377,71 +338,14 @@ fun DeviceControl(){
|
|||||||
}else{
|
}else{
|
||||||
Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show()
|
Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
inputPkg=""
|
|
||||||
refreshWhitelist()
|
refreshWhitelist()
|
||||||
},
|
},
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth(0.96F)
|
||||||
) {
|
) {
|
||||||
Text("从白名单中移除")
|
Text("移除")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=29&&isDeviceOwner(myDpm)){
|
|
||||||
Column(modifier = sections()){
|
|
||||||
Text(text = "私人DNS", style = typography.titleLarge)
|
|
||||||
val dnsStatus = mapOf(
|
|
||||||
PRIVATE_DNS_MODE_UNKNOWN to "未知",
|
|
||||||
PRIVATE_DNS_MODE_OFF to "关闭",
|
|
||||||
PRIVATE_DNS_MODE_OPPORTUNISTIC to "自动",
|
|
||||||
PRIVATE_DNS_MODE_PROVIDER_HOSTNAME to "指定主机名"
|
|
||||||
)
|
|
||||||
val operationResult = mapOf(
|
|
||||||
PRIVATE_DNS_SET_NO_ERROR to "成功",
|
|
||||||
PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING to "主机不支持DNS over TLS",
|
|
||||||
PRIVATE_DNS_SET_ERROR_FAILURE_SETTING to "失败"
|
|
||||||
)
|
|
||||||
var status by remember{mutableStateOf(dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)])}
|
|
||||||
Text(text = "状态:$status")
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
val result = myDpm.setGlobalPrivateDnsModeOpportunistic(myComponent)
|
|
||||||
Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show()
|
|
||||||
status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)]
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text("设为自动")
|
|
||||||
}
|
|
||||||
Spacer(Modifier.padding(vertical = 3.dp))
|
|
||||||
var inputHost by remember{mutableStateOf(myDpm.getGlobalPrivateDnsHost(myComponent) ?: "")}
|
|
||||||
TextField(
|
|
||||||
value = inputHost,
|
|
||||||
onValueChange = {inputHost=it},
|
|
||||||
label = {Text("DNS主机名")},
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
val result: Int
|
|
||||||
try{
|
|
||||||
result = myDpm.setGlobalPrivateDnsModeSpecifiedHost(myComponent,inputHost)
|
|
||||||
Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show()
|
|
||||||
}catch(e:IllegalArgumentException){
|
|
||||||
Toast.makeText(myContext, "无效主机名", Toast.LENGTH_SHORT).show()
|
|
||||||
}catch(e:SecurityException){
|
|
||||||
Toast.makeText(myContext, "安全错误", Toast.LENGTH_SHORT).show()
|
|
||||||
}finally {
|
|
||||||
status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text("设置DNS主机")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isDeviceOwner(myDpm)){
|
if(isDeviceOwner(myDpm)){
|
||||||
@@ -505,7 +409,7 @@ fun DeviceControl(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun DeviceCtrlItem(
|
fun DeviceCtrlItem(
|
||||||
itemName:Int,
|
itemName:Int,
|
||||||
itemDesc:Int,
|
itemDesc:Int,
|
||||||
leadIcon:Int,
|
leadIcon:Int,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ 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.os.Build.VERSION
|
||||||
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
|
||||||
@@ -67,6 +68,7 @@ fun MyScaffold(){
|
|||||||
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,
|
||||||
|
"Network" to R.string.network,
|
||||||
"Permissions" to R.string.permission,
|
"Permissions" to R.string.permission,
|
||||||
"UserManage" to R.string.user_manage,
|
"UserManage" to R.string.user_manage,
|
||||||
"ApplicationManage" to R.string.app_manage,
|
"ApplicationManage" to R.string.app_manage,
|
||||||
@@ -133,6 +135,7 @@ fun MyScaffold(){
|
|||||||
composable(route = "UserManage", content = { UserManage(navCtrl)})
|
composable(route = "UserManage", content = { UserManage(navCtrl)})
|
||||||
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()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,6 +179,7 @@ fun HomePage(navCtrl:NavHostController){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
HomePageItem(R.string.device_ctrl, R.drawable.mobile_phone_fill0, "DeviceControl", navCtrl)
|
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.app_manage, R.drawable.apps_fill0, "ApplicationManage", 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_restrict, R.drawable.manage_accounts_fill0, "UserRestriction", navCtrl)
|
||||||
HomePageItem(R.string.user_manage,R.drawable.account_circle_fill0,"UserManage",navCtrl)
|
HomePageItem(R.string.user_manage,R.drawable.account_circle_fill0,"UserManage",navCtrl)
|
||||||
|
|||||||
251
app/src/main/java/com/binbin/androidowner/Network.kt
Normal file
251
app/src/main/java/com/binbin/androidowner/Network.kt
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
package com.binbin.androidowner
|
||||||
|
|
||||||
|
import android.app.admin.DevicePolicyManager
|
||||||
|
import android.app.admin.WifiSsidPolicy
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.wifi.WifiSsid
|
||||||
|
import android.os.Build.VERSION
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
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.verticalScroll
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
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.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.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Network(){
|
||||||
|
Column(modifier = Modifier.verticalScroll(rememberScrollState()).fillMaxWidth()){
|
||||||
|
val myContext = LocalContext.current
|
||||||
|
val myDpm = myContext.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
|
||||||
|
val myComponent = ComponentName(myContext,MyDeviceAdminReceiver::class.java)
|
||||||
|
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
|
val bodyTextStyle = if(isWear){ typography.bodyMedium }else{ typography.bodyLarge }
|
||||||
|
val focusMgr = LocalFocusManager.current
|
||||||
|
|
||||||
|
if(VERSION.SDK_INT>=24){
|
||||||
|
val wifimac = try { myDpm.getWifiMacAddress(myComponent).toString() }catch(e:SecurityException){ "没有权限" }
|
||||||
|
Text(text = "WiFi MAC: $wifimac",modifier=Modifier.fillMaxWidth(), textAlign = TextAlign.Center,style=bodyTextStyle)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(VERSION.SDK_INT>=26&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
||||||
|
DeviceCtrlItem(R.string.network_logging,R.string.developing,R.drawable.wifi_fill0,
|
||||||
|
{myDpm.isNetworkLoggingEnabled(myComponent)},{b -> myDpm.setNetworkLoggingEnabled(myComponent,b) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT>=33&&isDeviceOwner(myDpm)){
|
||||||
|
DeviceCtrlItem(R.string.preferential_network_service,R.string.developing,R.drawable.globe_fill0,
|
||||||
|
{myDpm.isPreferentialNetworkServiceEnabled},{b -> myDpm.isPreferentialNetworkServiceEnabled = b}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT>=30){
|
||||||
|
DeviceCtrlItem(R.string.wifi_lockdown,R.string.place_holder,R.drawable.wifi_password_fill0,
|
||||||
|
{myDpm.hasLockdownAdminConfiguredNetworks(myComponent)},{b -> myDpm.setConfiguredNetworksLockdownState(myComponent,b)}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT>=33){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
var selectedWifiSecLevel by remember{mutableIntStateOf(myDpm.minimumRequiredWifiSecurityLevel)}
|
||||||
|
Text(text = "要求最小WiFi安全等级", style = typography.titleLarge, color = colorScheme.onPrimaryContainer)
|
||||||
|
RadioButtonItem("开放", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_OPEN}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_OPEN})
|
||||||
|
RadioButtonItem("WEP, WPA(2)-PSK", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_PERSONAL}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_PERSONAL})
|
||||||
|
RadioButtonItem("WPA-EAP", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_EAP}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_EAP})
|
||||||
|
RadioButtonItem("WPA3-192bit", {selectedWifiSecLevel==DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_192}, {selectedWifiSecLevel= DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_192})
|
||||||
|
Button(
|
||||||
|
enabled = isDeviceOwner(myDpm)||isProfileOwner(myDpm),
|
||||||
|
onClick = {
|
||||||
|
myDpm.minimumRequiredWifiSecurityLevel=selectedWifiSecLevel
|
||||||
|
Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
){
|
||||||
|
Text("应用")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Text(text = "Wifi安全等级需API33", modifier = Modifier.padding(vertical = 3.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
if(VERSION.SDK_INT>=33&&isDeviceOwner(myDpm)){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
var policy = myDpm.wifiSsidPolicy
|
||||||
|
var selectedPolicyType by remember{mutableIntStateOf(policy?.policyType ?: -1)}
|
||||||
|
var inputSsid by remember{mutableStateOf("")}
|
||||||
|
var ssidSet = policy?.ssids ?: mutableSetOf<WifiSsid>()
|
||||||
|
var ssidList by remember{mutableStateOf("")}
|
||||||
|
val refreshList = {
|
||||||
|
policy = myDpm.wifiSsidPolicy
|
||||||
|
selectedPolicyType = policy?.policyType ?: -1
|
||||||
|
ssidSet = policy?.ssids ?: mutableSetOf<WifiSsid>()
|
||||||
|
inputSsid = ""
|
||||||
|
ssidList = ""
|
||||||
|
var count = ssidSet.size
|
||||||
|
for(ssid in ssidSet){
|
||||||
|
count-=1
|
||||||
|
ssidList+=ssid
|
||||||
|
if(count>0){ssidList+="\n"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var inited by remember{mutableStateOf(false)}
|
||||||
|
if(!inited){refreshList(); inited=true}
|
||||||
|
Text(text = "WiFi SSID策略", style = typography.titleLarge)
|
||||||
|
RadioButtonItem("白名单",{selectedPolicyType==WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST},{selectedPolicyType= WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST})
|
||||||
|
RadioButtonItem("黑名单",{selectedPolicyType==WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST},{selectedPolicyType= WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST})
|
||||||
|
Text("SSID列表:")
|
||||||
|
Text(text = if(ssidList!=""){ssidList}else{"无"}, style = bodyTextStyle)
|
||||||
|
TextField(
|
||||||
|
value = inputSsid,
|
||||||
|
label = { Text("SSID")},
|
||||||
|
onValueChange = {inputSsid = it},
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)
|
||||||
|
)
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
focusMgr.clearFocus()
|
||||||
|
if(selectedPolicyType==-1){
|
||||||
|
Toast.makeText(myContext, "请选择策略", Toast.LENGTH_SHORT).show()
|
||||||
|
}else{
|
||||||
|
ssidSet.add(WifiSsid.fromBytes(inputSsid.toByteArray()))
|
||||||
|
myDpm.wifiSsidPolicy = WifiSsidPolicy(selectedPolicyType, ssidSet)
|
||||||
|
refreshList()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(0.49F)
|
||||||
|
) {
|
||||||
|
Text("添加")
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
focusMgr.clearFocus()
|
||||||
|
if(selectedPolicyType==-1){
|
||||||
|
Toast.makeText(myContext, "请选择策略", Toast.LENGTH_SHORT).show()
|
||||||
|
}else{
|
||||||
|
if(WifiSsid.fromBytes(inputSsid.toByteArray()) in ssidSet){
|
||||||
|
ssidSet.remove(WifiSsid.fromBytes(inputSsid.toByteArray()))
|
||||||
|
myDpm.wifiSsidPolicy = if(ssidSet.size==0){ null }else{ WifiSsidPolicy(selectedPolicyType, ssidSet) }
|
||||||
|
refreshList()
|
||||||
|
}else{
|
||||||
|
Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(0.96F)
|
||||||
|
) {
|
||||||
|
Text("移除")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT>=29&&isDeviceOwner(myDpm)){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
Text(text = "私人DNS", style = typography.titleLarge)
|
||||||
|
val dnsStatus = mapOf(
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_MODE_UNKNOWN to "未知",
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_MODE_OFF to "关闭",
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC to "自动",
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME to "指定主机名"
|
||||||
|
)
|
||||||
|
val operationResult = mapOf(
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_SET_NO_ERROR to "成功",
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING to "主机不支持DNS over TLS",
|
||||||
|
DevicePolicyManager.PRIVATE_DNS_SET_ERROR_FAILURE_SETTING to "失败"
|
||||||
|
)
|
||||||
|
var status by remember{mutableStateOf(dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)])}
|
||||||
|
Text(text = "状态:$status")
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val result = myDpm.setGlobalPrivateDnsModeOpportunistic(myComponent)
|
||||||
|
Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show()
|
||||||
|
status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)]
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("设为自动")
|
||||||
|
}
|
||||||
|
Spacer(Modifier.padding(vertical = 3.dp))
|
||||||
|
var inputHost by remember{mutableStateOf(myDpm.getGlobalPrivateDnsHost(myComponent) ?: "")}
|
||||||
|
TextField(
|
||||||
|
value = inputHost,
|
||||||
|
onValueChange = {inputHost=it},
|
||||||
|
label = {Text("DNS主机名")},
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val result: Int
|
||||||
|
try{
|
||||||
|
result = myDpm.setGlobalPrivateDnsModeSpecifiedHost(myComponent,inputHost)
|
||||||
|
Toast.makeText(myContext, operationResult[result], Toast.LENGTH_SHORT).show()
|
||||||
|
}catch(e:IllegalArgumentException){
|
||||||
|
Toast.makeText(myContext, "无效主机名", Toast.LENGTH_SHORT).show()
|
||||||
|
}catch(e:SecurityException){
|
||||||
|
Toast.makeText(myContext, "安全错误", Toast.LENGTH_SHORT).show()
|
||||||
|
}finally {
|
||||||
|
status = dnsStatus[myDpm.getGlobalPrivateDnsMode(myComponent)]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("设置DNS主机")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(VERSION.SDK_INT>=31&&(isDeviceOwner(myDpm)||isProfileOwner(myDpm))){
|
||||||
|
Column(modifier = sections()){
|
||||||
|
var keyPair by remember{mutableStateOf("")}
|
||||||
|
Text(text = "WiFi密钥对", style = typography.titleLarge)
|
||||||
|
TextField(
|
||||||
|
value = keyPair,
|
||||||
|
label = { Text("密钥对")},
|
||||||
|
onValueChange = {keyPair = it},
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}),
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)
|
||||||
|
)
|
||||||
|
val isExist = try{myDpm.isKeyPairGrantedToWifiAuth(keyPair)}catch(e:java.lang.IllegalArgumentException){false}
|
||||||
|
Text("已存在:$isExist")
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val result = myDpm.grantKeyPairToWifiAuth(keyPair)
|
||||||
|
Toast.makeText(myContext, if(result){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(0.49F)
|
||||||
|
) {
|
||||||
|
Text("添加")
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
val result = myDpm.revokeKeyPairFromWifiAuth(keyPair)
|
||||||
|
Toast.makeText(myContext, if(result){"成功"}else{"失败"}, Toast.LENGTH_SHORT).show()
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(0.96F)
|
||||||
|
) {
|
||||||
|
Text("移除")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(Modifier.padding(vertical = 30.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,31 +35,26 @@ fun AppSetting(navCtrl:NavHostController){
|
|||||||
val myContext = LocalContext.current
|
val myContext = LocalContext.current
|
||||||
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
val sharedPref = LocalContext.current.getSharedPreferences("data", Context.MODE_PRIVATE)
|
||||||
val isWear = sharedPref.getBoolean("isWear",false)
|
val isWear = sharedPref.getBoolean("isWear",false)
|
||||||
|
val bodyTextStyle = if(isWear){typography.bodyMedium}else{typography.bodyLarge}
|
||||||
Column(modifier = sections()) {
|
Column(modifier = sections()) {
|
||||||
Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 3.dp),horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 3.dp),horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
|
||||||
Text(text = "Wear", style = MaterialTheme.typography.titleLarge)
|
Text(text = "Wear", style = typography.titleLarge)
|
||||||
Switch(
|
Switch(
|
||||||
checked = isWear,
|
checked = isWear,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
sharedPref.edit().putBoolean("isWear",!sharedPref.getBoolean("isWear",false)).apply()
|
sharedPref.edit().putBoolean("isWear",!isWear).apply()
|
||||||
navCtrl.navigate("HomePage") {
|
navCtrl.navigateUp()
|
||||||
popUpTo(
|
|
||||||
navCtrl.graph.findStartDestination().id
|
|
||||||
) { saveState = true }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT>=32){
|
if(VERSION.SDK_INT>=32){
|
||||||
Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 3.dp),horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
|
Row(modifier = Modifier.fillMaxWidth().padding(horizontal = 3.dp),horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) {
|
||||||
Text(text = "动态取色", style = MaterialTheme.typography.titleLarge)
|
Text(text = "动态取色", style = typography.titleLarge)
|
||||||
Switch(
|
Switch(
|
||||||
checked = sharedPref.getBoolean("dynamicColor",false),
|
checked = sharedPref.getBoolean("dynamicColor",false),
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
sharedPref.edit().putBoolean("dynamicColor",!sharedPref.getBoolean("dynamicColor",false)).apply()
|
sharedPref.edit().putBoolean("dynamicColor",!sharedPref.getBoolean("dynamicColor",false)).apply()
|
||||||
navCtrl.navigate("HomePage") {
|
navCtrl.navigateUp()
|
||||||
popUpTo(navCtrl.graph.findStartDestination().id) { saveState = true }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -70,12 +65,14 @@ fun AppSetting(navCtrl:NavHostController){
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 12.dp)
|
modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 12.dp)
|
||||||
) {
|
) {
|
||||||
Text(text = "Android owner", style = MaterialTheme.typography.headlineSmall, color = MaterialTheme.colorScheme.onPrimaryContainer)
|
Text(text = "关于", style = typography.headlineSmall, color = MaterialTheme.colorScheme.onPrimaryContainer)
|
||||||
Text(text = "使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备",
|
Text(text = "使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备", style = bodyTextStyle)
|
||||||
style = if(!sharedPref.getBoolean("isWear",false)){MaterialTheme.typography.bodyLarge}else{MaterialTheme.typography.bodyMedium})
|
|
||||||
Spacer(Modifier.padding(vertical = 4.dp))
|
Spacer(Modifier.padding(vertical = 4.dp))
|
||||||
Text(text = "这个应用只在AOSP和LineageOS上测试过,不确保每个功能都在其它系统可用,尤其是国内的魔改系统。",
|
Text(text = "这个应用只在AOSP和LineageOS上测试过,不确保每个功能都在其它系统可用,尤其是国内的魔改系统。", style = bodyTextStyle)
|
||||||
style = if(!sharedPref.getBoolean("isWear",false)){MaterialTheme.typography.bodyLarge}else{MaterialTheme.typography.bodyMedium})
|
Spacer(Modifier.padding(vertical = 4.dp))
|
||||||
|
Text(text = "大部分功能都要Device owner权限", style = bodyTextStyle)
|
||||||
|
Spacer(Modifier.padding(vertical = 2.dp))
|
||||||
|
Text(text = "安卓版本越高,支持的功能越多", style = bodyTextStyle)
|
||||||
}
|
}
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
@@ -92,7 +89,7 @@ fun AppSetting(navCtrl:NavHostController){
|
|||||||
)
|
)
|
||||||
Column {
|
Column {
|
||||||
Text(text = "源代码", fontSize = 18.sp, fontWeight = FontWeight.SemiBold)
|
Text(text = "源代码", fontSize = 18.sp, fontWeight = FontWeight.SemiBold)
|
||||||
if(!sharedPref.getBoolean("isWear",false)){
|
if(!isWear){
|
||||||
Text(text = "https://github.com/BinTianqi/AndroidOwner", color = MaterialTheme.colorScheme.onPrimaryContainer)
|
Text(text = "https://github.com/BinTianqi/AndroidOwner", color = MaterialTheme.colorScheme.onPrimaryContainer)
|
||||||
Text(text = "欢迎提交issue、给小星星")
|
Text(text = "欢迎提交issue、给小星星")
|
||||||
}
|
}
|
||||||
|
|||||||
9
app/src/main/res/drawable/wifi_password_fill0.xml
Normal file
9
app/src/main/res/drawable/wifi_password_fill0.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M85,444 L0,359q93,-93 215.5,-146T480,160q142,0 264.5,53T960,359l-85,85q-76,-77 -177.5,-120.5T480,280q-116,0 -217.5,43.5T85,444ZM254,614 L170,529q60,-60 139.5,-94.5T480,400q91,0 170.5,34.5T790,529l-84,85q-44,-44 -102,-69t-124,-25q-66,0 -124,25t-102,69ZM480,840q-42,0 -71,-29t-29,-71q0,-42 29,-71t71,-29q42,0 71,29t29,71q0,42 -29,71t-71,29ZM760,960q-17,0 -28.5,-11.5T720,920v-120q0,-17 11.5,-28.5T760,760v-40q0,-33 23.5,-56.5T840,640q33,0 56.5,23.5T920,720v40q17,0 28.5,11.5T960,800v120q0,17 -11.5,28.5T920,960L760,960ZM800,760h80v-40q0,-17 -11.5,-28.5T840,680q-17,0 -28.5,11.5T800,720v40Z"/>
|
||||||
|
</vector>
|
||||||
@@ -119,4 +119,7 @@
|
|||||||
<string name="common_criteria_mode">通用标准模式</string>
|
<string name="common_criteria_mode">通用标准模式</string>
|
||||||
<string name="common_criteria_mode_desc">Common Criteria</string>
|
<string name="common_criteria_mode_desc">Common Criteria</string>
|
||||||
<string name="preferential_network_service">优先网络服务</string>
|
<string name="preferential_network_service">优先网络服务</string>
|
||||||
|
<string name="network">网络</string>
|
||||||
|
<string name="developing">功能开发中</string>
|
||||||
|
<string name="wifi_lockdown">WiFi锁定</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user