Support latest SACC features
This commit is contained in:
@@ -231,7 +231,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
private suspend fun updateConfiguration(config: SoftApConfigurationCompat) {
|
private suspend fun updateConfiguration(config: SoftApConfigurationCompat) {
|
||||||
config.requireSingleBand()
|
val (band, channel) = config.requireSingleBand()
|
||||||
if (RepeaterService.safeMode) {
|
if (RepeaterService.safeMode) {
|
||||||
RepeaterService.networkName = config.ssid
|
RepeaterService.networkName = config.ssid
|
||||||
RepeaterService.deviceAddress = config.bssid
|
RepeaterService.deviceAddress = config.bssid
|
||||||
@@ -248,8 +248,8 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
}
|
}
|
||||||
holder.config = null
|
holder.config = null
|
||||||
}
|
}
|
||||||
RepeaterService.operatingBand = config.band
|
RepeaterService.operatingBand = band
|
||||||
RepeaterService.operatingChannel = config.channel
|
RepeaterService.operatingChannel = channel
|
||||||
RepeaterService.isAutoShutdownEnabled = config.isAutoShutdownEnabled
|
RepeaterService.isAutoShutdownEnabled = config.isAutoShutdownEnabled
|
||||||
RepeaterService.shutdownTimeoutMillis = config.shutdownTimeoutMillis
|
RepeaterService.shutdownTimeoutMillis = config.shutdownTimeoutMillis
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.os.Parcelable
|
|||||||
import android.util.SparseIntArray
|
import android.util.SparseIntArray
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.os.BuildCompat
|
import androidx.core.os.BuildCompat
|
||||||
|
import androidx.core.util.keyIterator
|
||||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||||
import be.mygod.vpnhotspot.net.MacAddressCompat.Companion.toCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat.Companion.toCompat
|
||||||
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
||||||
@@ -24,6 +25,11 @@ data class SoftApConfigurationCompat(
|
|||||||
var bssidAddr: Long? = null,
|
var bssidAddr: Long? = null,
|
||||||
var passphrase: String? = null,
|
var passphrase: String? = null,
|
||||||
var isHiddenSsid: Boolean = false,
|
var isHiddenSsid: Boolean = false,
|
||||||
|
/**
|
||||||
|
* To read legacy band/channel pair, use [requireSingleBand]. For easy access, see [getChannel].
|
||||||
|
*
|
||||||
|
* You should probably not set or modify this field directly. Use [optimizeChannels] or [setChannel].
|
||||||
|
*/
|
||||||
@TargetApi(23)
|
@TargetApi(23)
|
||||||
var channels: SparseIntArray = SparseIntArray(1).apply { put(BAND_2GHZ, 0) },
|
var channels: SparseIntArray = SparseIntArray(1).apply { put(BAND_2GHZ, 0) },
|
||||||
var securityType: Int = SoftApConfiguration.SECURITY_TYPE_OPEN,
|
var securityType: Int = SoftApConfiguration.SECURITY_TYPE_OPEN,
|
||||||
@@ -333,25 +339,38 @@ data class SoftApConfigurationCompat(
|
|||||||
set(value) {
|
set(value) {
|
||||||
bssidAddr = value?.addr
|
bssidAddr = value?.addr
|
||||||
}
|
}
|
||||||
@get:Deprecated("Use channels", ReplaceWith("channels.keyAt(0)"))
|
|
||||||
@get:TargetApi(23)
|
/**
|
||||||
val band get() = channels.keyAt(0)
|
* Only single band/channel can be supplied on API 23-30
|
||||||
@get:Deprecated("Use channels", ReplaceWith("channels.valueAt(0)"))
|
*/
|
||||||
@get:TargetApi(23)
|
fun requireSingleBand(): Pair<Int, Int> {
|
||||||
val channel get() = channels.valueAt(0)
|
require(channels.size() == 1) { "Unsupported number of bands configured" }
|
||||||
|
return channels.keyAt(0) to channels.valueAt(0)
|
||||||
|
}
|
||||||
|
fun getChannel(band: Int): Int {
|
||||||
|
var result = -1
|
||||||
|
for (b in channels.keyIterator()) if (band and b == band) {
|
||||||
|
require(result == -1) { "Duplicate band found" }
|
||||||
|
result = channels[b]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
fun setChannel(channel: Int, band: Int = BAND_ANY) {
|
fun setChannel(channel: Int, band: Int = BAND_ANY) {
|
||||||
channels = SparseIntArray(1).apply { put(band, channel) }
|
channels = SparseIntArray(1).apply { put(band, channel) }
|
||||||
}
|
}
|
||||||
|
fun optimizeChannels(channels: SparseIntArray = this.channels) {
|
||||||
|
this.channels = SparseIntArray(channels.size()).apply {
|
||||||
|
var setBand = 0
|
||||||
|
for (band in channels.keyIterator()) if (channels[band] == 0) setBand = setBand or band
|
||||||
|
if (setBand != 0) put(setBand, 0) // merge all bands into one
|
||||||
|
for (band in channels.keyIterator()) if (band and setBand == 0) put(band, channels[band])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setMacRandomizationEnabled(enabled: Boolean) {
|
fun setMacRandomizationEnabled(enabled: Boolean) {
|
||||||
macRandomizationSetting = if (enabled) RANDOMIZATION_PERSISTENT else RANDOMIZATION_NONE
|
macRandomizationSetting = if (enabled) RANDOMIZATION_PERSISTENT else RANDOMIZATION_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Only single band/channel can be supplied on API 23-30
|
|
||||||
*/
|
|
||||||
fun requireSingleBand() = require(channels.size() == 1) { "Unsupported number of bands configured" }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on:
|
* Based on:
|
||||||
* https://android.googlesource.com/platform/packages/apps/Settings/+/android-5.0.0_r1/src/com/android/settings/wifi/WifiApDialog.java#88
|
* https://android.googlesource.com/platform/packages/apps/Settings/+/android-5.0.0_r1/src/com/android/settings/wifi/WifiApDialog.java#88
|
||||||
@@ -362,7 +381,7 @@ data class SoftApConfigurationCompat(
|
|||||||
@Deprecated("Class deprecated in framework, use toPlatform().toWifiConfiguration()")
|
@Deprecated("Class deprecated in framework, use toPlatform().toWifiConfiguration()")
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
fun toWifiConfiguration(): android.net.wifi.WifiConfiguration {
|
fun toWifiConfiguration(): android.net.wifi.WifiConfiguration {
|
||||||
requireSingleBand()
|
val (band, channel) = requireSingleBand()
|
||||||
val wc = underlying as? android.net.wifi.WifiConfiguration
|
val wc = underlying as? android.net.wifi.WifiConfiguration
|
||||||
val result = if (wc == null) android.net.wifi.WifiConfiguration() else android.net.wifi.WifiConfiguration(wc)
|
val result = if (wc == null) android.net.wifi.WifiConfiguration() else android.net.wifi.WifiConfiguration(wc)
|
||||||
val original = wc?.toCompat()
|
val original = wc?.toCompat()
|
||||||
@@ -373,8 +392,10 @@ data class SoftApConfigurationCompat(
|
|||||||
apBand.setInt(result, when (band) {
|
apBand.setInt(result, when (band) {
|
||||||
BAND_2GHZ -> 0
|
BAND_2GHZ -> 0
|
||||||
BAND_5GHZ -> 1
|
BAND_5GHZ -> 1
|
||||||
BAND_2GHZ or BAND_5GHZ, BAND_ANY -> -1
|
else -> (-1).also {
|
||||||
else -> throw IllegalArgumentException("Convert fail, unsupported band setting :$band")
|
require(Build.VERSION.SDK_INT >= 28) { "A band must be specified on this platform" }
|
||||||
|
require(isLegacyEitherBand(band)) { "Convert fail, unsupported band setting :$band" }
|
||||||
|
}
|
||||||
})
|
})
|
||||||
apChannel.setInt(result, channel)
|
apChannel.setInt(result, channel)
|
||||||
} else require(isLegacyEitherBand(band)) { "Specifying band is unsupported on this platform" }
|
} else require(isLegacyEitherBand(band)) { "Specifying band is unsupported on this platform" }
|
||||||
@@ -405,8 +426,7 @@ data class SoftApConfigurationCompat(
|
|||||||
setPassphrase(builder, if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) null else passphrase,
|
setPassphrase(builder, if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) null else passphrase,
|
||||||
securityType)
|
securityType)
|
||||||
if (BuildCompat.isAtLeastS()) setChannels(builder, channels) else {
|
if (BuildCompat.isAtLeastS()) setChannels(builder, channels) else {
|
||||||
requireSingleBand()
|
val (band, channel) = requireSingleBand()
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
if (channel == 0) setBand(builder, band) else setChannel(builder, channel, band)
|
if (channel == 0) setBand(builder, band) else setChannel(builder, channel, band)
|
||||||
}
|
}
|
||||||
setBssid(builder, bssid?.toPlatform())
|
setBssid(builder, bssid?.toPlatform())
|
||||||
|
|||||||
@@ -10,13 +10,16 @@ import android.os.Parcelable
|
|||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
|
import android.util.SparseIntArray
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.AdapterView
|
import android.widget.AdapterView
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.Spinner
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import androidx.core.os.BuildCompat
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import be.mygod.librootkotlinx.toByteArray
|
import be.mygod.librootkotlinx.toByteArray
|
||||||
import be.mygod.librootkotlinx.toParcelable
|
import be.mygod.librootkotlinx.toParcelable
|
||||||
@@ -32,6 +35,7 @@ import be.mygod.vpnhotspot.util.readableMessage
|
|||||||
import be.mygod.vpnhotspot.util.showAllowingStateLoss
|
import be.mygod.vpnhotspot.util.showAllowingStateLoss
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on: https://android.googlesource.com/platform/packages/apps/Settings/+/39b4674/src/com/android/settings/wifi/WifiApDialog.java
|
* Based on: https://android.googlesource.com/platform/packages/apps/Settings/+/39b4674/src/com/android/settings/wifi/WifiApDialog.java
|
||||||
@@ -40,27 +44,30 @@ import kotlinx.parcelize.Parcelize
|
|||||||
* Related: https://android.googlesource.com/platform/packages/apps/Settings/+/defb1183ecb00d6231bac7d934d07f58f90261ea
|
* Related: https://android.googlesource.com/platform/packages/apps/Settings/+/defb1183ecb00d6231bac7d934d07f58f90261ea
|
||||||
*/
|
*/
|
||||||
class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiApDialogFragment.Arg>(), TextWatcher,
|
class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiApDialogFragment.Arg>(), TextWatcher,
|
||||||
Toolbar.OnMenuItemClickListener {
|
Toolbar.OnMenuItemClickListener, AdapterView.OnItemSelectedListener {
|
||||||
companion object {
|
companion object {
|
||||||
private const val BASE64_FLAGS = Base64.NO_PADDING or Base64.NO_WRAP
|
private const val BASE64_FLAGS = Base64.NO_PADDING or Base64.NO_WRAP
|
||||||
private val nonMacChars = "[^0-9a-fA-F:]+".toRegex()
|
private val nonMacChars = "[^0-9a-fA-F:]+".toRegex()
|
||||||
private val channels by lazy {
|
private val baseOptions by lazy { listOf(ChannelOption.Disabled, ChannelOption.Auto) }
|
||||||
val list = ArrayList<BandOption.Channel>()
|
private val channels2G by lazy {
|
||||||
for (chan in 1..14) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_2GHZ, chan))
|
baseOptions + (1..14).map { ChannelOption(it, SoftApConfigurationCompat.BAND_2GHZ) }
|
||||||
for (chan in 1..196) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_5GHZ, chan))
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 30) {
|
private val channels5G by lazy {
|
||||||
for (chan in 1..253) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_6GHZ, chan))
|
baseOptions + (1..196).map { ChannelOption(it, SoftApConfigurationCompat.BAND_5GHZ) }
|
||||||
}
|
}
|
||||||
list
|
@get:RequiresApi(30)
|
||||||
|
private val channels6G by lazy {
|
||||||
|
baseOptions + (1..233).map { ChannelOption(it, SoftApConfigurationCompat.BAND_6GHZ) }
|
||||||
|
}
|
||||||
|
@get:RequiresApi(31)
|
||||||
|
private val channels60G by lazy {
|
||||||
|
baseOptions + (1..6).map { ChannelOption(it, SoftApConfigurationCompat.BAND_60GHZ) }
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Source: https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/c2fc6a1/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java#1396
|
* Source: https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/c2fc6a1/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java#1396
|
||||||
*/
|
*/
|
||||||
private val p2pChannels by lazy {
|
private val p2pChannels by lazy {
|
||||||
(1..165).map {
|
baseOptions + (15..165).map { ChannelOption(it, SoftApConfigurationCompat.BAND_5GHZ) }
|
||||||
val band = if (it <= 14) SoftApConfigurationCompat.BAND_2GHZ else SoftApConfigurationCompat.BAND_5GHZ
|
|
||||||
BandOption.Channel(band, it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,35 +80,20 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
*/
|
*/
|
||||||
val p2pMode: Boolean = false) : Parcelable
|
val p2pMode: Boolean = false) : Parcelable
|
||||||
|
|
||||||
private sealed class BandOption {
|
private open class ChannelOption(val channel: Int = 0, val band: Int = 0) {
|
||||||
open val band get() = SoftApConfigurationCompat.BAND_ANY
|
object Disabled : ChannelOption(-1) {
|
||||||
open val channel get() = 0
|
override fun toString() = app.getString(R.string.wifi_ap_choose_disabled)
|
||||||
|
}
|
||||||
object BandAny : BandOption() {
|
object Auto : ChannelOption() {
|
||||||
override fun toString() = app.getString(R.string.wifi_ap_choose_auto)
|
override fun toString() = app.getString(R.string.wifi_ap_choose_auto)
|
||||||
}
|
}
|
||||||
object Band2GHz : BandOption() {
|
override fun toString() = "${SoftApConfigurationCompat.channelToFrequency(band, channel)} MHz ($channel)"
|
||||||
override val band get() = SoftApConfigurationCompat.BAND_2GHZ
|
|
||||||
override fun toString() = app.getString(R.string.wifi_ap_choose_2G)
|
|
||||||
}
|
|
||||||
object Band5GHz : BandOption() {
|
|
||||||
override val band get() = SoftApConfigurationCompat.BAND_5GHZ
|
|
||||||
override fun toString() = app.getString(R.string.wifi_ap_choose_5G)
|
|
||||||
}
|
|
||||||
@RequiresApi(30)
|
|
||||||
object Band6GHz : BandOption() {
|
|
||||||
override val band get() = SoftApConfigurationCompat.BAND_6GHZ
|
|
||||||
override fun toString() = app.getString(R.string.wifi_ap_choose_6G)
|
|
||||||
}
|
|
||||||
class Channel(override val band: Int, override val channel: Int) : BandOption() {
|
|
||||||
override fun toString() = "${SoftApConfigurationCompat.channelToFrequency(band, channel)} MHz ($channel)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var dialogView: DialogWifiApBinding
|
private lateinit var dialogView: DialogWifiApBinding
|
||||||
private lateinit var bandOptions: MutableList<BandOption>
|
|
||||||
private lateinit var base: SoftApConfigurationCompat
|
private lateinit var base: SoftApConfigurationCompat
|
||||||
private var started = false
|
private var started = false
|
||||||
|
private val currentChannels5G get() = if (arg.p2pMode && !RepeaterService.safeMode) p2pChannels else channels5G
|
||||||
override val ret get() = Arg(generateConfig())
|
override val ret get() = Arg(generateConfig())
|
||||||
|
|
||||||
private fun generateConfig(full: Boolean = true) = base.copy(
|
private fun generateConfig(full: Boolean = true) = base.copy(
|
||||||
@@ -117,8 +109,15 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
if (text.isNullOrEmpty()) 0 else text.toString().toLong()
|
if (text.isNullOrEmpty()) 0 else text.toString().toLong()
|
||||||
}
|
}
|
||||||
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
||||||
val bandOption = dialogView.band.selectedItem as BandOption
|
val channels = SparseIntArray(4)
|
||||||
setChannel(bandOption.channel, bandOption.band)
|
for ((band, spinner) in arrayOf(SoftApConfigurationCompat.BAND_2GHZ to dialogView.band2G,
|
||||||
|
SoftApConfigurationCompat.BAND_5GHZ to dialogView.band5G,
|
||||||
|
SoftApConfigurationCompat.BAND_6GHZ to dialogView.band6G,
|
||||||
|
SoftApConfigurationCompat.BAND_60GHZ to dialogView.band60G)) {
|
||||||
|
val channel = (spinner.selectedItem as ChannelOption?)?.channel
|
||||||
|
if (channel != null && channel >= 0) channels.put(band, channel)
|
||||||
|
}
|
||||||
|
optimizeChannels(channels)
|
||||||
}
|
}
|
||||||
bssid = if (dialogView.bssid.length() != 0) {
|
bssid = if (dialogView.bssid.length() != 0) {
|
||||||
MacAddressCompat.fromString(dialogView.bssid.text.toString())
|
MacAddressCompat.fromString(dialogView.bssid.text.toString())
|
||||||
@@ -131,6 +130,10 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
.filter { it.isNotEmpty() }.map { MacAddressCompat.fromString(it).toPlatform() }
|
.filter { it.isNotEmpty() }.map { MacAddressCompat.fromString(it).toPlatform() }
|
||||||
blockedClientList = (dialogView.blockedList.text ?: "").split(nonMacChars)
|
blockedClientList = (dialogView.blockedList.text ?: "").split(nonMacChars)
|
||||||
.filter { it.isNotEmpty() }.map { MacAddressCompat.fromString(it).toPlatform() }
|
.filter { it.isNotEmpty() }.map { MacAddressCompat.fromString(it).toPlatform() }
|
||||||
|
setMacRandomizationEnabled(dialogView.macRandomization.isChecked)
|
||||||
|
isBridgedModeOpportunisticShutdownEnabled = dialogView.bridgedModeOpportunisticShutdown.isChecked
|
||||||
|
isIeee80211axEnabled = dialogView.ieee80211ax.isChecked
|
||||||
|
isUserConfiguration = dialogView.userConfig.isChecked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,27 +166,23 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
TetherTimeoutMonitor.defaultTimeout)
|
TetherTimeoutMonitor.defaultTimeout)
|
||||||
dialogView.timeout.addTextChangedListener(this@WifiApDialogFragment)
|
dialogView.timeout.addTextChangedListener(this@WifiApDialogFragment)
|
||||||
} else dialogView.timeoutWrapper.isGone = true
|
} else dialogView.timeoutWrapper.isGone = true
|
||||||
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) dialogView.band.apply {
|
fun Spinner.configure(options: List<ChannelOption>) {
|
||||||
bandOptions = mutableListOf<BandOption>().apply {
|
adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_item, 0, options).apply {
|
||||||
if (arg.p2pMode) {
|
|
||||||
add(BandOption.BandAny)
|
|
||||||
if (RepeaterService.safeMode) {
|
|
||||||
add(BandOption.Band2GHz)
|
|
||||||
add(BandOption.Band5GHz)
|
|
||||||
addAll(channels)
|
|
||||||
} else addAll(p2pChannels)
|
|
||||||
} else {
|
|
||||||
if (Build.VERSION.SDK_INT >= 28) add(BandOption.BandAny)
|
|
||||||
add(BandOption.Band2GHz)
|
|
||||||
add(BandOption.Band5GHz)
|
|
||||||
if (Build.VERSION.SDK_INT >= 30) add(BandOption.Band6GHz)
|
|
||||||
addAll(channels)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_item, 0, bandOptions).apply {
|
|
||||||
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||||
}
|
}
|
||||||
} else dialogView.bandWrapper.isGone = true
|
onItemSelectedListener = this@WifiApDialogFragment
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
||||||
|
dialogView.band2G.configure(channels2G)
|
||||||
|
dialogView.band5G.configure(currentChannels5G)
|
||||||
|
} else {
|
||||||
|
dialogView.bandWrapper2G.isGone = true
|
||||||
|
dialogView.bandWrapper5G.isGone = true
|
||||||
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 30 && !arg.p2pMode) dialogView.band6G.configure(channels6G)
|
||||||
|
else dialogView.bandWrapper6G.isGone = true
|
||||||
|
if (BuildCompat.isAtLeastS() && !arg.p2pMode) dialogView.band60G.configure(channels60G)
|
||||||
|
else dialogView.bandWrapper60G.isGone = true
|
||||||
dialogView.bssid.addTextChangedListener(this@WifiApDialogFragment)
|
dialogView.bssid.addTextChangedListener(this@WifiApDialogFragment)
|
||||||
if (arg.p2pMode) dialogView.hiddenSsid.isGone = true
|
if (arg.p2pMode) dialogView.hiddenSsid.isGone = true
|
||||||
if (arg.p2pMode || Build.VERSION.SDK_INT < 30) {
|
if (arg.p2pMode || Build.VERSION.SDK_INT < 30) {
|
||||||
@@ -196,10 +195,25 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
dialogView.blockedList.addTextChangedListener(this@WifiApDialogFragment)
|
dialogView.blockedList.addTextChangedListener(this@WifiApDialogFragment)
|
||||||
dialogView.allowedList.addTextChangedListener(this@WifiApDialogFragment)
|
dialogView.allowedList.addTextChangedListener(this@WifiApDialogFragment)
|
||||||
}
|
}
|
||||||
|
if (arg.p2pMode && Build.VERSION.SDK_INT >= 29) dialogView.macRandomization.isEnabled = false
|
||||||
|
else if (arg.p2pMode || !BuildCompat.isAtLeastS()) dialogView.macRandomization.isGone = true
|
||||||
|
if (arg.p2pMode || !BuildCompat.isAtLeastS()) {
|
||||||
|
dialogView.bridgedModeOpportunisticShutdown.isGone = true
|
||||||
|
dialogView.ieee80211ax.isGone = true
|
||||||
|
dialogView.userConfig.isGone = true
|
||||||
|
}
|
||||||
base = arg.configuration
|
base = arg.configuration
|
||||||
populateFromConfiguration()
|
populateFromConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun locate(band: Int, channels: List<ChannelOption>): Int {
|
||||||
|
val channel = base.getChannel(band)
|
||||||
|
val selection = channels.indexOfFirst { it.channel == channel }
|
||||||
|
return if (selection == -1) {
|
||||||
|
Timber.w(Exception("Unable to locate $band, $channel, ${arg.p2pMode && !RepeaterService.safeMode}"))
|
||||||
|
0
|
||||||
|
} else selection
|
||||||
|
}
|
||||||
private fun populateFromConfiguration() {
|
private fun populateFromConfiguration() {
|
||||||
dialogView.ssid.setText(base.ssid)
|
dialogView.ssid.setText(base.ssid)
|
||||||
if (!arg.p2pMode) dialogView.security.setSelection(base.securityType)
|
if (!arg.p2pMode) dialogView.security.setSelection(base.securityType)
|
||||||
@@ -207,10 +221,10 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
dialogView.autoShutdown.isChecked = base.isAutoShutdownEnabled
|
dialogView.autoShutdown.isChecked = base.isAutoShutdownEnabled
|
||||||
dialogView.timeout.setText(base.shutdownTimeoutMillis.let { if (it == 0L) "" else it.toString() })
|
dialogView.timeout.setText(base.shutdownTimeoutMillis.let { if (it == 0L) "" else it.toString() })
|
||||||
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
||||||
val selection = if (base.channel != 0) {
|
dialogView.band2G.setSelection(locate(SoftApConfigurationCompat.BAND_2GHZ, channels2G))
|
||||||
bandOptions.indexOfFirst { it.channel == base.channel }
|
dialogView.band5G.setSelection(locate(SoftApConfigurationCompat.BAND_5GHZ, currentChannels5G))
|
||||||
} else bandOptions.indexOfFirst { it.band == base.band }
|
dialogView.band6G.setSelection(locate(SoftApConfigurationCompat.BAND_6GHZ, channels6G))
|
||||||
dialogView.band.setSelection(if (selection == -1) 0 else selection)
|
dialogView.band60G.setSelection(locate(SoftApConfigurationCompat.BAND_60GHZ, channels60G))
|
||||||
}
|
}
|
||||||
dialogView.bssid.setText(base.bssid?.toString())
|
dialogView.bssid.setText(base.bssid?.toString())
|
||||||
dialogView.hiddenSsid.isChecked = base.isHiddenSsid
|
dialogView.hiddenSsid.isChecked = base.isHiddenSsid
|
||||||
@@ -218,6 +232,11 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
dialogView.clientUserControl.isChecked = base.isClientControlByUserEnabled
|
dialogView.clientUserControl.isChecked = base.isClientControlByUserEnabled
|
||||||
dialogView.blockedList.setText(base.blockedClientList.joinToString("\n"))
|
dialogView.blockedList.setText(base.blockedClientList.joinToString("\n"))
|
||||||
dialogView.allowedList.setText(base.allowedClientList.joinToString("\n"))
|
dialogView.allowedList.setText(base.allowedClientList.joinToString("\n"))
|
||||||
|
dialogView.macRandomization.isChecked =
|
||||||
|
base.macRandomizationSetting == SoftApConfigurationCompat.RANDOMIZATION_PERSISTENT
|
||||||
|
dialogView.bridgedModeOpportunisticShutdown.isChecked = base.isBridgedModeOpportunisticShutdownEnabled
|
||||||
|
dialogView.ieee80211ax.isChecked = base.isIeee80211axEnabled
|
||||||
|
dialogView.userConfig.isChecked = base.isUserConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
@@ -253,6 +272,29 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialogView.timeoutWrapper.error = timeoutError
|
dialogView.timeoutWrapper.error = timeoutError
|
||||||
|
val isBandValid = when {
|
||||||
|
arg.p2pMode || Build.VERSION.SDK_INT in 23 until 30 -> {
|
||||||
|
val option5G = dialogView.band5G.selectedItem
|
||||||
|
when (dialogView.band2G.selectedItem) {
|
||||||
|
is ChannelOption.Disabled -> option5G !is ChannelOption.Disabled &&
|
||||||
|
(!arg.p2pMode || RepeaterService.safeMode || option5G !is ChannelOption.Auto)
|
||||||
|
is ChannelOption.Auto ->
|
||||||
|
(arg.p2pMode || Build.VERSION.SDK_INT >= 28) && option5G is ChannelOption.Auto ||
|
||||||
|
(!arg.p2pMode || RepeaterService.safeMode) && option5G is ChannelOption.Disabled
|
||||||
|
else -> option5G is ChannelOption.Disabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Build.VERSION.SDK_INT == 30 -> {
|
||||||
|
var expected = 1
|
||||||
|
var set = 0
|
||||||
|
for (s in arrayOf(dialogView.band2G, dialogView.band5G, dialogView.band6G)) when (s.selectedItem) {
|
||||||
|
is ChannelOption.Auto -> expected = 0
|
||||||
|
!is ChannelOption.Disabled -> ++set
|
||||||
|
}
|
||||||
|
set == expected
|
||||||
|
}
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
dialogView.bssidWrapper.error = null
|
dialogView.bssidWrapper.error = null
|
||||||
val bssidValid = dialogView.bssid.length() == 0 || try {
|
val bssidValid = dialogView.bssid.length() == 0 || try {
|
||||||
MacAddressCompat.fromString(dialogView.bssid.text.toString())
|
MacAddressCompat.fromString(dialogView.bssid.text.toString())
|
||||||
@@ -289,7 +331,7 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
val canCopy = timeoutError == null && bssidValid && maxClientError == null && blockedListError == null &&
|
val canCopy = timeoutError == null && bssidValid && maxClientError == null && blockedListError == null &&
|
||||||
allowedListError == null
|
allowedListError == null
|
||||||
(dialog as? AlertDialog)?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled =
|
(dialog as? AlertDialog)?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled =
|
||||||
ssidLength in 1..32 && passwordValid && canCopy
|
ssidLength in 1..32 && passwordValid && isBandValid && canCopy
|
||||||
dialogView.toolbar.menu.findItem(android.R.id.copy).isEnabled = canCopy
|
dialogView.toolbar.menu.findItem(android.R.id.copy).isEnabled = canCopy
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +339,9 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
||||||
override fun afterTextChanged(editable: Editable) = validate()
|
override fun afterTextChanged(editable: Editable) = validate()
|
||||||
|
|
||||||
|
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) = validate()
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) = error("unreachable")
|
||||||
|
|
||||||
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
override fun onMenuItemClick(item: MenuItem?): Boolean {
|
||||||
return when (item?.itemId) {
|
return when (item?.itemId) {
|
||||||
android.R.id.copy -> {
|
android.R.id.copy -> {
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
android:maxLength="19" />
|
android:maxLength="19" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/band_wrapper"
|
android:id="@+id/band_wrapper_2G"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dip"
|
android:layout_marginTop="8dip"
|
||||||
@@ -129,14 +129,71 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
style="@style/wifi_item_label"
|
style="@style/wifi_item_label"
|
||||||
android:text="@string/wifi_hotspot_ap_band_title" />
|
android:text="@string/wifi_ap_choose_2G" />
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/band"
|
android:id="@+id/band_2G"
|
||||||
style="@style/wifi_item_content"
|
style="@style/wifi_item_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minHeight="@dimen/touch_target_min"
|
android:minHeight="@dimen/touch_target_min"
|
||||||
android:prompt="@string/wifi_hotspot_ap_band_title" />
|
android:prompt="@string/wifi_ap_choose_2G" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/band_wrapper_5G"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:text="@string/wifi_ap_choose_5G" />
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/band_5G"
|
||||||
|
style="@style/wifi_item_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:prompt="@string/wifi_ap_choose_5G" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/band_wrapper_6G"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:text="@string/wifi_ap_choose_6G" />
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/band_6G"
|
||||||
|
style="@style/wifi_item_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:prompt="@string/wifi_ap_choose_6G" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/band_wrapper_60G"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:text="@string/wifi_ap_choose_60G" />
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/band_60G"
|
||||||
|
style="@style/wifi_item_content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:prompt="@string/wifi_ap_choose_60G" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/bssid_wrapper"
|
android:id="@+id/bssid_wrapper"
|
||||||
@@ -216,6 +273,38 @@
|
|||||||
style="@style/wifi_item_edit_content"
|
style="@style/wifi_item_edit_content"
|
||||||
android:inputType="textMultiLine|textNoSuggestions" />
|
android:inputType="textMultiLine|textNoSuggestions" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/mac_randomization"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:text="@string/wifi_mac_randomization" />
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/bridged_mode_opportunistic_shutdown"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:text="@string/wifi_bridged_mode_opportunistic_shutdown" />
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/ieee_80211ax"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:text="@string/wifi_ieee_80211ax" />
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/user_config"
|
||||||
|
style="@style/wifi_item_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dip"
|
||||||
|
android:minHeight="@dimen/touch_target_min"
|
||||||
|
android:text="@string/wifi_user_config" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -172,16 +172,22 @@
|
|||||||
<string name="wifi_hotspot_timeout">关闭延迟</string>
|
<string name="wifi_hotspot_timeout">关闭延迟</string>
|
||||||
<string name="wifi_hotspot_timeout_default">默认延迟:%d 毫秒</string>
|
<string name="wifi_hotspot_timeout_default">默认延迟:%d 毫秒</string>
|
||||||
<string name="wifi_hotspot_ap_band_title" msgid="1165801173359290681">"AP 频段"</string>
|
<string name="wifi_hotspot_ap_band_title" msgid="1165801173359290681">"AP 频段"</string>
|
||||||
|
<string name="wifi_ap_choose_disabled">Disabled</string>
|
||||||
<string name="wifi_ap_choose_auto" msgid="2677800651271769965">"自动"</string>
|
<string name="wifi_ap_choose_auto" msgid="2677800651271769965">"自动"</string>
|
||||||
<string name="wifi_ap_choose_2G" msgid="8724267386885036210">"2.4 GHz 频段"</string>
|
<string name="wifi_ap_choose_2G" msgid="8724267386885036210">"2.4 GHz 频段"</string>
|
||||||
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">"5.0 GHz 频段"</string>
|
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">"5 GHz 频段"</string>
|
||||||
<string name="wifi_ap_choose_6G">6.0 GHz 频段</string>
|
<string name="wifi_ap_choose_6G">6 GHz 频段</string>
|
||||||
|
<string name="wifi_ap_choose_60G">60 GHz 频段</string>
|
||||||
<string name="wifi_advanced_mac_address_title" msgid="6571335466330978393">"MAC 地址"</string>
|
<string name="wifi_advanced_mac_address_title" msgid="6571335466330978393">"MAC 地址"</string>
|
||||||
<string name="wifi_hidden_network" msgid="973162091800925000">"隐藏的网络"</string>
|
<string name="wifi_hidden_network" msgid="973162091800925000">"隐藏的网络"</string>
|
||||||
<string name="wifi_max_clients">允许连接设备数上限</string>
|
<string name="wifi_max_clients">允许连接设备数上限</string>
|
||||||
<string name="wifi_client_user_control">过滤可以连接的设备</string>
|
<string name="wifi_client_user_control">过滤可以连接的设备</string>
|
||||||
<string name="wifi_blocked_list">设备黑名单</string>
|
<string name="wifi_blocked_list">设备黑名单</string>
|
||||||
<string name="wifi_allowed_list">设备白名单</string>
|
<string name="wifi_allowed_list">设备白名单</string>
|
||||||
|
<string name="wifi_mac_randomization">随机生成 MAC 地址</string>
|
||||||
|
<string name="wifi_bridged_mode_opportunistic_shutdown">启用桥接模式伺机关闭</string>
|
||||||
|
<string name="wifi_ieee_80211ax">启用 Wi\u2011Fi 6</string>
|
||||||
|
<string name="wifi_user_config">用户提供配置</string>
|
||||||
<string name="wifi_save" msgid="3331121567988522826">"保存"</string>
|
<string name="wifi_save" msgid="3331121567988522826">"保存"</string>
|
||||||
|
|
||||||
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-zh/donations__strings.xml -->
|
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-zh/donations__strings.xml -->
|
||||||
|
|||||||
@@ -176,16 +176,20 @@
|
|||||||
<string name="wifi_hotspot_timeout">關閉延遲時間</string>
|
<string name="wifi_hotspot_timeout">關閉延遲時間</string>
|
||||||
<string name="wifi_hotspot_timeout_default">默認延遲:%d 毫秒</string>
|
<string name="wifi_hotspot_timeout_default">默認延遲:%d 毫秒</string>
|
||||||
<string name="wifi_hotspot_ap_band_title" msgid="1165801173359290681">AP 頻帶</string>
|
<string name="wifi_hotspot_ap_band_title" msgid="1165801173359290681">AP 頻帶</string>
|
||||||
|
<string name="wifi_ap_choose_disabled">Disabled</string>
|
||||||
<string name="wifi_ap_choose_auto" msgid="2677800651271769965">自動</string>
|
<string name="wifi_ap_choose_auto" msgid="2677800651271769965">自動</string>
|
||||||
<string name="wifi_ap_choose_2G" msgid="8724267386885036210">2.4 GHz 頻帶</string>
|
<string name="wifi_ap_choose_2G" msgid="8724267386885036210">2.4 GHz 頻帶</string>
|
||||||
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">5.0 GHz 頻帶</string>
|
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">5 GHz 頻帶</string>
|
||||||
<string name="wifi_ap_choose_6G">6.0 GHz 頻帶</string>
|
<string name="wifi_ap_choose_6G">6 GHz 頻帶</string>
|
||||||
|
<string name="wifi_ap_choose_60G">60 GHz 頻帶</string>
|
||||||
<string name="wifi_advanced_mac_address_title" msgid="6571335466330978393">"MAC 地址"</string>
|
<string name="wifi_advanced_mac_address_title" msgid="6571335466330978393">"MAC 地址"</string>
|
||||||
<string name="wifi_hidden_network" msgid="973162091800925000">"隱藏的網路"</string>
|
<string name="wifi_hidden_network" msgid="973162091800925000">"隱藏的網路"</string>
|
||||||
<string name="wifi_max_clients">允許的連接裝置數量</string>
|
<string name="wifi_max_clients">允許的連接裝置數量</string>
|
||||||
<string name="wifi_client_user_control">過濾可以連接的裝置</string>
|
<string name="wifi_client_user_control">過濾可以連接的裝置</string>
|
||||||
<string name="wifi_blocked_list">裝置黑名單</string>
|
<string name="wifi_blocked_list">裝置黑名單</string>
|
||||||
<string name="wifi_allowed_list">裝置白名單</string>
|
<string name="wifi_allowed_list">裝置白名單</string>
|
||||||
|
<string name="wifi_mac_randomization">隨機化 MAC 位址</string>
|
||||||
|
<string name="wifi_ieee_80211ax">啟用 Wi\u2011Fi 6</string>
|
||||||
<string name="wifi_save" msgid="3331121567988522826">儲存</string>
|
<string name="wifi_save" msgid="3331121567988522826">儲存</string>
|
||||||
|
|
||||||
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-zh/donations__strings.xml -->
|
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values-zh/donations__strings.xml -->
|
||||||
|
|||||||
@@ -194,16 +194,22 @@
|
|||||||
<string name="wifi_hotspot_timeout">Inactive timeout</string>
|
<string name="wifi_hotspot_timeout">Inactive timeout</string>
|
||||||
<string name="wifi_hotspot_timeout_default">Default timeout: %dms</string>
|
<string name="wifi_hotspot_timeout_default">Default timeout: %dms</string>
|
||||||
<string name="wifi_hotspot_ap_band_title">AP Band</string>
|
<string name="wifi_hotspot_ap_band_title">AP Band</string>
|
||||||
|
<string name="wifi_ap_choose_disabled">Disabled</string>
|
||||||
<string name="wifi_ap_choose_auto">Auto</string>
|
<string name="wifi_ap_choose_auto">Auto</string>
|
||||||
<string name="wifi_ap_choose_2G">2.4 GHz Band</string>
|
<string name="wifi_ap_choose_2G">2.4 GHz Band</string>
|
||||||
<string name="wifi_ap_choose_5G">5.0 GHz Band</string>
|
<string name="wifi_ap_choose_5G">5 GHz Band</string>
|
||||||
<string name="wifi_ap_choose_6G">6.0 GHz Band</string>
|
<string name="wifi_ap_choose_6G">6 GHz Band</string>
|
||||||
|
<string name="wifi_ap_choose_60G">60 GHz Band</string>
|
||||||
<string name="wifi_advanced_mac_address_title">MAC address</string>
|
<string name="wifi_advanced_mac_address_title">MAC address</string>
|
||||||
<string name="wifi_hidden_network">Hidden network</string>
|
<string name="wifi_hidden_network">Hidden network</string>
|
||||||
<string name="wifi_max_clients">Maximum number of clients</string>
|
<string name="wifi_max_clients">Maximum number of clients</string>
|
||||||
<string name="wifi_client_user_control">Control which client can use hotspot</string>
|
<string name="wifi_client_user_control">Control which client can use hotspot</string>
|
||||||
<string name="wifi_blocked_list">Blocked list of clients</string>
|
<string name="wifi_blocked_list">Blocked list of clients</string>
|
||||||
<string name="wifi_allowed_list">Allowed list of clients</string>
|
<string name="wifi_allowed_list">Allowed list of clients</string>
|
||||||
|
<string name="wifi_mac_randomization">Use randomized MAC</string>
|
||||||
|
<string name="wifi_bridged_mode_opportunistic_shutdown">Enable bridged mode opportunistic shutdown</string>
|
||||||
|
<string name="wifi_ieee_80211ax">Enable Wi\u2011Fi 6</string>
|
||||||
|
<string name="wifi_user_config">User Supplied Configuration</string>
|
||||||
<string name="wifi_save">Save</string>
|
<string name="wifi_save">Save</string>
|
||||||
|
|
||||||
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values/donations__strings.xml -->
|
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values/donations__strings.xml -->
|
||||||
|
|||||||
Reference in New Issue
Block a user