Add Wi-Fi

This commit is contained in:
BinTianqi
2024-12-28 12:46:46 +08:00
parent 84c1dff9e6
commit 38d384d669
10 changed files with 366 additions and 7 deletions

View File

@@ -86,4 +86,5 @@ dependencies {
implementation(libs.androidx.fragment)
implementation(libs.hiddenApiBypass)
implementation(libs.serialization)
implementation(kotlin("reflect"))
}

View File

@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-sdk tools:overrideLibrary="rikka.shizuku.provider,rikka.shizuku.api,rikka.shizuku.shared,rikka.shizuku.aidl"/>
<application
android:dataExtractionRules="@xml/data_extraction_rules"

View File

@@ -59,6 +59,7 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.dpm.AddNetwork
import com.bintianqi.owndroid.dpm.AffiliationID
import com.bintianqi.owndroid.dpm.AlwaysOnVPNPackage
import com.bintianqi.owndroid.dpm.ApplicationManage
@@ -236,6 +237,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
composable(route = "Network") { Network(navCtrl) }
composable(route = "NetworkOptions") { NetworkOptions(navCtrl) }
composable(route = "AddWifi") { AddNetwork(navCtrl) }
composable(route = "MinWifiSecurityLevel") { WifiSecurityLevel(navCtrl) }
composable(route = "WifiSsidPolicy") { WifiSsidPolicy(navCtrl) }
composable(route = "PrivateDNS") { PrivateDNS(navCtrl) }

View File

