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.androidx.fragment)
implementation(libs.hiddenApiBypass) implementation(libs.hiddenApiBypass)
implementation(libs.serialization) 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_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.REQUEST_DELETE_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.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"/> <uses-sdk tools:overrideLibrary="rikka.shizuku.provider,rikka.shizuku.api,rikka.shizuku.shared,rikka.shizuku.aidl"/>
<application <application
android:dataExtractionRules="@xml/data_extraction_rules" 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.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.bintianqi.owndroid.dpm.AddNetwork
import com.bintianqi.owndroid.dpm.AffiliationID import com.bintianqi.owndroid.dpm.AffiliationID
import com.bintianqi.owndroid.dpm.AlwaysOnVPNPackage import com.bintianqi.owndroid.dpm.AlwaysOnVPNPackage
import com.bintianqi.owndroid.dpm.ApplicationManage import com.bintianqi.owndroid.dpm.ApplicationManage
@@ -236,6 +237,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
composable(route = "Network") { Network(navCtrl) } composable(route = "Network") { Network(navCtrl) }
composable(route = "NetworkOptions") { NetworkOptions(navCtrl) } composable(route = "NetworkOptions") { NetworkOptions(navCtrl) }
composable(route = "AddWifi") { AddNetwork(navCtrl) }
composable(route = "MinWifiSecurityLevel") { WifiSecurityLevel(navCtrl) } composable(route = "MinWifiSecurityLevel") { WifiSecurityLevel(navCtrl) }
composable(route = "WifiSsidPolicy") { WifiSsidPolicy(navCtrl) } composable(route = "WifiSsidPolicy") { WifiSsidPolicy(navCtrl) }
composable(route = "PrivateDNS") { PrivateDNS(navCtrl) } composable(route = "PrivateDNS") { PrivateDNS(navCtrl) }

View File

