From 30f29f0c4b5d2ab2138b182b49153c0a5f937812 Mon Sep 17 00:00:00 2001 From: BinTianqi <1220958406@qq.com> Date: Mon, 5 Feb 2024 17:22:20 +0800 Subject: [PATCH] Add a separate Network page --- Readme.md | 8 +- app/build.gradle.kts | 4 +- app/src/main/AndroidManifest.xml | 1 + .../com/binbin/androidowner/DeviceControl.kt | 156 +++-------- .../com/binbin/androidowner/MainActivity.kt | 4 + .../java/com/binbin/androidowner/Network.kt | 251 ++++++++++++++++++ .../java/com/binbin/androidowner/Setting.kt | 31 +-- .../main/res/drawable/wifi_password_fill0.xml | 9 + app/src/main/res/values/strings.xml | 3 + 9 files changed, 319 insertions(+), 148 deletions(-) create mode 100644 app/src/main/java/com/binbin/androidowner/Network.kt create mode 100644 app/src/main/res/drawable/wifi_password_fill0.xml diff --git a/Readme.md b/Readme.md index 00c992f..21b5644 100644 --- a/Readme.md +++ b/Readme.md @@ -13,10 +13,12 @@ 适配了一些预见式返回动画(需安卓13或14),可能不太稳定,如果有问题请向我反馈 - 设备控制 + - 重启、锁屏 - 禁用相机 - 禁止截屏 - 全局静音 - 关闭USB信号(需设备支持) + - 设置时间 - 管理系统更新策略 - 清除数据 - 管理应用 @@ -49,9 +51,9 @@ ### 即将加入的功能 - Managed Profile,工作资料和多用户相关 -- 应用管理--安装/卸载应用 -- 应用管理--包选择器(目前只能手动输入包名) -- 用户管理--用户选择器(目前只能手动输入序列号) +- ~~应用管理:安装/卸载应用~~(暂不考虑) +- 应用管理:包选择器(目前只能手动输入包名) +- 用户管理:用户选择器(目前只能手动输入序列号) ### 许可证 diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4a88355..c097f3a 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 = 10 - versionName = "2.3" + versionCode = 11 + versionName = "2.4" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 05dac6e..34c175c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ + 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)){ DeviceCtrlItem(R.string.secure_logging,R.string.no_effect,R.drawable.description_fill0, {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)){ DeviceCtrlItem(R.string.common_criteria_mode,R.string.common_criteria_mode_desc,R.drawable.security_fill0, {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)){ Button( onClick = {myDpm.uninstallAllUserCaCerts(myComponent);Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show()}, @@ -173,7 +156,7 @@ fun DeviceControl(){ Column(modifier = sections()){ Text(text = "修改时间", style = typography.titleLarge) 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( value = inputTime, 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)){ Column(modifier = sections()){ val lockTaskPolicyList = mutableListOf( @@ -335,6 +295,7 @@ fun DeviceControl(){ var listText by remember{mutableStateOf("")} var inputPkg by remember{mutableStateOf("")} val refreshWhitelist = { + inputPkg="" listText="" var currentItem = whitelist.size for(each in whitelist){ @@ -354,92 +315,35 @@ fun DeviceControl(){ keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus()}), modifier = Modifier.fillMaxWidth().padding(vertical = 3.dp) ) - Button( - onClick = { - focusMgr.clearFocus() - whitelist.add(inputPkg) - myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray()) - Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() - inputPkg="" - refreshWhitelist() - }, - modifier = Modifier.fillMaxWidth() - ) { - Text("加入白名单") - } - Button( - onClick = { - focusMgr.clearFocus() - if(inputPkg in whitelist){ - whitelist.remove(inputPkg) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween){ + Button( + onClick = { + focusMgr.clearFocus() + whitelist.add(inputPkg) myDpm.setLockTaskPackages(myComponent,whitelist.toTypedArray()) Toast.makeText(myContext, "成功", Toast.LENGTH_SHORT).show() - }else{ - Toast.makeText(myContext, "不存在", Toast.LENGTH_SHORT).show() - } - inputPkg="" - refreshWhitelist() - }, - modifier = Modifier.fillMaxWidth() - ) { - 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主机") + refreshWhitelist() + }, + modifier = Modifier.fillMaxWidth(0.49F) + ) { + Text("添加") + } + Button( + onClick = { + focusMgr.clearFocus() + 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(0.96F) + ) { + Text("移除") + } } } } @@ -505,7 +409,7 @@ fun DeviceControl(){ } @Composable -private fun DeviceCtrlItem( +fun DeviceCtrlItem( itemName:Int, itemDesc:Int, leadIcon:Int, diff --git a/app/src/main/java/com/binbin/androidowner/MainActivity.kt b/app/src/main/java/com/binbin/androidowner/MainActivity.kt index aeceae1..75d1706 100644 --- a/app/src/main/java/com/binbin/androidowner/MainActivity.kt +++ b/app/src/main/java/com/binbin/androidowner/MainActivity.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import android.app.admin.DevicePolicyManager import android.content.ComponentName import android.content.Context +import android.os.Build.VERSION import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -67,6 +68,7 @@ fun MyScaffold(){ val topBarNameMap = mapOf( "HomePage" to R.string.app_name, "DeviceControl" to R.string.device_ctrl, + "Network" to R.string.network, "Permissions" to R.string.permission, "UserManage" to R.string.user_manage, "ApplicationManage" to R.string.app_manage, @@ -133,6 +135,7 @@ fun MyScaffold(){ composable(route = "UserManage", content = { UserManage(navCtrl)}) composable(route = "Password", content = { Password()}) 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) + 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.user_restrict, R.drawable.manage_accounts_fill0, "UserRestriction", navCtrl) HomePageItem(R.string.user_manage,R.drawable.account_circle_fill0,"UserManage",navCtrl) diff --git a/app/src/main/java/com/binbin/androidowner/Network.kt b/app/src/main/java/com/binbin/androidowner/Network.kt new file mode 100644 index 0000000..d2ac1fe --- /dev/null +++ b/app/src/main/java/com/binbin/androidowner/Network.kt @@ -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() + var ssidList by remember{mutableStateOf("")} + val refreshList = { + policy = myDpm.wifiSsidPolicy + selectedPolicyType = policy?.policyType ?: -1 + ssidSet = policy?.ssids ?: mutableSetOf() + 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)) + } +} diff --git a/app/src/main/java/com/binbin/androidowner/Setting.kt b/app/src/main/java/com/binbin/androidowner/Setting.kt index e2fd0fd..fc6787c 100644 --- a/app/src/main/java/com/binbin/androidowner/Setting.kt +++ b/app/src/main/java/com/binbin/androidowner/Setting.kt @@ -35,31 +35,26 @@ fun AppSetting(navCtrl:NavHostController){ val myContext = LocalContext.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 = sections()) { 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( checked = isWear, onCheckedChange = { - sharedPref.edit().putBoolean("isWear",!sharedPref.getBoolean("isWear",false)).apply() - navCtrl.navigate("HomePage") { - popUpTo( - navCtrl.graph.findStartDestination().id - ) { saveState = true } - } + sharedPref.edit().putBoolean("isWear",!isWear).apply() + navCtrl.navigateUp() } ) } if(VERSION.SDK_INT>=32){ 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( checked = sharedPref.getBoolean("dynamicColor",false), onCheckedChange = { sharedPref.edit().putBoolean("dynamicColor",!sharedPref.getBoolean("dynamicColor",false)).apply() - navCtrl.navigate("HomePage") { - popUpTo(navCtrl.graph.findStartDestination().id) { saveState = true } - } + navCtrl.navigateUp() } ) } @@ -70,12 +65,14 @@ fun AppSetting(navCtrl:NavHostController){ Column( 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 = "使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备", - style = if(!sharedPref.getBoolean("isWear",false)){MaterialTheme.typography.bodyLarge}else{MaterialTheme.typography.bodyMedium}) + Text(text = "关于", style = typography.headlineSmall, color = MaterialTheme.colorScheme.onPrimaryContainer) + Text(text = "使用安卓的Device admin、Device owner 、Profile owner,全方位掌控你的设备", style = bodyTextStyle) Spacer(Modifier.padding(vertical = 4.dp)) - Text(text = "这个应用只在AOSP和LineageOS上测试过,不确保每个功能都在其它系统可用,尤其是国内的魔改系统。", - style = if(!sharedPref.getBoolean("isWear",false)){MaterialTheme.typography.bodyLarge}else{MaterialTheme.typography.bodyMedium}) + Text(text = "这个应用只在AOSP和LineageOS上测试过,不确保每个功能都在其它系统可用,尤其是国内的魔改系统。", style = bodyTextStyle) + Spacer(Modifier.padding(vertical = 4.dp)) + Text(text = "大部分功能都要Device owner权限", style = bodyTextStyle) + Spacer(Modifier.padding(vertical = 2.dp)) + Text(text = "安卓版本越高,支持的功能越多", style = bodyTextStyle) } Row( verticalAlignment = Alignment.CenterVertically, @@ -92,7 +89,7 @@ fun AppSetting(navCtrl:NavHostController){ ) Column { 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 = "欢迎提交issue、给小星星") } diff --git a/app/src/main/res/drawable/wifi_password_fill0.xml b/app/src/main/res/drawable/wifi_password_fill0.xml new file mode 100644 index 0000000..6acbb88 --- /dev/null +++ b/app/src/main/res/drawable/wifi_password_fill0.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1b9fe93..8033fe6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -119,4 +119,7 @@ 通用标准模式 Common Criteria 优先网络服务 + 网络 + 功能开发中 + WiFi锁定