@@ -1,6 +1,7 @@
package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OFF
import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC
import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME
@@ -19,8 +20,13 @@ import android.app.admin.WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager.NameNotFoundException
import android.net.IpConfiguration
import android.net.LinkAddress
import android.net.ProxyInfo
import android.net.StaticIpConfiguration
import android.net.Uri
import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiManager
import android.net.wifi.WifiSsid
import android.os.Build.VERSION
import android.telephony.TelephonyManager
@@ -61,9 +67,13 @@ import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
@@ -105,8 +115,11 @@ import com.bintianqi.owndroid.ui.ListItem
import com.bintianqi.owndroid.ui.MyScaffold
import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.UpOrDownTextFieldTrailingIconButton
import com.bintianqi.owndroid.writeClipBoard
import java.net.InetAddress
import kotlin.math.max
import kotlin.reflect.jvm.jvmErasure
@Composable
fun Network(navCtrl:NavHostController) {
@@ -125,6 +138,7 @@ fun Network(navCtrl:NavHostController) {
if(VERSION.SDK_INT >= 30) {
FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("NetworkOptions") }
}
FunctionItem(R.string.add_wifi, "", R.drawable.wifi_add_fill0) { navCtrl.navigate("AddWifi") }
if(VERSION.SDK_INT >= 33 && (deviceOwner || dpm.isOrgProfile(receiver))) {
FunctionItem(R.string.min_wifi_security_level, "", R.drawable.wifi_password_fill0) { navCtrl.navigate("MinWifiSecurityLevel") }
}
@@ -202,6 +216,266 @@ fun NetworkOptions(navCtrl: NavHostController) {
)
}
@Suppress("DEPRECATION")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AddNetwork(navCtrl: NavHostController) {
val context = LocalContext.current
var resultDialog by remember { mutableStateOf(false) }
var createdNetworkId by remember { mutableIntStateOf(-1) }
var createNetworkResult by remember {mutableIntStateOf(0)}
var dropdownMenu by remember { mutableIntStateOf(0) } // 0: None, 1:Status, 2:Security, 3:MAC randomization, 4:Static IP, 5:Proxy
var networkId by remember { mutableStateOf("") }
var status by remember { mutableIntStateOf(WifiConfiguration.Status.ENABLED) }
var ssid by remember { mutableStateOf("") }
var hiddenSsid by remember { mutableStateOf(false) }
var securityType by remember { mutableIntStateOf(WifiConfiguration.SECURITY_TYPE_OPEN) }
var password by remember { mutableStateOf("") }
var macRandomizationSetting by remember { mutableIntStateOf(WifiConfiguration.RANDOMIZATION_AUTO) }
var useStaticIp by remember { mutableStateOf(false) }
var ipAddress by remember { mutableStateOf("") }
var gatewayAddress by remember { mutableStateOf("") }
var dnsServers by remember { mutableStateOf("") }
var useHttpProxy by remember { mutableStateOf(false) }
var httpProxyHost by remember { mutableStateOf("") }
var httpProxyPort by remember { mutableStateOf("") }
var httpProxyExclList by remember { mutableStateOf("") }
MyScaffold(R.string.add_wifi, 8.dp, navCtrl) {
OutlinedTextField(
value = networkId, onValueChange = { networkId = it }, label = { Text(stringResource(R.string.network_id)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
isError = networkId != "" && (try { networkId.toInt(); false } catch(_: NumberFormatException) { true }),
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
)
ExposedDropdownMenuBox(dropdownMenu == 1, { dropdownMenu = if(it) 1 else 0 }) {
val statusText = when(status) {
WifiConfiguration.Status.CURRENT -> R.string.current
WifiConfiguration.Status.DISABLED -> R.string.disabled
WifiConfiguration.Status.ENABLED -> R.string.enabled
else -> R.string.place_holder
}
OutlinedTextField(
value = stringResource(statusText), onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.status)) },
trailingIcon = { UpOrDownTextFieldTrailingIconButton(dropdownMenu == 1) {} },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth().padding(bottom = 16.dp)
)
ExposedDropdownMenu(dropdownMenu == 1, { dropdownMenu = 0 }) {
DropdownMenuItem(
text = { Text(stringResource(R.string.current)) },
onClick = {
status = WifiConfiguration.Status.CURRENT
dropdownMenu = 0
}
)
DropdownMenuItem(
text = { Text(stringResource(R.string.disabled)) },
onClick = {
status = WifiConfiguration.Status.DISABLED
dropdownMenu = 0
}
)
DropdownMenuItem(
text = { Text(stringResource(R.string.enabled)) },
onClick = {
status = WifiConfiguration.Status.ENABLED
dropdownMenu = 0
}
)
}
}
OutlinedTextField(
value = ssid, onValueChange = { ssid = it }, label = { Text("SSID") },
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
CheckBoxItem(R.string.hidden_ssid, hiddenSsid, { hiddenSsid = it })
if(VERSION.SDK_INT >= 30) {
// TODO: more protocols
val securityTypeTextMap = mutableMapOf(
WifiConfiguration.SECURITY_TYPE_OPEN to stringResource(R.string.wifi_security_open),
WifiConfiguration.SECURITY_TYPE_PSK to "PSK"
)
ExposedDropdownMenuBox(dropdownMenu == 2, { dropdownMenu = if(it) 2 else 0 }) {
OutlinedTextField(
value = securityTypeTextMap[securityType] ?: "", onValueChange = {}, label = { Text(stringResource(R.string.security)) },
trailingIcon = { UpOrDownTextFieldTrailingIconButton(dropdownMenu == 1) {} }, readOnly = true,
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth().padding(vertical = 4.dp)
)
ExposedDropdownMenu(dropdownMenu == 2, { dropdownMenu = 0 }) {
securityTypeTextMap.forEach {
DropdownMenuItem(text = { Text(it.value) }, onClick = { securityType = it.key; dropdownMenu = 0 })
}
}
}
AnimatedVisibility(securityType == WifiConfiguration.SECURITY_TYPE_PSK) {
OutlinedTextField(
value = password, onValueChange = { password = it }, label = { Text(stringResource(R.string.password)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 12.dp)
)
}
}
if(VERSION.SDK_INT >= 33) {
val macRandomizationSettingTextMap = mapOf(
WifiConfiguration.RANDOMIZATION_NONE to R.string.none,
WifiConfiguration.RANDOMIZATION_PERSISTENT to R.string.persistent,
WifiConfiguration.RANDOMIZATION_NON_PERSISTENT to R.string.non_persistent,
WifiConfiguration.RANDOMIZATION_AUTO to R.string.auto
)
ExposedDropdownMenuBox(dropdownMenu == 3, { dropdownMenu = if(it) 3 else 0 }) {
OutlinedTextField(
value = stringResource(macRandomizationSettingTextMap[macRandomizationSetting] ?: R.string.place_holder),
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.mac_randomization)) },
trailingIcon = { UpOrDownTextFieldTrailingIconButton(dropdownMenu == 3) {} },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth().padding(bottom = 8.dp)
)
ExposedDropdownMenu(dropdownMenu == 3, { dropdownMenu = 0 }) {
macRandomizationSettingTextMap.forEach {
DropdownMenuItem(
text = { Text(stringResource(it.value)) },
onClick = {
macRandomizationSetting = it.key
dropdownMenu = 0
}
)
}
}
}
}
if(VERSION.SDK_INT >= 33) {
ExposedDropdownMenuBox(dropdownMenu == 4, { dropdownMenu = if(it) 4 else 0 }) {
OutlinedTextField(
value = if(useStaticIp) stringResource(R.string.static_str) else "DHCP",
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.ip_settings)) },
trailingIcon = { UpOrDownTextFieldTrailingIconButton(dropdownMenu == 4) {} },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth().padding(bottom = 4.dp)
)
ExposedDropdownMenu(dropdownMenu == 4, { dropdownMenu = 0 }) {
DropdownMenuItem(text = { Text("DHCP") }, onClick = { useStaticIp = false; dropdownMenu = 0 })
DropdownMenuItem(text = { Text(stringResource(R.string.static_str)) }, onClick = { useStaticIp = true; dropdownMenu = 0 })
}
}
AnimatedVisibility(visible = useStaticIp, modifier = Modifier.padding(bottom = 8.dp)) {
Column {
OutlinedTextField(
value = ipAddress, onValueChange = { ipAddress = it },
placeholder = { Text("192.168.1.2/24") }, label = { Text(stringResource(R.string.ip_address)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
OutlinedTextField(
value = gatewayAddress, onValueChange = { gatewayAddress = it },
placeholder = { Text("192.168.1.1") }, label = { Text(stringResource(R.string.gateway_address)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
OutlinedTextField(
value = dnsServers, onValueChange = { dnsServers = it },
label = { Text(stringResource(R.string.dns_servers)) }, minLines = 2,
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
}
}
}
if(VERSION.SDK_INT >= 26) {
ExposedDropdownMenuBox(dropdownMenu == 5, { dropdownMenu = if(it) 5 else 0 }) {
OutlinedTextField(
value = if(useHttpProxy) "HTTP" else stringResource(R.string.none),
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.proxy)) },
trailingIcon = { UpOrDownTextFieldTrailingIconButton(dropdownMenu == 5) {} },
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable).fillMaxWidth().padding(bottom = 4.dp)
)
ExposedDropdownMenu(dropdownMenu == 5, { dropdownMenu = 0 }) {
DropdownMenuItem(text = { Text(stringResource(R.string.none)) }, onClick = { useHttpProxy = false; dropdownMenu = 0 })
DropdownMenuItem(text = { Text("HTTP") }, onClick = { useHttpProxy = true; dropdownMenu = 0 })
}
}
AnimatedVisibility(visible = useHttpProxy, modifier = Modifier.padding(bottom = 8.dp)) {
Column {
OutlinedTextField(
value = httpProxyHost, onValueChange = { httpProxyHost = it }, label = { Text(stringResource(R.string.host)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
OutlinedTextField(
value = httpProxyPort, onValueChange = { httpProxyPort = it }, label = { Text(stringResource(R.string.port)) },
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
OutlinedTextField(
value = httpProxyExclList, onValueChange = { httpProxyExclList = it }, label = { Text(stringResource(R.string.excluded_hosts)) },
minLines = 2, placeholder = { Text("example.com\n*.example.com") },
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp)
)
}
}
}
Button(
onClick = {
val wm = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
try {
val config = WifiConfiguration()
if(networkId != "") config.networkId = networkId.toInt()
config.status = status
config.SSID = '"' + ssid + '"'
config.hiddenSSID = hiddenSsid
if(VERSION.SDK_INT >= 30) config.setSecurityParams(securityType)
if(securityType == WifiConfiguration.SECURITY_TYPE_PSK) config.preSharedKey = '"' + password + '"'
if(VERSION.SDK_INT >= 33) config.macRandomizationSetting = macRandomizationSetting
if(VERSION.SDK_INT >= 33 && useStaticIp) {
val ipConf = IpConfiguration.Builder()
val staticIpConf = StaticIpConfiguration.Builder()
val la: LinkAddress
val con = LinkAddress::class.constructors.find { it.parameters.size == 1 && it.parameters[0].type.jvmErasure == String::class }
la = con!!.call(ipAddress)
staticIpConf.setIpAddress(la)
staticIpConf.setGateway(InetAddress.getByName(gatewayAddress))
staticIpConf.setDnsServers(dnsServers.lines().map { InetAddress.getByName(it) })
ipConf.setStaticIpConfiguration(staticIpConf.build())
config.setIpConfiguration(ipConf.build())
}
if(VERSION.SDK_INT >= 26 && useHttpProxy) {
config.httpProxy = ProxyInfo.buildDirectProxy(httpProxyHost, httpProxyPort.toInt(), httpProxyExclList.lines())
}
if(VERSION.SDK_INT >= 31) {
val result = wm.addNetworkPrivileged(config)
createdNetworkId = result.networkId
createNetworkResult = result.statusCode
} else {
createdNetworkId = wm.addNetwork(config)
}
resultDialog = true
} catch(e: Exception) {
e.printStackTrace()
AlertDialog.Builder(context)
.setTitle(R.string.error)
.setPositiveButton(R.string.confirm) { dialog, _ -> dialog.cancel() }
.setMessage(e.message ?: "")
.show()
}
},
modifier = Modifier.fillMaxWidth().padding(vertical = 4.dp)
) {
Text(stringResource(R.string.add))
}
if(resultDialog) AlertDialog(
text = {
val statusText = when(createNetworkResult) {
WifiManager.AddNetworkResult.STATUS_SUCCESS -> R.string.success
//WifiManager.AddNetworkResult.STATUS_ADD_WIFI_CONFIG_FAILURE -> R.string.failed
WifiManager.AddNetworkResult.STATUS_INVALID_CONFIGURATION -> R.string.add_network_result_invalid_configuration
else -> R.string.failed
}
Text(stringResource(statusText) + "\n" + stringResource(R.string.network_id) + ": " + createdNetworkId)
},
confirmButton = {
TextButton(onClick = { resultDialog = false }) {
Text(stringResource(R.string.confirm))
}
},
onDismissRequest = { resultDialog = false }
)
}
}
@SuppressLint("NewApi")
@Composable
fun WifiSecurityLevel(navCtrl: NavHostController) {
@@ -513,7 +787,7 @@ fun RecommendedGlobalProxy(navCtrl: NavHostController) {
OutlinedTextField(
value = exclList,
onValueChange = { exclList = it },
label = { Text(stringResource(R.string.exclude_hosts)) },
label = { Text(stringResource(R.string.excluded_hosts)) },
maxLines = 5,
minLines = 2,
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)

View File

@@ -4,6 +4,7 @@ import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@@ -13,6 +14,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme.colorScheme
@@ -22,6 +24,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
@@ -315,3 +318,17 @@ fun MyScaffold(
}
}
}
@Composable
fun UpOrDownTextFieldTrailingIconButton(active: Boolean, onClick: () -> Unit) {
val degrees by animateFloatAsState(if(active) 180F else 0F)
IconButton(
onClick = onClick,
modifier = Modifier.clip(RoundedCornerShape(50))
) {
Icon(
imageVector = Icons.Default.ArrowDropDown, contentDescription = null,
modifier = Modifier.rotate(degrees)
)
}
}

View 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:pathData="M720,840v-120L600,720v-80h120v-120h80v120h120v80L800,720v120h-80ZM480,840L0,360q95,-97 219.5,-148.5T480,160q136,0 260.5,51.5T960,360L822,497q-14,-14 -28,-28.5T766,440l78,-78q-79,-60 -172,-91t-192,-31q-99,0 -192,31t-172,91l364,364 40,-40 28.5,28.5L577,743l-97,97ZM480,483Z"
android:fillColor="#000000"/>
</vector>

View File

@@ -64,6 +64,7 @@
<string name="unknown_error">Unknown error</string>
<string name="permission_denied">Permission denied</string>
<string name="error">Error</string>
<string name="status">Status</string>
<!--Разрешения-->
@@ -215,6 +216,19 @@
<!--Сеть-->
<string name="network">Сеть</string>
<string name="wifi_mac_address">MAC-адрес Wi-Fi</string>
<!--TODO-->
<string name="add_wifi">Add Wi-Fi</string>
<string name="current">Current</string>
<string name="hidden_ssid">Hidden SSID</string>
<string name="ip_settings">IP settings</string>
<string name="static_str">Static</string>
<string name="ip_address">IP address</string>
<string name="gateway_address">Gateway address</string>
<string name="dns_servers">DNS servers</string>
<string name="mac_randomization">MAC randomization</string>
<string name="non_persistent">Non persistent</string>
<string name="host">Host</string>
<string name="add_network_result_invalid_configuration">Invalid configuration</string>
<string name="min_wifi_security_level">Минимальный уровень безопасности Wi-Fi</string>
<string name="wifi_security_open">Открытая</string>
<string name="lockdown_admin_configured_network">Блокировка ети, настроенной администратором</string>
@@ -235,7 +249,7 @@
<string name="proxy_type_direct">Прямой прокси</string>
<string name="specify_port">Указать порт</string>
<string name="invalid_config">Неверная конфигурация</string>
<string name="exclude_hosts">Исключить хосты</string>
<string name="excluded_hosts">Исключить хосты</string> <!--TODO-->
<string name="network_logging">Network logging</string> <!--TODO-->
<string name="log_file_size_is">Размер файла журнала: %1$s</string>
<string name="delete_logs">Удалить журналы</string>

View File

@@ -65,6 +65,7 @@
<string name="unknown_error">Unknown error</string>
<string name="permission_denied">Permission denied</string>
<string name="error">Error</string>
<string name="status">Status</string>
<!--Permissions-->
<string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string>
@@ -216,6 +217,19 @@
<!--Network-->
<string name="network"></string>
<string name="wifi_mac_address">Wi-Fi MAC adresi</string>
<!--TODO-->
<string name="add_wifi">Add Wi-Fi</string>
<string name="current">Current</string>
<string name="hidden_ssid">Hidden SSID</string>
<string name="ip_settings">IP settings</string>
<string name="static_str">Static</string>
<string name="ip_address">IP address</string>
<string name="gateway_address">Gateway address</string>
<string name="dns_servers">DNS servers</string>
<string name="mac_randomization">MAC randomization</string>
<string name="non_persistent">Non persistent</string>
<string name="host">Host</string>
<string name="add_network_result_invalid_configuration">Invalid configuration</string>
<string name="min_wifi_security_level">Minimum Wi-Fi güvenlik seviyesi</string>
<string name="wifi_security_open">ık</string>
<string name="lockdown_admin_configured_network">Yönetici tarafından yapılandırılmış ağı kilitle</string>
@@ -236,7 +250,7 @@
<string name="proxy_type_direct">Direct proxy</string> <!--TODO-->
<string name="specify_port">Specify port</string> <!--TODO-->
<string name="invalid_config">Invalid config</string> <!--TODO-->
<string name="exclude_hosts">Exclude hosts</string> <!--TODO-->
<string name="excluded_hosts">Excluded hosts</string> <!--TODO-->
<string name="network_logging">Network logging</string> <!--TODO-->
<string name="log_file_size_is">Log file size: %1$s</string> <!--TODO-->
<string name="delete_logs">Delete logs</string> <!--TODO-->

View File

@@ -61,6 +61,7 @@
<string name="unknown_error">未知错误</string>
<string name="permission_denied">无权限</string>
<string name="error">错误</string>
<string name="status">状态</string>
<!--Permissions-->
<string name="click_to_activate">点击以激活</string>
@@ -208,7 +209,19 @@
<!--Network-->
<string name="network">网络</string>
<string name="wifi_mac_address">Wi-Fi Mac地址</string>
<string name="wifi_mac_address">Wi-Fi MAC地址</string>
<string name="add_wifi">添加Wi-Fi</string>
<string name="current">当前</string>
<string name="hidden_ssid">隐藏的SSID</string>
<string name="ip_settings">IP设置</string>
<string name="static_str">静态</string>
<string name="ip_address">IP地址</string>
<string name="gateway_address">网关地址</string>
<string name="dns_servers">DNS服务器</string>
<string name="mac_randomization">MAC随机化</string>
<string name="non_persistent">非持久</string>
<string name="host">主机</string>
<string name="add_network_result_invalid_configuration">Invalid configuration</string>
<string name="min_wifi_security_level">最低Wi-Fi安全等级</string>
<string name="wifi_security_open">开放</string>
<string name="lockdown_admin_configured_network">锁定由管理员配置的网络</string>
@@ -229,7 +242,7 @@
<string name="proxy_type_direct">直连代理</string>
<string name="specify_port">指定端口</string>
<string name="invalid_config">无效配置</string>
<string name="exclude_hosts">排除列表</string>
<string name="excluded_hosts">排除的主机</string>
<string name="network_logging">网络日志</string>
<string name="log_file_size_is">日志文件大小:%1$s</string>
<string name="delete_logs">删除日志</string>
@@ -534,7 +547,7 @@
<string name="project_homepage">项目主页</string>
<string name="appearance">外观</string>
<string name="security">安全</string>
<string name="security">安全</string>
<string name="lock_owndroid">锁定OwnDroid</string>
<string name="enable_bio_auth">使用生物识别</string>
<string name="authenticate">验证</string>

View File

@@ -1,6 +1,7 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!--Global-->
<string name="app_name" translatable="false">OwnDroid</string>
<string name="place_holder" translatable="false"/>
<string name="disabled">Disabled</string>
<string name="enabled">Enabled</string>
<string name="disable">Disable</string>
@@ -65,6 +66,7 @@
<string name="permission_denied">Permission denied</string>
<string name="api" translatable="false">API</string>
<string name="error">Error</string>
<string name="status">Status</string>
<!--Permissions-->
<string name="click_to_activate">Click to activate</string>
@@ -220,6 +222,18 @@
<!--Network-->
<string name="network">Network</string>
<string name="wifi_mac_address">Wi-Fi Mac address</string>
<string name="add_wifi">Add Wi-Fi</string>
<string name="current">Current</string>
<string name="hidden_ssid">Hidden SSID</string>
<string name="ip_settings">IP settings</string>
<string name="static_str">Static</string>
<string name="ip_address">IP address</string>
<string name="gateway_address">Gateway address</string>
<string name="dns_servers">DNS servers</string>
<string name="mac_randomization">MAC randomization</string>
<string name="non_persistent">Non persistent</string>
<string name="host">Host</string>
<string name="add_network_result_invalid_configuration">Invalid configuration</string>
<string name="min_wifi_security_level">Minimum Wi-Fi security level</string>
<string name="wifi_security_open">Open</string>
<string name="lockdown_admin_configured_network">Lockdown admin configured network</string>
@@ -240,7 +254,7 @@
<string name="proxy_type_direct">Direct proxy</string>
<string name="specify_port">Specify port</string>
<string name="invalid_config">Invalid config</string>
<string name="exclude_hosts">Exclude hosts</string>
<string name="excluded_hosts">Excluded hosts</string>
<string name="network_logging">Network logging</string>
<string name="log_file_size_is">Log file size: %1$s</string>
<string name="delete_logs">Delete logs</string>