@@ -1,6 +1,7 @@
package com.bintianqi.owndroid.dpm package com.bintianqi.owndroid.dpm
import android.annotation.SuppressLint 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_OFF
import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_OPPORTUNISTIC
import android.app.admin.DevicePolicyManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME 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.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager.NameNotFoundException import android.content.pm.PackageManager.NameNotFoundException
import android.net.IpConfiguration
import android.net.LinkAddress
import android.net.ProxyInfo import android.net.ProxyInfo
import android.net.StaticIpConfiguration
import android.net.Uri import android.net.Uri
import android.net.wifi.WifiConfiguration
import android.net.wifi.WifiManager
import android.net.wifi.WifiSsid import android.net.wifi.WifiSsid
import android.os.Build.VERSION import android.os.Build.VERSION
import android.telephony.TelephonyManager 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.material.icons.filled.Delete
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button 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.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.MenuAnchorType
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text 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.MyScaffold
import com.bintianqi.owndroid.ui.RadioButtonItem import com.bintianqi.owndroid.ui.RadioButtonItem
import com.bintianqi.owndroid.ui.SwitchItem import com.bintianqi.owndroid.ui.SwitchItem
import com.bintianqi.owndroid.ui.UpOrDownTextFieldTrailingIconButton
import com.bintianqi.owndroid.writeClipBoard import com.bintianqi.owndroid.writeClipBoard
import java.net.InetAddress
import kotlin.math.max import kotlin.math.max
import kotlin.reflect.jvm.jvmErasure
@Composable @Composable
fun Network(navCtrl:NavHostController) { fun Network(navCtrl:NavHostController) {
@@ -125,6 +138,7 @@ fun Network(navCtrl:NavHostController) {
if(VERSION.SDK_INT >= 30) { if(VERSION.SDK_INT >= 30) {
FunctionItem(R.string.options, "", R.drawable.tune_fill0) { navCtrl.navigate("NetworkOptions") } 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))) { if(VERSION.SDK_INT >= 33 && (deviceOwner || dpm.isOrgProfile(receiver))) {
FunctionItem(R.string.min_wifi_security_level, "", R.drawable.wifi_password_fill0) { navCtrl.navigate("MinWifiSecurityLevel") } 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") @SuppressLint("NewApi")
@Composable @Composable
fun WifiSecurityLevel(navCtrl: NavHostController) { fun WifiSecurityLevel(navCtrl: NavHostController) {
@@ -513,7 +787,7 @@ fun RecommendedGlobalProxy(navCtrl: NavHostController) {
OutlinedTextField( OutlinedTextField(
value = exclList, value = exclList,
onValueChange = { exclList = it }, onValueChange = { exclList = it },
label = { Text(stringResource(R.string.exclude_hosts)) }, label = { Text(stringResource(R.string.excluded_hosts)) },
maxLines = 5, maxLines = 5,
minLines = 2, minLines = 2,
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp) modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp)

View File

@@ -4,6 +4,7 @@ import android.widget.Toast
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* 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.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.outlined.Info
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
@@ -22,6 +24,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource 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="unknown_error">Unknown error</string>
<string name="permission_denied">Permission denied</string> <string name="permission_denied">Permission denied</string>
<string name="error">Error</string> <string name="error">Error</string>
<string name="status">Status</string>
<!--Разрешения--> <!--Разрешения-->
@@ -215,6 +216,19 @@
<!--Сеть--> <!--Сеть-->
<string name="network">Сеть</string> <string name="network">Сеть</string>
<string name="wifi_mac_address">MAC-адрес Wi-Fi</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="min_wifi_security_level">Минимальный уровень безопасности Wi-Fi</string>
<string name="wifi_security_open">Открытая</string> <string name="wifi_security_open">Открытая</string>
<string name="lockdown_admin_configured_network">Блокировка ети, настроенной администратором</string> <string name="lockdown_admin_configured_network">Блокировка ети, настроенной администратором</string>
@@ -235,7 +249,7 @@
<string name="proxy_type_direct">Прямой прокси</string> <string name="proxy_type_direct">Прямой прокси</string>
<string name="specify_port">Указать порт</string> <string name="specify_port">Указать порт</string>
<string name="invalid_config">Неверная конфигурация</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="network_logging">Network logging</string> <!--TODO-->
<string name="log_file_size_is">Размер файла журнала: %1$s</string> <string name="log_file_size_is">Размер файла журнала: %1$s</string>
<string name="delete_logs">Удалить журналы</string> <string name="delete_logs">Удалить журналы</string>

View File

@@ -65,6 +65,7 @@
<string name="unknown_error">Unknown error</string> <string name="unknown_error">Unknown error</string>
<string name="permission_denied">Permission denied</string> <string name="permission_denied">Permission denied</string>
<string name="error">Error</string> <string name="error">Error</string>
<string name="status">Status</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string> <string name="click_to_activate">Etkinleştirmek İçin Tıklayın</string>
@@ -216,6 +217,19 @@
<!--Network--> <!--Network-->
<string name="network"></string> <string name="network"></string>
<string name="wifi_mac_address">Wi-Fi MAC adresi</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="min_wifi_security_level">Minimum Wi-Fi güvenlik seviyesi</string>
<string name="wifi_security_open">ık</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> <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="proxy_type_direct">Direct proxy</string> <!--TODO-->
<string name="specify_port">Specify port</string> <!--TODO--> <string name="specify_port">Specify port</string> <!--TODO-->
<string name="invalid_config">Invalid config</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="network_logging">Network logging</string> <!--TODO-->
<string name="log_file_size_is">Log file size: %1$s</string> <!--TODO--> <string name="log_file_size_is">Log file size: %1$s</string> <!--TODO-->
<string name="delete_logs">Delete logs</string> <!--TODO--> <string name="delete_logs">Delete logs</string> <!--TODO-->

View File

@@ -61,6 +61,7 @@
<string name="unknown_error">未知错误</string> <string name="unknown_error">未知错误</string>
<string name="permission_denied">无权限</string> <string name="permission_denied">无权限</string>
<string name="error">错误</string> <string name="error">错误</string>
<string name="status">状态</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">点击以激活</string> <string name="click_to_activate">点击以激活</string>
@@ -208,7 +209,19 @@
<!--Network--> <!--Network-->
<string name="network">网络</string> <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="min_wifi_security_level">最低Wi-Fi安全等级</string>
<string name="wifi_security_open">开放</string> <string name="wifi_security_open">开放</string>
<string name="lockdown_admin_configured_network">锁定由管理员配置的网络</string> <string name="lockdown_admin_configured_network">锁定由管理员配置的网络</string>
@@ -229,7 +242,7 @@
<string name="proxy_type_direct">直连代理</string> <string name="proxy_type_direct">直连代理</string>
<string name="specify_port">指定端口</string> <string name="specify_port">指定端口</string>
<string name="invalid_config">无效配置</string> <string name="invalid_config">无效配置</string>
<string name="exclude_hosts">排除列表</string> <string name="excluded_hosts">排除的主机</string>
<string name="network_logging">网络日志</string> <string name="network_logging">网络日志</string>
<string name="log_file_size_is">日志文件大小:%1$s</string> <string name="log_file_size_is">日志文件大小:%1$s</string>
<string name="delete_logs">删除日志</string> <string name="delete_logs">删除日志</string>
@@ -534,7 +547,7 @@
<string name="project_homepage">项目主页</string> <string name="project_homepage">项目主页</string>
<string name="appearance">外观</string> <string name="appearance">外观</string>
<string name="security">安全</string> <string name="security">安全</string>
<string name="lock_owndroid">锁定OwnDroid</string> <string name="lock_owndroid">锁定OwnDroid</string>
<string name="enable_bio_auth">使用生物识别</string> <string name="enable_bio_auth">使用生物识别</string>
<string name="authenticate">验证</string> <string name="authenticate">验证</string>

View File

@@ -1,6 +1,7 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!--Global--> <!--Global-->
<string name="app_name" translatable="false">OwnDroid</string> <string name="app_name" translatable="false">OwnDroid</string>
<string name="place_holder" translatable="false"/>
<string name="disabled">Disabled</string> <string name="disabled">Disabled</string>
<string name="enabled">Enabled</string> <string name="enabled">Enabled</string>
<string name="disable">Disable</string> <string name="disable">Disable</string>
@@ -65,6 +66,7 @@
<string name="permission_denied">Permission denied</string> <string name="permission_denied">Permission denied</string>
<string name="api" translatable="false">API</string> <string name="api" translatable="false">API</string>
<string name="error">Error</string> <string name="error">Error</string>
<string name="status">Status</string>
<!--Permissions--> <!--Permissions-->
<string name="click_to_activate">Click to activate</string> <string name="click_to_activate">Click to activate</string>
@@ -220,6 +222,18 @@
<!--Network--> <!--Network-->
<string name="network">Network</string> <string name="network">Network</string>
<string name="wifi_mac_address">Wi-Fi Mac address</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="min_wifi_security_level">Minimum Wi-Fi security level</string>
<string name="wifi_security_open">Open</string> <string name="wifi_security_open">Open</string>
<string name="lockdown_admin_configured_network">Lockdown admin configured network</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="proxy_type_direct">Direct proxy</string>
<string name="specify_port">Specify port</string> <string name="specify_port">Specify port</string>
<string name="invalid_config">Invalid config</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="network_logging">Network logging</string>
<string name="log_file_size_is">Log file size: %1$s</string> <string name="log_file_size_is">Log file size: %1$s</string>
<string name="delete_logs">Delete logs</string> <string name="delete_logs">Delete logs</string>