mirror of
https://github.com/awfixers-stuff/OwnDroid.git
synced 2026-03-27 12:26:11 +00:00
New APN settings screen
This commit is contained in:
@@ -62,6 +62,8 @@ import androidx.navigation.compose.rememberNavController
|
|||||||
import androidx.navigation.toRoute
|
import androidx.navigation.toRoute
|
||||||
import com.bintianqi.owndroid.dpm.Accounts
|
import com.bintianqi.owndroid.dpm.Accounts
|
||||||
import com.bintianqi.owndroid.dpm.AccountsScreen
|
import com.bintianqi.owndroid.dpm.AccountsScreen
|
||||||
|
import com.bintianqi.owndroid.dpm.AddApnSetting
|
||||||
|
import com.bintianqi.owndroid.dpm.AddApnSettingScreen
|
||||||
import com.bintianqi.owndroid.dpm.AddDelegatedAdmin
|
import com.bintianqi.owndroid.dpm.AddDelegatedAdmin
|
||||||
import com.bintianqi.owndroid.dpm.AddDelegatedAdminScreen
|
import com.bintianqi.owndroid.dpm.AddDelegatedAdminScreen
|
||||||
import com.bintianqi.owndroid.dpm.AddNetwork
|
import com.bintianqi.owndroid.dpm.AddNetwork
|
||||||
@@ -285,10 +287,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
|||||||
composable<Home> { HomeScreen { navController.navigate(it) } }
|
composable<Home> { HomeScreen { navController.navigate(it) } }
|
||||||
|
|
||||||
composable<Permissions> {
|
composable<Permissions> {
|
||||||
PermissionsScreen(::navigateUp, { navController.navigate(it) }) {
|
PermissionsScreen(::navigateUp, { navController.navigate(it) }) { navController.navigate(ShizukuScreen, it) }
|
||||||
val dest = navController.graph.findNode(ShizukuScreen)!!.id
|
|
||||||
navController.navigate(dest, it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
composable<ShizukuScreen> { ShizukuScreen(it.arguments!!, ::navigateUp) { navController.navigate(it) } }
|
composable<ShizukuScreen> { ShizukuScreen(it.arguments!!, ::navigateUp) { navController.navigate(it) } }
|
||||||
composable<Accounts>(mapOf(serializableNavTypePair<List<Accounts.Account>>())) { AccountsScreen(it.toRoute(), ::navigateUp) }
|
composable<Accounts>(mapOf(serializableNavTypePair<List<Accounts.Account>>())) { AccountsScreen(it.toRoute(), ::navigateUp) }
|
||||||
@@ -323,12 +322,7 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
|||||||
composable<WipeData> { WipeDataScreen(::navigateUp) }
|
composable<WipeData> { WipeDataScreen(::navigateUp) }
|
||||||
|
|
||||||
composable<Network> { NetworkScreen(::navigateUp, ::navigate) }
|
composable<Network> { NetworkScreen(::navigateUp, ::navigate) }
|
||||||
composable<WiFi> {
|
composable<WiFi> { WifiScreen(::navigateUp, { navController.navigate(it) }) { navController.navigate(AddNetwork, it)} }
|
||||||
WifiScreen(::navigateUp, { navController.navigate(it) }) {
|
|
||||||
val dest = navController.graph.findNode(AddNetwork)!!.id
|
|
||||||
navController.navigate(dest, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
composable<NetworkOptions> { NetworkOptionsScreen(::navigateUp) }
|
composable<NetworkOptions> { NetworkOptionsScreen(::navigateUp) }
|
||||||
composable<AddNetwork> { AddNetworkScreen(it.arguments!!, ::navigateUp) }
|
composable<AddNetwork> { AddNetworkScreen(it.arguments!!, ::navigateUp) }
|
||||||
composable<WifiSecurityLevel> { WifiSecurityLevelScreen(::navigateUp) }
|
composable<WifiSecurityLevel> { WifiSecurityLevelScreen(::navigateUp) }
|
||||||
@@ -344,7 +338,8 @@ fun Home(activity: FragmentActivity, vm: MyViewModel) {
|
|||||||
composable<WifiAuthKeypair> { WifiAuthKeypairScreen(::navigateUp) }
|
composable<WifiAuthKeypair> { WifiAuthKeypairScreen(::navigateUp) }
|
||||||
composable<PreferentialNetworkService> { PreferentialNetworkServiceScreen(::navigateUp, ::navigate) }
|
composable<PreferentialNetworkService> { PreferentialNetworkServiceScreen(::navigateUp, ::navigate) }
|
||||||
composable<AddPreferentialNetworkServiceConfig> { AddPreferentialNetworkServiceConfigScreen(it.toRoute(), ::navigateUp) }
|
composable<AddPreferentialNetworkServiceConfig> { AddPreferentialNetworkServiceConfigScreen(it.toRoute(), ::navigateUp) }
|
||||||
composable<OverrideApn> { OverrideApnScreen(::navigateUp) }
|
composable<OverrideApn> { OverrideApnScreen(::navigateUp) { navController.navigate(AddApnSetting, it) } }
|
||||||
|
composable<AddApnSetting> { AddApnSettingScreen(it.arguments?.getParcelable("setting"), ::navigateUp) }
|
||||||
|
|
||||||
composable<WorkProfile> { WorkProfileScreen(::navigateUp, ::navigate) }
|
composable<WorkProfile> { WorkProfileScreen(::navigateUp, ::navigate) }
|
||||||
composable<OrganizationOwnedProfile> { OrganizationOwnedProfileScreen(::navigateUp) }
|
composable<OrganizationOwnedProfile> { OrganizationOwnedProfileScreen(::navigateUp) }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import androidx.activity.result.contract.ActivityResultContract
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import com.bintianqi.owndroid.dpm.addDeviceAdmin
|
import com.bintianqi.owndroid.dpm.addDeviceAdmin
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
@@ -135,3 +136,7 @@ fun exportLogs(context: Context, uri: Uri) {
|
|||||||
context.showOperationResultToast(proc.exitValue() == 0)
|
context.showOperationResultToast(proc.exitValue() == 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> NavHostController.navigate(route: T, args: Bundle) {
|
||||||
|
navigate(graph.findNode(route)!!.id, args)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.bintianqi.owndroid.dpm
|
package com.bintianqi.owndroid.dpm
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.AlertDialog
|
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
|
||||||
@@ -32,23 +33,7 @@ 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.os.Bundle
|
import android.os.Bundle
|
||||||
import android.telephony.TelephonyManager
|
import android.telephony.data.ApnSetting
|
||||||
import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
|
|
||||||
import android.telephony.data.ApnSetting.AUTH_TYPE_CHAP
|
|
||||||
import android.telephony.data.ApnSetting.AUTH_TYPE_NONE
|
|
||||||
import android.telephony.data.ApnSetting.AUTH_TYPE_PAP
|
|
||||||
import android.telephony.data.ApnSetting.AUTH_TYPE_PAP_OR_CHAP
|
|
||||||
import android.telephony.data.ApnSetting.Builder
|
|
||||||
import android.telephony.data.ApnSetting.MVNO_TYPE_GID
|
|
||||||
import android.telephony.data.ApnSetting.MVNO_TYPE_ICCID
|
|
||||||
import android.telephony.data.ApnSetting.MVNO_TYPE_IMSI
|
|
||||||
import android.telephony.data.ApnSetting.MVNO_TYPE_SPN
|
|
||||||
import android.telephony.data.ApnSetting.PROTOCOL_IP
|
|
||||||
import android.telephony.data.ApnSetting.PROTOCOL_IPV4V6
|
|
||||||
import android.telephony.data.ApnSetting.PROTOCOL_IPV6
|
|
||||||
import android.telephony.data.ApnSetting.PROTOCOL_NON_IP
|
|
||||||
import android.telephony.data.ApnSetting.PROTOCOL_PPP
|
|
||||||
import android.telephony.data.ApnSetting.PROTOCOL_UNSTRUCTURED
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
@@ -56,6 +41,7 @@ import androidx.annotation.RequiresApi
|
|||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
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.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
@@ -63,6 +49,8 @@ import androidx.compose.foundation.interaction.collectIsPressedAsState
|
|||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -80,6 +68,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
import androidx.compose.material.icons.filled.Edit
|
import androidx.compose.material.icons.filled.Edit
|
||||||
import androidx.compose.material.icons.outlined.Delete
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
import androidx.compose.material.icons.outlined.LocationOn
|
import androidx.compose.material.icons.outlined.LocationOn
|
||||||
@@ -88,9 +77,11 @@ import androidx.compose.material3.Button
|
|||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.DatePicker
|
import androidx.compose.material3.DatePicker
|
||||||
import androidx.compose.material3.DatePickerDialog
|
import androidx.compose.material3.DatePickerDialog
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
|
import androidx.compose.material3.FilterChip
|
||||||
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
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -106,7 +97,6 @@ import androidx.compose.material3.Tab
|
|||||||
import androidx.compose.material3.TabRow
|
import androidx.compose.material3.TabRow
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.material3.TextField
|
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.rememberDatePickerState
|
import androidx.compose.material3.rememberDatePickerState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -123,6 +113,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -132,7 +123,6 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import com.bintianqi.owndroid.ChoosePackageContract
|
import com.bintianqi.owndroid.ChoosePackageContract
|
||||||
import com.bintianqi.owndroid.R
|
import com.bintianqi.owndroid.R
|
||||||
@@ -196,7 +186,7 @@ fun NetworkScreen(onNavigateUp: () -> Unit, onNavigate: (Any) -> Unit) {
|
|||||||
FunctionItem(R.string.preferential_network_service, icon = R.drawable.globe_fill0) { onNavigate(PreferentialNetworkService) }
|
FunctionItem(R.string.preferential_network_service, icon = R.drawable.globe_fill0) { onNavigate(PreferentialNetworkService) }
|
||||||
}
|
}
|
||||||
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
if(VERSION.SDK_INT >= 28 && deviceOwner) {
|
||||||
FunctionItem(R.string.override_apn_settings, icon = R.drawable.cell_tower_fill0) { onNavigate(OverrideApn) }
|
FunctionItem(R.string.override_apn, icon = R.drawable.cell_tower_fill0) { onNavigate(OverrideApn) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1880,374 +1870,397 @@ fun AddPreferentialNetworkServiceConfigScreen(route: AddPreferentialNetworkServi
|
|||||||
|
|
||||||
@RequiresApi(28)
|
@RequiresApi(28)
|
||||||
@Composable
|
@Composable
|
||||||
fun OverrideApnScreen(onNavigateUp: () -> Unit) {
|
fun OverrideApnScreen(onNavigateUp: () -> Unit, onNavigateToAddSetting: (Bundle) -> Unit) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val dpm = context.getDPM()
|
val dpm = context.getDPM()
|
||||||
val receiver = context.getReceiver()
|
val receiver = context.getReceiver()
|
||||||
val focusMgr = LocalFocusManager.current
|
var enabled by remember { mutableStateOf(false) }
|
||||||
val setting = dpm.getOverrideApns(receiver)
|
val settings = remember { mutableStateListOf<ApnSetting>() }
|
||||||
var inputNum by remember { mutableStateOf("0") }
|
fun refresh() {
|
||||||
var nextStep by remember { mutableStateOf(false) }
|
enabled = dpm.isOverrideApnEnabled(receiver)
|
||||||
val builder = Builder()
|
settings.clear()
|
||||||
MyScaffold(R.string.override_apn_settings, 8.dp, onNavigateUp) {
|
settings.addAll(dpm.getOverrideApns(receiver))
|
||||||
Text(text = stringResource(id = R.string.developing))
|
}
|
||||||
Spacer(Modifier.padding(vertical = 5.dp))
|
LaunchedEffect(Unit) { refresh() }
|
||||||
|
MyScaffold(R.string.override_apn, 0.dp, onNavigateUp, false) {
|
||||||
SwitchItem(
|
SwitchItem(
|
||||||
R.string.enable,
|
R.string.enable, state = enabled,
|
||||||
getState = { dpm.isOverrideApnEnabled(receiver) }, onCheckedChange = { dpm.setOverrideApnsEnabled(receiver,it) },
|
onCheckedChange = {
|
||||||
padding = false
|
dpm.setOverrideApnsEnabled(receiver, it)
|
||||||
|
refresh()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
Text(text = stringResource(R.string.total_apn_amount, setting.size))
|
settings.forEach {
|
||||||
if(setting.isNotEmpty()) {
|
Row(
|
||||||
Text(text = stringResource(R.string.select_a_apn_or_create, setting.size))
|
Modifier.fillMaxWidth().padding(start = 16.dp, end = 8.dp, top = 8.dp, bottom = 8.dp),
|
||||||
TextField(
|
Arrangement.SpaceBetween, Alignment.CenterVertically
|
||||||
value = inputNum,
|
) {
|
||||||
label = { Text("APN") },
|
Column {
|
||||||
onValueChange = { inputNum = it },
|
Text(it.id.toString())
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
Text(it.apnName.toString(), color = MaterialTheme.colorScheme.onSurfaceVariant, style = typography.bodyMedium)
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
Text(it.entryName.toString(), color = MaterialTheme.colorScheme.onSurfaceVariant, style = typography.bodyMedium)
|
||||||
modifier = Modifier.fillMaxWidth().padding(vertical = 2.dp),
|
}
|
||||||
enabled = !nextStep
|
IconButton({
|
||||||
)
|
onNavigateToAddSetting(bundleOf("setting" to it))
|
||||||
}else{
|
}) {
|
||||||
Text(text = stringResource(R.string.no_apn_you_should_create_one))
|
Icon(Icons.Default.Edit, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Button(
|
Row(
|
||||||
onClick = { focusMgr.clearFocus(); nextStep =! nextStep },
|
Modifier.fillMaxWidth().clickable {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
onNavigateToAddSetting(Bundle())
|
||||||
enabled = inputNum != "" && (nextStep || inputNum=="0" || setting[inputNum.toInt()-1] != null)
|
}.padding(horizontal = 8.dp, vertical = 12.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(stringResource(if(nextStep) R.string.previous_step else R.string.next_step))
|
Icon(Icons.Default.Add, null, Modifier.padding(horizontal = 8.dp))
|
||||||
}
|
Text(stringResource(R.string.add_config), style = typography.labelLarge)
|
||||||
var result = Builder().build()
|
|
||||||
AnimatedVisibility(nextStep) {
|
|
||||||
var carrierEnabled by remember { mutableStateOf(false) }
|
|
||||||
var inputApnName by remember { mutableStateOf("") }
|
|
||||||
var user by remember { mutableStateOf("") }
|
|
||||||
var profileId by remember { mutableStateOf("") }
|
|
||||||
var selectedAuthType by remember { mutableIntStateOf(AUTH_TYPE_NONE) }
|
|
||||||
var carrierId by remember { mutableStateOf("$UNKNOWN_CARRIER_ID") }
|
|
||||||
var apnTypeBitmask by remember { mutableStateOf("") }
|
|
||||||
var entryName by remember { mutableStateOf("") }
|
|
||||||
var mmsProxyAddress by remember { mutableStateOf("") }
|
|
||||||
var mmsProxyPort by remember { mutableStateOf("") }
|
|
||||||
var proxyAddress by remember { mutableStateOf("") }
|
|
||||||
var proxyPort by remember { mutableStateOf("") }
|
|
||||||
var mmsc by remember { mutableStateOf("") }
|
|
||||||
var mtuV4 by remember { mutableStateOf("") }
|
|
||||||
var mtuV6 by remember { mutableStateOf("") }
|
|
||||||
var mvnoType by remember { mutableIntStateOf(-1) }
|
|
||||||
var networkTypeBitmask by remember { mutableStateOf("") }
|
|
||||||
var operatorNumeric by remember { mutableStateOf("") }
|
|
||||||
var password by remember { mutableStateOf("") }
|
|
||||||
var persistent by remember { mutableStateOf(false) }
|
|
||||||
var protocol by remember { mutableIntStateOf(-1) }
|
|
||||||
var roamingProtocol by remember { mutableIntStateOf(-1) }
|
|
||||||
var id by remember { mutableIntStateOf(0) }
|
|
||||||
|
|
||||||
if(inputNum!="0") {
|
|
||||||
val current = setting[inputNum.toInt()-1]
|
|
||||||
id = current.id
|
|
||||||
carrierEnabled = current.isEnabled
|
|
||||||
inputApnName = current.apnName
|
|
||||||
user = current.user
|
|
||||||
if(VERSION.SDK_INT>=33) {profileId = current.profileId.toString() }
|
|
||||||
selectedAuthType = current.authType
|
|
||||||
apnTypeBitmask = current.apnTypeBitmask.toString()
|
|
||||||
entryName = current.entryName
|
|
||||||
if(VERSION.SDK_INT>=29) {mmsProxyAddress = current.mmsProxyAddressAsString}
|
|
||||||
mmsProxyPort = current.mmsProxyPort.toString()
|
|
||||||
if(VERSION.SDK_INT>=29) {proxyAddress = current.proxyAddressAsString}
|
|
||||||
proxyPort = current.proxyPort.toString()
|
|
||||||
mmsc = current.mmsc.toString()
|
|
||||||
if(VERSION.SDK_INT>=33) { mtuV4 = current.mtuV4.toString(); mtuV6 = current.mtuV6.toString() }
|
|
||||||
mvnoType = current.mvnoType
|
|
||||||
networkTypeBitmask = current.networkTypeBitmask.toString()
|
|
||||||
operatorNumeric = current.operatorNumeric
|
|
||||||
password = current.password
|
|
||||||
if(VERSION.SDK_INT>=33) {persistent = current.isPersistent}
|
|
||||||
protocol = current.protocol
|
|
||||||
roamingProtocol = current.roamingProtocol
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
|
|
||||||
Text(text = "APN", style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = inputApnName,
|
|
||||||
onValueChange = {inputApnName=it },
|
|
||||||
label = { Text(stringResource(R.string.name)) },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Text(text = stringResource(R.string.enable), style = typography.titleLarge)
|
|
||||||
Switch(checked = carrierEnabled, onCheckedChange = {carrierEnabled=it })
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.user_name), style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = user,
|
|
||||||
onValueChange = { user=it },
|
|
||||||
label = { Text(stringResource(R.string.user_name)) },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=33) {
|
|
||||||
Text(text = stringResource(R.string.profile_id), style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = profileId,
|
|
||||||
onValueChange = { profileId=it },
|
|
||||||
label = { Text("ID") },
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.auth_type), style = typography.titleLarge)
|
|
||||||
RadioButtonItem(R.string.none, selectedAuthType==AUTH_TYPE_NONE) { selectedAuthType = AUTH_TYPE_NONE }
|
|
||||||
RadioButtonItem("CHAP", selectedAuthType == AUTH_TYPE_CHAP) { selectedAuthType = AUTH_TYPE_CHAP }
|
|
||||||
RadioButtonItem("PAP", selectedAuthType == AUTH_TYPE_PAP) { selectedAuthType = AUTH_TYPE_PAP }
|
|
||||||
RadioButtonItem("PAP/CHAP", selectedAuthType == AUTH_TYPE_PAP_OR_CHAP) { selectedAuthType = AUTH_TYPE_PAP_OR_CHAP }
|
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=29) {
|
|
||||||
val ts = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
|
|
||||||
carrierId = ts.simCarrierId.toString()
|
|
||||||
Text(text = "CarrierID", style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = carrierId,
|
|
||||||
onValueChange = { carrierId=it },
|
|
||||||
label = { Text("ID") },
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.apn_type), style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = apnTypeBitmask,
|
|
||||||
onValueChange = { apnTypeBitmask=it },
|
|
||||||
label = { Text(stringResource(R.string.bitmask)) },
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.description), style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = entryName,
|
|
||||||
onValueChange = {entryName=it },
|
|
||||||
label = { Text(stringResource(R.string.description)) },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.mms_proxy), style = typography.titleLarge)
|
|
||||||
if(VERSION.SDK_INT>=29) {
|
|
||||||
TextField(
|
|
||||||
value = mmsProxyAddress,
|
|
||||||
onValueChange = { mmsProxyAddress=it },
|
|
||||||
label = { Text(stringResource(R.string.address)) },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
TextField(
|
|
||||||
value = mmsProxyPort,
|
|
||||||
onValueChange = { mmsProxyPort=it },
|
|
||||||
label = { Text(stringResource(R.string.port)) },
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.proxy), style = typography.titleLarge)
|
|
||||||
if(VERSION.SDK_INT>=29) {
|
|
||||||
TextField(
|
|
||||||
value = proxyAddress,
|
|
||||||
onValueChange = { proxyAddress=it },
|
|
||||||
label = { Text(stringResource(R.string.address)) },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
TextField(
|
|
||||||
value = proxyPort,
|
|
||||||
onValueChange = { proxyPort=it },
|
|
||||||
label = { Text(stringResource(R.string.port)) },
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = "MMSC", style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = mmsc,
|
|
||||||
onValueChange = { mmsc=it },
|
|
||||||
label = { Text("Uri") },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=33) {
|
|
||||||
Text(text = "MTU", style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = mtuV4,
|
|
||||||
onValueChange = { mtuV4=it },
|
|
||||||
label = { Text("IPV4") },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
TextField(
|
|
||||||
value = mtuV6,
|
|
||||||
onValueChange = { mtuV6=it },
|
|
||||||
label = { Text("IPV6") },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(text = "MVNO", style = typography.titleLarge)
|
|
||||||
RadioButtonItem("SPN", mvnoType == MVNO_TYPE_SPN) { mvnoType = MVNO_TYPE_SPN }
|
|
||||||
RadioButtonItem("IMSI", mvnoType == MVNO_TYPE_IMSI) { mvnoType = MVNO_TYPE_IMSI }
|
|
||||||
RadioButtonItem("GID", mvnoType == MVNO_TYPE_GID) { mvnoType = MVNO_TYPE_GID }
|
|
||||||
RadioButtonItem("ICCID", mvnoType == MVNO_TYPE_ICCID) { mvnoType = MVNO_TYPE_ICCID }
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.apn_network_type), style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = networkTypeBitmask,
|
|
||||||
onValueChange = { networkTypeBitmask=it },
|
|
||||||
label = { Text(stringResource(R.string.bitmask)) },
|
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = "OperatorNumeric", style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = operatorNumeric,
|
|
||||||
onValueChange = { operatorNumeric=it },
|
|
||||||
label = { Text("ID") },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.password), style = typography.titleLarge)
|
|
||||||
TextField(
|
|
||||||
value = password,
|
|
||||||
onValueChange = { password=it },
|
|
||||||
label = { Text(stringResource(R.string.password)) },
|
|
||||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
|
||||||
keyboardActions = KeyboardActions(onDone = { focusMgr.clearFocus() }),
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 4.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
if(VERSION.SDK_INT>=33) {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
Text(text = stringResource(R.string.persistent), style = typography.titleLarge)
|
|
||||||
Switch(checked = persistent, onCheckedChange = { persistent=it })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.protocol), style = typography.titleLarge)
|
|
||||||
RadioButtonItem("IPV4", protocol == PROTOCOL_IP) { protocol = PROTOCOL_IP }
|
|
||||||
RadioButtonItem("IPV6", protocol == PROTOCOL_IPV6) { protocol = PROTOCOL_IPV6 }
|
|
||||||
RadioButtonItem("IPV4/IPV6", protocol == PROTOCOL_IPV4V6) { protocol = PROTOCOL_IPV4V6 }
|
|
||||||
RadioButtonItem("PPP", protocol == PROTOCOL_PPP) { protocol = PROTOCOL_PPP }
|
|
||||||
if(VERSION.SDK_INT>=29) {
|
|
||||||
RadioButtonItem("non-IP", protocol == PROTOCOL_NON_IP) { protocol = PROTOCOL_NON_IP }
|
|
||||||
RadioButtonItem("Unstructured", protocol == PROTOCOL_UNSTRUCTURED) { protocol = PROTOCOL_UNSTRUCTURED }
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(text = stringResource(R.string.roaming_protocol), style = typography.titleLarge)
|
|
||||||
RadioButtonItem("IPV4", roamingProtocol == PROTOCOL_IP) { roamingProtocol = PROTOCOL_IP }
|
|
||||||
RadioButtonItem("IPV6", roamingProtocol == PROTOCOL_IPV6) { roamingProtocol = PROTOCOL_IPV6 }
|
|
||||||
RadioButtonItem("IPV4/IPV6", roamingProtocol == PROTOCOL_IPV4V6) { roamingProtocol = PROTOCOL_IPV4V6 }
|
|
||||||
RadioButtonItem("PPP", roamingProtocol == PROTOCOL_PPP) { roamingProtocol = PROTOCOL_PPP }
|
|
||||||
if(VERSION.SDK_INT>=29) {
|
|
||||||
RadioButtonItem("non-IP", roamingProtocol == PROTOCOL_NON_IP) { roamingProtocol = PROTOCOL_NON_IP }
|
|
||||||
RadioButtonItem("Unstructured", roamingProtocol == PROTOCOL_UNSTRUCTURED) { roamingProtocol = PROTOCOL_UNSTRUCTURED }
|
|
||||||
}
|
|
||||||
|
|
||||||
var finalStep by remember { mutableStateOf(false) }
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
if(!finalStep) {
|
|
||||||
builder.setCarrierEnabled(carrierEnabled)
|
|
||||||
builder.setApnName(inputApnName)
|
|
||||||
builder.setUser(user)
|
|
||||||
if(VERSION.SDK_INT>=33) { builder.setProfileId(profileId.toInt()) }
|
|
||||||
builder.setAuthType(selectedAuthType)
|
|
||||||
if(VERSION.SDK_INT>=29) { builder.setCarrierId(carrierId.toInt()) }
|
|
||||||
builder.setApnTypeBitmask(apnTypeBitmask.toInt())
|
|
||||||
builder.setEntryName(entryName)
|
|
||||||
if(VERSION.SDK_INT>=29) { builder.setMmsProxyAddress(mmsProxyAddress) }
|
|
||||||
builder.setMmsProxyPort(mmsProxyPort.toInt())
|
|
||||||
if(VERSION.SDK_INT>=29) { builder.setProxyAddress(proxyAddress) }
|
|
||||||
builder.setProxyPort(proxyPort.toInt())
|
|
||||||
builder.setMmsc(mmsc.toUri())
|
|
||||||
if(VERSION.SDK_INT>=33) { builder.setMtuV4(mtuV4.toInt()); builder.setMtuV6(mtuV6.toInt()) }
|
|
||||||
builder.setMvnoType(mvnoType)
|
|
||||||
builder.setNetworkTypeBitmask(networkTypeBitmask.toInt())
|
|
||||||
builder.setOperatorNumeric(operatorNumeric)
|
|
||||||
builder.setPassword(password)
|
|
||||||
if(VERSION.SDK_INT>=33) { builder.setPersistent(persistent) }
|
|
||||||
builder.setProtocol(protocol)
|
|
||||||
builder.setRoamingProtocol(roamingProtocol)
|
|
||||||
result = builder.build()
|
|
||||||
}
|
|
||||||
finalStep=!finalStep
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(stringResource(if(finalStep) R.string.previous_step else R.string.next_step))
|
|
||||||
}
|
|
||||||
AnimatedVisibility(finalStep) {
|
|
||||||
if(inputNum=="0") {
|
|
||||||
Button(
|
|
||||||
onClick = { dpm.addOverrideApn(receiver,result) },
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.create))
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
|
|
||||||
Button(
|
|
||||||
onClick = { context.showOperationResultToast(dpm.updateOverrideApn(receiver, id, result)) },
|
|
||||||
modifier = Modifier.fillMaxWidth(0.49F)
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.update))
|
|
||||||
}
|
|
||||||
Button(
|
|
||||||
onClick = { context.showOperationResultToast(dpm.removeOverrideApn(receiver,id)) },
|
|
||||||
modifier = Modifier.fillMaxWidth(0.96F)
|
|
||||||
) {
|
|
||||||
Text(stringResource(R.string.remove))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private data class ApnType(val id: Int, val name: String, val requiresApi: Int = 0)
|
||||||
|
@SuppressLint("InlinedApi")
|
||||||
|
private val apnTypes = listOf(
|
||||||
|
ApnType(ApnSetting.TYPE_DEFAULT, "Default"), ApnType(ApnSetting.TYPE_MMS, "MMS"), ApnType(ApnSetting.TYPE_SUPL, "SUPL"),
|
||||||
|
ApnType(ApnSetting.TYPE_DUN, "DUN"), ApnType(ApnSetting.TYPE_HIPRI, "HiPri"), ApnType(ApnSetting.TYPE_FOTA, "FOTA"),
|
||||||
|
ApnType(ApnSetting.TYPE_IMS, "IMS"), ApnType(ApnSetting.TYPE_CBS, "CBS"), ApnType(ApnSetting.TYPE_IA, "IA"),
|
||||||
|
ApnType(ApnSetting.TYPE_EMERGENCY, "Emergency"), ApnType(ApnSetting.TYPE_MCX, "MCX", 29), ApnType(ApnSetting.TYPE_XCAP, "XCAP", 30),
|
||||||
|
ApnType(ApnSetting.TYPE_BIP, "BIP", 31), ApnType(ApnSetting.TYPE_VSIM, "VSIM", 31), ApnType(ApnSetting.TYPE_ENTERPRISE, "Enterprise", 33),
|
||||||
|
ApnType(ApnSetting.TYPE_RCS, "RCS", 35) // TODO: Adapt A16 later
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable object AddApnSetting
|
||||||
|
|
||||||
|
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||||
|
@RequiresApi(28)
|
||||||
|
@Composable
|
||||||
|
fun AddApnSettingScreen(origin: ApnSetting?, onNavigateUp: () -> Unit) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val dpm = context.getDPM()
|
||||||
|
val receiver = context.getReceiver()
|
||||||
|
val fm = LocalFocusManager.current
|
||||||
|
var dropdown by remember { mutableIntStateOf(0) } // 1:Auth type, 2:MVNO type, 3:Protocol, 4:Roaming protocol
|
||||||
|
var dialog by remember { mutableIntStateOf(0) } // 1:Proxy, 2:MMS proxy
|
||||||
|
var enabled by remember { mutableStateOf(true) }
|
||||||
|
var apnName by remember { mutableStateOf(origin?.apnName ?: "") }
|
||||||
|
var entryName by remember { mutableStateOf(origin?.entryName ?: "") }
|
||||||
|
var apnType by remember { mutableIntStateOf(origin?.apnTypeBitmask ?: 0) }
|
||||||
|
var profileId by remember { mutableStateOf(if(VERSION.SDK_INT >= 33) origin?.profileId?.toString() ?: "" else "") }
|
||||||
|
var carrierId by remember { mutableStateOf(if(VERSION.SDK_INT >= 29) origin?.carrierId?.toString() ?: "" else "") }
|
||||||
|
var authType by remember { mutableIntStateOf(origin?.authType ?: ApnSetting.AUTH_TYPE_NONE) }
|
||||||
|
var user by remember { mutableStateOf(origin?.user ?: "") }
|
||||||
|
var password by remember { mutableStateOf(origin?.password ?: "") }
|
||||||
|
var proxyAddress by remember { mutableStateOf(if(VERSION.SDK_INT >= 29) origin?.proxyAddressAsString ?: "" else "") }
|
||||||
|
var proxyPort by remember { mutableStateOf(if(VERSION.SDK_INT >= 29) origin?.proxyPort?.toString() ?: "" else "") }
|
||||||
|
var mmsProxyAddress by remember { mutableStateOf(if(VERSION.SDK_INT >= 29) origin?.mmsProxyAddressAsString ?: "" else "") }
|
||||||
|
var mmsProxyPort by remember { mutableStateOf(if(VERSION.SDK_INT >= 29) origin?.mmsProxyPort?.toString() ?: "" else "") }
|
||||||
|
var mmsc by remember { mutableStateOf(origin?.mmsc?.toString() ?: "") }
|
||||||
|
var mtuV4 by remember { mutableStateOf(if(VERSION.SDK_INT >= 33) origin?.mtuV4?.toString() ?: "" else "") }
|
||||||
|
var mtuV6 by remember { mutableStateOf(if(VERSION.SDK_INT >= 33) origin?.mtuV6?.toString() ?: "" else "") }
|
||||||
|
var mvnoType by remember { mutableIntStateOf(origin?.mvnoType ?: ApnSetting.MVNO_TYPE_SPN) }
|
||||||
|
var networkTypeBitmask by remember { mutableStateOf(origin?.networkTypeBitmask?.toString() ?: "") }
|
||||||
|
var operatorNumeric by remember { mutableStateOf(origin?.operatorNumeric ?: "") }
|
||||||
|
var protocol by remember { mutableIntStateOf(origin?.protocol ?: ApnSetting.PROTOCOL_IP) }
|
||||||
|
var roamingProtocol by remember { mutableIntStateOf(origin?.roamingProtocol ?: ApnSetting.PROTOCOL_IP) }
|
||||||
|
var persistent by remember { mutableStateOf(if(VERSION.SDK_INT >= 33) origin?.isPersistent == true else false) }
|
||||||
|
var alwaysOn by remember { mutableStateOf(VERSION.SDK_INT >= 35 && origin?.isAlwaysOn == true) }
|
||||||
|
var errorMessage: String? by remember { mutableStateOf(null) }
|
||||||
|
MyScaffold(R.string.apn_setting, 8.dp, onNavigateUp, false) {
|
||||||
|
val protocolMap = mapOf(
|
||||||
|
ApnSetting.PROTOCOL_IP to "IPv4", ApnSetting.PROTOCOL_IPV6 to "IPv6",
|
||||||
|
ApnSetting.PROTOCOL_IPV4V6 to "IPv4/v6", ApnSetting.PROTOCOL_PPP to "PPP"
|
||||||
|
).let {
|
||||||
|
if(VERSION.SDK_INT >= 29) {
|
||||||
|
it.plus(listOf(ApnSetting.PROTOCOL_NON_IP to "Non-IP", ApnSetting.PROTOCOL_UNSTRUCTURED to "Unstructured"))
|
||||||
|
} else it
|
||||||
|
}
|
||||||
|
SwitchItem(R.string.enabled, state = enabled, onCheckedChange = { enabled = it }, padding = false)
|
||||||
|
OutlinedTextField(
|
||||||
|
apnName, { apnName = it }, Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(stringResource(R.string.apn_name) + " (*)") },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
entryName, { entryName = it }, Modifier.fillMaxWidth().padding(vertical = 4.dp),
|
||||||
|
label = { Text(stringResource(R.string.entry_name) + " (*)") },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.type) + " (*)", Modifier.padding(vertical = 4.dp), style = typography.titleLarge)
|
||||||
|
FlowRow(Modifier.padding(bottom = 4.dp)) {
|
||||||
|
apnTypes.filter { VERSION.SDK_INT >= it.requiresApi }.forEach {
|
||||||
|
FilterChip(
|
||||||
|
apnType and it.id == it.id, {
|
||||||
|
apnType = if(apnType and it.id == it.id) apnType and (apnType xor it.id) else apnType or it.id
|
||||||
|
},
|
||||||
|
{ Text(it.name) }, Modifier.padding(horizontal = 4.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT >= 33) OutlinedTextField(
|
||||||
|
profileId, { profileId = it }, Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(stringResource(R.string.profile_id)) }, isError = profileId.isNotEmpty() && profileId.toIntOrNull() == null,
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
if(VERSION.SDK_INT >= 29) OutlinedTextField(
|
||||||
|
carrierId, { carrierId = it }, Modifier.fillMaxWidth().padding(vertical = 4.dp),
|
||||||
|
label = { Text(stringResource(R.string.carrier_id)) },
|
||||||
|
isError = carrierId.isNotEmpty() && carrierId.toIntOrNull() == null,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
Row(Modifier.fillMaxWidth().padding(vertical = 10.dp), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
val rotate by animateFloatAsState(if(dropdown == 1) 180F else 0F)
|
||||||
|
val authTypeMap = mapOf(
|
||||||
|
ApnSetting.AUTH_TYPE_NONE to stringResource(R.string.none), ApnSetting.AUTH_TYPE_PAP to "PAP",
|
||||||
|
ApnSetting.AUTH_TYPE_CHAP to "CHAP", ApnSetting.AUTH_TYPE_PAP_OR_CHAP to "PAP/CHAP"
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.auth_type))
|
||||||
|
Row(Modifier.clickable { dropdown = 1 }.padding(4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(authTypeMap[authType]!!, Modifier.padding(2.dp))
|
||||||
|
Icon(Icons.Default.ArrowDropDown, null, Modifier.padding(start = 4.dp).rotate(rotate))
|
||||||
|
DropdownMenu(dropdown == 1, { dropdown = 0 }) {
|
||||||
|
authTypeMap.forEach {
|
||||||
|
DropdownMenuItem({ Text(it.value) }, { authType = it.key; dropdown = 0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
user, { user = it }, Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(stringResource(R.string.user)) },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
password, { password = it }, Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(stringResource(R.string.password)) },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
if(VERSION.SDK_INT >= 29) {
|
||||||
|
Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Column {
|
||||||
|
Text(stringResource(R.string.proxy), Modifier.padding(end = 8.dp))
|
||||||
|
Text(
|
||||||
|
if(proxyAddress.isEmpty()) stringResource(R.string.none) else "$proxyAddress:$proxyPort",
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant, style = typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TextButton({ dialog = 1 }) { Text(stringResource(R.string.edit)) }
|
||||||
|
}
|
||||||
|
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Column {
|
||||||
|
Text(stringResource(R.string.mms_proxy), Modifier.padding(end = 8.dp))
|
||||||
|
Text(
|
||||||
|
if(mmsProxyAddress.isEmpty()) stringResource(R.string.none) else "$mmsProxyAddress:$mmsProxyPort",
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant, style = typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TextButton({ dialog = 2 }) { Text(stringResource(R.string.edit)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
mmsc, { mmsc = it }, Modifier.fillMaxWidth(),
|
||||||
|
label = { Text("MMSC") },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
if(VERSION.SDK_INT >= 33) Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), Arrangement.SpaceBetween) {
|
||||||
|
val fr = FocusRequester()
|
||||||
|
OutlinedTextField(
|
||||||
|
mtuV4, { mtuV4 = it }, Modifier.fillMaxWidth(0.49F),
|
||||||
|
label = { Text("MTU (IPv4)") },
|
||||||
|
isError = !mtuV4.isEmpty() && mtuV4.toIntOrNull() == null,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions { fr.requestFocus() }
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
mtuV6, { mtuV6 = it }, Modifier.focusRequester(fr).fillMaxWidth(0.96F),
|
||||||
|
label = { Text("MTU (IPv6)") },
|
||||||
|
isError = !mtuV6.isEmpty() && mtuV6.toIntOrNull() == null,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Row(Modifier.fillMaxWidth().padding(vertical = 10.dp), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
val rotate by animateFloatAsState(if(dropdown == 2) 180F else 0F)
|
||||||
|
val mvnoTypeMap = mapOf(
|
||||||
|
ApnSetting.MVNO_TYPE_SPN to "SPM", ApnSetting.MVNO_TYPE_IMSI to "IMSI",
|
||||||
|
ApnSetting.MVNO_TYPE_GID to "GID", ApnSetting.MVNO_TYPE_ICCID to "ICCID"
|
||||||
|
)
|
||||||
|
Text(stringResource(R.string.mvno_type))
|
||||||
|
Row(Modifier.clickable { dropdown = 2 }.padding(4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(mvnoTypeMap[mvnoType]!!, Modifier.padding(4.dp))
|
||||||
|
Icon(Icons.Default.ArrowDropDown, null, Modifier.padding(start = 4.dp).rotate(rotate))
|
||||||
|
DropdownMenu(dropdown == 2, { dropdown = 0 }) {
|
||||||
|
mvnoTypeMap.forEach {
|
||||||
|
DropdownMenuItem({ Text(it.value) }, { mvnoType = it.key; dropdown = 0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutlinedTextField(
|
||||||
|
networkTypeBitmask, { networkTypeBitmask = it }, Modifier.fillMaxWidth(),
|
||||||
|
label = { Text(stringResource(R.string.network_type_bitmask)) },
|
||||||
|
isError = networkTypeBitmask.isNotEmpty() && networkTypeBitmask.toIntOrNull() == null,
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
operatorNumeric, { operatorNumeric = it }, Modifier.fillMaxWidth().padding(vertical = 4.dp),
|
||||||
|
label = { Text("Numeric operator ID") },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
Row(Modifier.fillMaxWidth().padding(vertical = 10.dp), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
val rotate by animateFloatAsState(if(dropdown == 3) 180F else 0F)
|
||||||
|
Text(stringResource(R.string.protocol))
|
||||||
|
Row(Modifier.clickable { dropdown = 3 }.padding(4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(protocolMap[protocol]!!, Modifier.padding(2.dp))
|
||||||
|
Icon(Icons.Default.ArrowDropDown, null, Modifier.padding(start = 4.dp).rotate(rotate))
|
||||||
|
DropdownMenu(dropdown == 3, { dropdown = 0 }) {
|
||||||
|
protocolMap.forEach {
|
||||||
|
DropdownMenuItem({ Text(it.value) }, { protocol = it.key; dropdown = 0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Row(Modifier.fillMaxWidth().padding(vertical = 10.dp), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
val rotate by animateFloatAsState(if(dropdown == 4) 180F else 0F)
|
||||||
|
Text(stringResource(R.string.roaming_protocol))
|
||||||
|
Row(Modifier.clickable { dropdown = 4 }.padding(4.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(protocolMap[roamingProtocol]!!, Modifier.padding(2.dp))
|
||||||
|
Icon(Icons.Default.ArrowDropDown, null, Modifier.padding(start = 4.dp).rotate(rotate))
|
||||||
|
DropdownMenu(dropdown == 4, { dropdown = 0 }) {
|
||||||
|
protocolMap.forEach {
|
||||||
|
DropdownMenuItem({ Text(it.value) }, { roamingProtocol = it.key; dropdown = 0 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(VERSION.SDK_INT >= 33) Row(Modifier.fillMaxWidth(), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
Text(stringResource(R.string.persistent))
|
||||||
|
Switch(persistent, { persistent = it })
|
||||||
|
}
|
||||||
|
Row(Modifier.fillMaxWidth(), Arrangement.SpaceBetween, Alignment.CenterVertically) {
|
||||||
|
Text(stringResource(R.string.always_on))
|
||||||
|
Switch(alwaysOn, { alwaysOn = it })
|
||||||
|
}
|
||||||
|
Button(
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
val setting = ApnSetting.Builder().apply {
|
||||||
|
setCarrierEnabled(enabled)
|
||||||
|
setApnName(apnName)
|
||||||
|
setEntryName(entryName)
|
||||||
|
setApnTypeBitmask(apnType)
|
||||||
|
setAuthType(authType)
|
||||||
|
setUser(user)
|
||||||
|
setPassword(password)
|
||||||
|
if(VERSION.SDK_INT >= 33) profileId.toIntOrNull()?.let { setProfileId(it) }
|
||||||
|
if(VERSION.SDK_INT >= 29) {
|
||||||
|
carrierId.toIntOrNull()?.let { setCarrierId(it) }
|
||||||
|
setProxyAddress(proxyAddress)
|
||||||
|
proxyPort.toIntOrNull()?.let { setProxyPort(it) }
|
||||||
|
setMmsProxyAddress(mmsProxyAddress)
|
||||||
|
mmsProxyPort.toIntOrNull()?.let { setMmsProxyPort(it) }
|
||||||
|
}
|
||||||
|
setMmsc(Uri.parse(mmsc))
|
||||||
|
if(VERSION.SDK_INT >= 33) {
|
||||||
|
mtuV4.toIntOrNull()?.let { setMtuV4(it) }
|
||||||
|
mtuV6.toIntOrNull()?.let { setMtuV6(it) }
|
||||||
|
}
|
||||||
|
setMvnoType(mvnoType)
|
||||||
|
networkTypeBitmask.toIntOrNull()?.let { setNetworkTypeBitmask(it) }
|
||||||
|
setOperatorNumeric(operatorNumeric)
|
||||||
|
setProtocol(protocol)
|
||||||
|
setRoamingProtocol(roamingProtocol)
|
||||||
|
if(VERSION.SDK_INT >= 33) setPersistent(persistent)
|
||||||
|
if(VERSION.SDK_INT >= 35) setAlwaysOn(alwaysOn)
|
||||||
|
}.build()
|
||||||
|
if(origin == null) {
|
||||||
|
dpm.addOverrideApn(receiver, setting)
|
||||||
|
} else {
|
||||||
|
dpm.updateOverrideApn(receiver, origin.id, setting)
|
||||||
|
}
|
||||||
|
onNavigateUp()
|
||||||
|
} catch(e: Exception) {
|
||||||
|
errorMessage = (e::class.qualifiedName ?: "") + "\n" + (e.message ?: "")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Modifier.fillMaxWidth().padding(vertical = 4.dp)
|
||||||
|
) {
|
||||||
|
Text(stringResource(if(origin != null) R.string.update else R.string.add))
|
||||||
|
}
|
||||||
|
if(origin != null) Button(
|
||||||
|
{
|
||||||
|
dpm.removeOverrideApn(receiver, origin.id)
|
||||||
|
onNavigateUp()
|
||||||
|
},
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
colors = ButtonDefaults.buttonColors(MaterialTheme.colorScheme.error, MaterialTheme.colorScheme.onError)
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.delete))
|
||||||
|
}
|
||||||
|
if(dialog != 0) {
|
||||||
|
var address by remember { mutableStateOf((if(dialog == 1) proxyAddress else mmsProxyAddress)) }
|
||||||
|
var port by remember { mutableStateOf((if(dialog == 1) proxyPort else mmsProxyPort)) }
|
||||||
|
val fr = FocusRequester()
|
||||||
|
AlertDialog(
|
||||||
|
title = { Text(if(dialog == 1) "Proxy" else "MMS proxy") },
|
||||||
|
text = {
|
||||||
|
val fm = LocalFocusManager.current
|
||||||
|
Column {
|
||||||
|
OutlinedTextField(
|
||||||
|
address, { address = it }, Modifier.fillMaxWidth().padding(bottom = 4.dp),
|
||||||
|
textStyle = typography.bodyLarge,
|
||||||
|
label = { Text(stringResource(R.string.address)) },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions { fr.requestFocus() }
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
port, { port = it }, Modifier.fillMaxWidth().focusRequester(fr),
|
||||||
|
textStyle = typography.bodyLarge,
|
||||||
|
isError = port.isNotEmpty() && port.toIntOrNull() == null,
|
||||||
|
label = { Text(stringResource(R.string.port)) },
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
|
||||||
|
keyboardActions = KeyboardActions { fm.clearFocus() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
TextButton(
|
||||||
|
{
|
||||||
|
if(dialog == 1) {
|
||||||
|
proxyAddress = address
|
||||||
|
proxyPort = port
|
||||||
|
} else {
|
||||||
|
mmsProxyAddress = address
|
||||||
|
mmsProxyPort = port
|
||||||
|
}
|
||||||
|
dialog = 0
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.confirm))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
TextButton({ dialog = 0 }) { Text(stringResource(R.string.cancel)) }
|
||||||
|
},
|
||||||
|
onDismissRequest = { dialog = 0 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(errorMessage != null) AlertDialog(
|
||||||
|
title = { Text(stringResource(R.string.error)) },
|
||||||
|
text = { Text(errorMessage ?: "") },
|
||||||
|
confirmButton = {
|
||||||
|
TextButton({ errorMessage = null }) { Text(stringResource(R.string.confirm)) }
|
||||||
|
},
|
||||||
|
onDismissRequest = { errorMessage = null }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,7 +39,6 @@
|
|||||||
<string name="apply">Применить</string>
|
<string name="apply">Применить</string>
|
||||||
<string name="decide_by_user">Определять пользователем</string>
|
<string name="decide_by_user">Определять пользователем</string>
|
||||||
<string name="unsupported">Не поддерживается</string>
|
<string name="unsupported">Не поддерживается</string>
|
||||||
<string name="developing">Разрабатываемая функция</string>
|
|
||||||
<string name="options">Опции</string>
|
<string name="options">Опции</string>
|
||||||
<string name="copy_command">Копировать команду</string>
|
<string name="copy_command">Копировать команду</string>
|
||||||
<string name="package_name">Имя пакета</string>
|
<string name="package_name">Имя пакета</string>
|
||||||
@@ -318,31 +317,30 @@
|
|||||||
<string name="included_uids">Включенные UID</string>
|
<string name="included_uids">Включенные UID</string>
|
||||||
<string name="excluded_uids">Исключенные UID</string>
|
<string name="excluded_uids">Исключенные UID</string>
|
||||||
<string name="one_uid_per_line">Один UID на строку</string>
|
<string name="one_uid_per_line">Один UID на строку</string>
|
||||||
<string name="override_apn_settings">Настройки APN</string>
|
<!--TODO: following 4 strings-->
|
||||||
<string name="total_apn_amount">Количество настроек APN: %1$s</string>
|
<string name="override_apn">Override APN</string>
|
||||||
<string name="select_a_apn_or_create">Выберите настройку APN для редактирования (1~%1$s) или введите 0, чтобы создать новую настройку APN.</string>
|
<string name="apn_setting">APN setting</string>
|
||||||
<string name="no_apn_you_should_create_one">Нет настроек APN. Будет создана новая.</string>
|
<string name="apn_name">APN name</string>
|
||||||
<string name="previous_step">Предыдущий шаг</string>
|
<string name="entry_name">Entry name</string>
|
||||||
<string name="next_step">Следующий шаг</string>
|
|
||||||
<string name="name">Имя</string>
|
<string name="name">Имя</string>
|
||||||
<string name="user_name">Имя пользователя</string>
|
|
||||||
<string name="profile_id">Идентификатор профиля</string>
|
<string name="profile_id">Идентификатор профиля</string>
|
||||||
<string name="auth_type">Тип аутентификации</string>
|
<string name="auth_type">Тип аутентификации</string>
|
||||||
<string name="apn_type">Тип APN</string>
|
|
||||||
<string name="bitmask">Битовая маска</string>
|
|
||||||
<string name="description">Описание</string>
|
<string name="description">Описание</string>
|
||||||
<string name="mms_proxy">MMS-прокси</string>
|
<string name="mms_proxy">MMS-прокси</string>
|
||||||
<string name="address">Адрес</string>
|
<string name="address">Адрес</string>
|
||||||
<string name="port">Порт</string>
|
<string name="port">Порт</string>
|
||||||
<string name="proxy">Прокси</string>
|
<string name="proxy">Прокси</string>
|
||||||
<string name="apn_network_type">Тип сети</string>
|
|
||||||
<string name="persistent">Постоянный</string>
|
<string name="persistent">Постоянный</string>
|
||||||
<string name="protocol">Протокол</string>
|
<string name="protocol">Протокол</string>
|
||||||
<string name="roaming_protocol">Протокол роуминга</string>
|
<string name="roaming_protocol">Протокол роуминга</string>
|
||||||
|
<!--TODO: following 4 strings-->
|
||||||
|
<string name="carrier_id">Carrier ID</string>
|
||||||
|
<string name="mvno_type">MVNO type</string>
|
||||||
|
<string name="network_type_bitmask">Network type bitmask</string>
|
||||||
|
<string name="always_on">Always on</string>
|
||||||
<string name="update">Обновить</string>
|
<string name="update">Обновить</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--Рабочий профиль-->
|
<!--Рабочий профиль-->
|
||||||
<string name="work_profile">Рабочий профиль</string>
|
<string name="work_profile">Рабочий профиль</string>
|
||||||
<string name="work_profile_owner">Владелец профиля (рабочий профиль)</string>
|
<string name="work_profile_owner">Владелец профиля (рабочий профиль)</string>
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
<string name="apply">Uygula</string>
|
<string name="apply">Uygula</string>
|
||||||
<string name="decide_by_user">Kullanıcı Tarafından Karar Ver</string>
|
<string name="decide_by_user">Kullanıcı Tarafından Karar Ver</string>
|
||||||
<string name="unsupported">Desteklenmiyor</string>
|
<string name="unsupported">Desteklenmiyor</string>
|
||||||
<string name="developing">Geliştirilen İşlev</string>
|
|
||||||
<string name="options">Seçenekler</string>
|
<string name="options">Seçenekler</string>
|
||||||
<string name="copy_command">Komutu Kopyala</string>
|
<string name="copy_command">Komutu Kopyala</string>
|
||||||
<string name="package_name">Paket Adı</string>
|
<string name="package_name">Paket Adı</string>
|
||||||
@@ -318,34 +317,34 @@
|
|||||||
<string name="export_logs">Export logs</string> <!--TODO-->
|
<string name="export_logs">Export logs</string> <!--TODO-->
|
||||||
<string name="wifi_auth_keypair">Wi-Fi anahtar çifti</string>
|
<string name="wifi_auth_keypair">Wi-Fi anahtar çifti</string>
|
||||||
<string name="preferential_network_service">Tercihli ağ hizmeti</string>
|
<string name="preferential_network_service">Tercihli ağ hizmeti</string>
|
||||||
<string name="add_config">Add config</string> <!--TODO-->
|
<!--TODO: following 11 strings-->
|
||||||
<string name="network_id">Network ID</string> <!--TODO-->
|
<string name="add_config">Add config</string>
|
||||||
<string name="allow_fallback_to_default_connection">Allow fallback to default connection</string> <!--TODO-->
|
<string name="network_id">Network ID</string>
|
||||||
<string name="block_non_matching_networks">Block non matching networks</string> <!--TODO-->
|
<string name="allow_fallback_to_default_connection">Allow fallback to default connection</string>
|
||||||
<string name="included_uids">Included UIDs</string> <!--TODO-->
|
<string name="block_non_matching_networks">Block non matching networks</string>
|
||||||
<string name="excluded_uids">Excluded UIDs</string> <!--TODO-->
|
<string name="included_uids">Included UIDs</string>
|
||||||
<string name="one_uid_per_line">One UID per line</string> <!--TODO-->
|
<string name="excluded_uids">Excluded UIDs</string>
|
||||||
<string name="override_apn_settings">APN ayarlarını geçersiz kıl</string>
|
<string name="one_uid_per_line">One UID per line</string>
|
||||||
<string name="total_apn_amount">APN ayarlarının toplamı: %1$s</string>
|
<string name="override_apn">Override APN</string>
|
||||||
<string name="select_a_apn_or_create">Düzenlemek istediğiniz APN ayarını seçin (1~%1$s) veya yeni bir APN ayarı oluşturmak için 0 girin.</string>
|
<string name="apn_setting">APN setting</string>
|
||||||
<string name="no_apn_you_should_create_one">APN ayarı yok. Yeni bir tane oluşturulacak.</string>
|
<string name="apn_name">APN name</string>
|
||||||
<string name="previous_step">Önceki adım</string>
|
<string name="entry_name">Entry name</string>
|
||||||
<string name="next_step">Sonraki adım</string>
|
|
||||||
<string name="name">İsim</string>
|
<string name="name">İsim</string>
|
||||||
<string name="user_name">Kullanıcı adı</string>
|
|
||||||
<string name="profile_id">Profil Kimliği</string>
|
<string name="profile_id">Profil Kimliği</string>
|
||||||
<string name="auth_type">Kimlik doğrulama türü</string>
|
<string name="auth_type">Kimlik doğrulama türü</string>
|
||||||
<string name="apn_type">APN türü</string>
|
|
||||||
<string name="bitmask">Bitmask</string>
|
|
||||||
<string name="description">Açıklama</string>
|
<string name="description">Açıklama</string>
|
||||||
<string name="mms_proxy">MMS proxy</string>
|
<string name="mms_proxy">MMS proxy</string>
|
||||||
<string name="address">Adres</string>
|
<string name="address">Adres</string>
|
||||||
<string name="port">Port</string>
|
<string name="port">Port</string>
|
||||||
<string name="proxy">Proxy</string>
|
<string name="proxy">Proxy</string>
|
||||||
<string name="apn_network_type">Ağ türü</string>
|
|
||||||
<string name="persistent">Kalıcı</string>
|
<string name="persistent">Kalıcı</string>
|
||||||
<string name="protocol">Protokol</string>
|
<string name="protocol">Protokol</string>
|
||||||
<string name="roaming_protocol">Dolaşım protokolü</string>
|
<string name="roaming_protocol">Dolaşım protokolü</string>
|
||||||
|
<!--TODO: following 4 strings-->
|
||||||
|
<string name="carrier_id">Carrier ID</string>
|
||||||
|
<string name="mvno_type">MVNO type</string>
|
||||||
|
<string name="network_type_bitmask">Network type bitmask</string>
|
||||||
|
<string name="always_on">Always on</string>
|
||||||
<string name="update">Güncelle</string>
|
<string name="update">Güncelle</string>
|
||||||
|
|
||||||
<!--WorkProfile-->
|
<!--WorkProfile-->
|
||||||
|
|||||||
@@ -39,7 +39,6 @@
|
|||||||
<string name="apply">应用</string>
|
<string name="apply">应用</string>
|
||||||
<string name="decide_by_user">由用户决定</string>
|
<string name="decide_by_user">由用户决定</string>
|
||||||
<string name="unsupported">不支持</string>
|
<string name="unsupported">不支持</string>
|
||||||
<string name="developing">功能开发中</string>
|
|
||||||
<string name="options">选项</string>
|
<string name="options">选项</string>
|
||||||
<string name="copy_command">复制代码</string>
|
<string name="copy_command">复制代码</string>
|
||||||
<string name="copy">复制</string>
|
<string name="copy">复制</string>
|
||||||
@@ -312,28 +311,26 @@
|
|||||||
<string name="block_non_matching_networks">阻止不匹配的网络</string>
|
<string name="block_non_matching_networks">阻止不匹配的网络</string>
|
||||||
<string name="included_uids">包含的UID</string>
|
<string name="included_uids">包含的UID</string>
|
||||||
<string name="excluded_uids">排除的UIDs</string>
|
<string name="excluded_uids">排除的UIDs</string>
|
||||||
<string name="one_uid_per_line">一行一个UID</string>
|
<string name="one_uid_per_line">每行一个UID</string>
|
||||||
<string name="override_apn_settings">APN设置</string>
|
<string name="override_apn">覆盖APN</string>
|
||||||
<string name="total_apn_amount">一共有%1$s个APN设置</string>
|
<string name="apn_setting">APN设置</string>
|
||||||
<string name="select_a_apn_or_create">选择一个你要修改的APN设置(1~%1$s)或者输入0以新建APN设置</string>
|
<string name="apn_name">APN名称</string>
|
||||||
<string name="no_apn_you_should_create_one">当前没有APN设置,你可以新建一个APN设置</string>
|
<string name="entry_name">条目名称</string>
|
||||||
<string name="previous_step">上一步</string>
|
|
||||||
<string name="next_step">下一步</string>
|
|
||||||
<string name="name">名称</string>
|
<string name="name">名称</string>
|
||||||
<string name="user_name">用户名</string>
|
|
||||||
<string name="profile_id">资料ID</string>
|
<string name="profile_id">资料ID</string>
|
||||||
<string name="auth_type">验证类型</string>
|
<string name="auth_type">认证类型</string>
|
||||||
<string name="apn_type">APN类型</string>
|
|
||||||
<string name="bitmask">位掩码</string>
|
|
||||||
<string name="description">描述</string>
|
<string name="description">描述</string>
|
||||||
<string name="mms_proxy">MMS代理</string>
|
<string name="mms_proxy">MMS代理</string>
|
||||||
<string name="address">地址</string>
|
<string name="address">地址</string>
|
||||||
<string name="port">端口</string>
|
<string name="port">端口</string>
|
||||||
<string name="proxy">代理</string>
|
<string name="proxy">代理</string>
|
||||||
<string name="apn_network_type">网络类型</string>
|
<string name="persistent">持久化</string>
|
||||||
<string name="persistent">持久的</string>
|
|
||||||
<string name="protocol">协议</string>
|
<string name="protocol">协议</string>
|
||||||
<string name="roaming_protocol">漫游协议</string>
|
<string name="roaming_protocol">漫游协议</string>
|
||||||
|
<string name="carrier_id">运营商ID</string>
|
||||||
|
<string name="mvno_type">MVNO类型</string>
|
||||||
|
<string name="network_type_bitmask">网络类型位掩码</string>
|
||||||
|
<string name="always_on">总是开启</string>
|
||||||
<string name="update">更新</string>
|
<string name="update">更新</string>
|
||||||
|
|
||||||
<!--WorkProfile-->
|
<!--WorkProfile-->
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
<string name="apply">Apply</string>
|
<string name="apply">Apply</string>
|
||||||
<string name="decide_by_user">Decide by user</string>
|
<string name="decide_by_user">Decide by user</string>
|
||||||
<string name="unsupported">Unsupported</string>
|
<string name="unsupported">Unsupported</string>
|
||||||
<string name="developing">Developing function</string>
|
|
||||||
<string name="options">Options</string>
|
<string name="options">Options</string>
|
||||||
<string name="copy_command">Copy Command</string>
|
<string name="copy_command">Copy Command</string>
|
||||||
<string name="package_name">Package name</string>
|
<string name="package_name">Package name</string>
|
||||||
@@ -346,27 +345,25 @@
|
|||||||
<string name="included_uids">Included UIDs</string>
|
<string name="included_uids">Included UIDs</string>
|
||||||
<string name="excluded_uids">Excluded UIDs</string>
|
<string name="excluded_uids">Excluded UIDs</string>
|
||||||
<string name="one_uid_per_line">One UID per line</string>
|
<string name="one_uid_per_line">One UID per line</string>
|
||||||
<string name="override_apn_settings">APN settings</string>
|
<string name="override_apn">Override APN</string>
|
||||||
<string name="total_apn_amount">APN settings amount: %1$s</string>
|
<string name="apn_setting">APN setting</string>
|
||||||
<string name="select_a_apn_or_create">Select an APN setting you want to edit (1~%1$s) or enter 0 to create a new APN setting. </string>
|
<string name="apn_name">APN name</string>
|
||||||
<string name="no_apn_you_should_create_one">No APN settings. Will create a new one. </string>
|
<string name="entry_name">Entry name</string>
|
||||||
<string name="previous_step">Previous step</string>
|
|
||||||
<string name="next_step">Next step</string>
|
|
||||||
<string name="name">Name</string>
|
<string name="name">Name</string>
|
||||||
<string name="user_name">User name</string>
|
|
||||||
<string name="profile_id">Profile ID</string>
|
<string name="profile_id">Profile ID</string>
|
||||||
<string name="auth_type">Auth type</string>
|
<string name="auth_type">Auth type</string>
|
||||||
<string name="apn_type">APN type</string>
|
|
||||||
<string name="bitmask">Bitmask</string>
|
|
||||||
<string name="description">Description</string>
|
<string name="description">Description</string>
|
||||||
<string name="mms_proxy">MMS proxy</string>
|
<string name="mms_proxy">MMS proxy</string>
|
||||||
<string name="address">Address</string>
|
<string name="address">Address</string>
|
||||||
<string name="port">Port</string>
|
<string name="port">Port</string>
|
||||||
<string name="proxy">Proxy</string>
|
<string name="proxy">Proxy</string>
|
||||||
<string name="apn_network_type">Network type</string>
|
|
||||||
<string name="persistent">Persistent</string>
|
<string name="persistent">Persistent</string>
|
||||||
<string name="protocol">Protocol</string>
|
<string name="protocol">Protocol</string>
|
||||||
<string name="roaming_protocol">Roaming protocol</string>
|
<string name="roaming_protocol">Roaming protocol</string>
|
||||||
|
<string name="carrier_id">Carrier ID</string>
|
||||||
|
<string name="mvno_type">MVNO type</string>
|
||||||
|
<string name="network_type_bitmask">Network type bitmask</string>
|
||||||
|
<string name="always_on">Always on</string>
|
||||||
<string name="update">Update</string>
|
<string name="update">Update</string>
|
||||||
|
|
||||||
<!--WorkProfile-->
|
<!--WorkProfile-->
|
||||||
|
|||||||
Reference in New Issue
Block a user