Support latest SACC features
This commit is contained in:
@@ -231,7 +231,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
return null
|
||||
}
|
||||
private suspend fun updateConfiguration(config: SoftApConfigurationCompat) {
|
||||
config.requireSingleBand()
|
||||
val (band, channel) = config.requireSingleBand()
|
||||
if (RepeaterService.safeMode) {
|
||||
RepeaterService.networkName = config.ssid
|
||||
RepeaterService.deviceAddress = config.bssid
|
||||
@@ -248,8 +248,8 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
}
|
||||
holder.config = null
|
||||
}
|
||||
RepeaterService.operatingBand = config.band
|
||||
RepeaterService.operatingChannel = config.channel
|
||||
RepeaterService.operatingBand = band
|
||||
RepeaterService.operatingChannel = channel
|
||||
RepeaterService.isAutoShutdownEnabled = config.isAutoShutdownEnabled
|
||||
RepeaterService.shutdownTimeoutMillis = config.shutdownTimeoutMillis
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.os.Parcelable
|
||||
import android.util.SparseIntArray
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.os.BuildCompat
|
||||
import androidx.core.util.keyIterator
|
||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||
import be.mygod.vpnhotspot.net.MacAddressCompat.Companion.toCompat
|
||||
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
||||
@@ -24,6 +25,11 @@ data class SoftApConfigurationCompat(
|
||||
var bssidAddr: Long? = null,
|
||||
var passphrase: String? = null,
|
||||
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)
|
||||
var channels: SparseIntArray = SparseIntArray(1).apply { put(BAND_2GHZ, 0) },
|
||||
var securityType: Int = SoftApConfiguration.SECURITY_TYPE_OPEN,
|
||||
@@ -333,25 +339,38 @@ data class SoftApConfigurationCompat(
|
||||
set(value) {
|
||||
bssidAddr = value?.addr
|
||||
}
|
||||
@get:Deprecated("Use channels", ReplaceWith("channels.keyAt(0)"))
|
||||
@get:TargetApi(23)
|
||||
val band get() = channels.keyAt(0)
|
||||
@get:Deprecated("Use channels", ReplaceWith("channels.valueAt(0)"))
|
||||
@get:TargetApi(23)
|
||||
val channel get() = channels.valueAt(0)
|
||||
|
||||
/**
|
||||
* Only single band/channel can be supplied on API 23-30
|
||||
*/
|
||||
fun requireSingleBand(): Pair<Int, Int> {
|
||||
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) {
|
||||
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) {
|
||||
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:
|
||||
* 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()")
|
||||
@Suppress("DEPRECATION")
|
||||
fun toWifiConfiguration(): android.net.wifi.WifiConfiguration {
|
||||
requireSingleBand()
|
||||
val (band, channel) = requireSingleBand()
|
||||
val wc = underlying as? android.net.wifi.WifiConfiguration
|
||||
val result = if (wc == null) android.net.wifi.WifiConfiguration() else android.net.wifi.WifiConfiguration(wc)
|
||||
val original = wc?.toCompat()
|
||||
@@ -373,8 +392,10 @@ data class SoftApConfigurationCompat(
|
||||
apBand.setInt(result, when (band) {
|
||||
BAND_2GHZ -> 0
|
||||
BAND_5GHZ -> 1
|
||||
BAND_2GHZ or BAND_5GHZ, BAND_ANY -> -1
|
||||
else -> throw IllegalArgumentException("Convert fail, unsupported band setting :$band")
|
||||
else -> (-1).also {
|
||||
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)
|
||||
} 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,
|
||||
securityType)
|
||||
if (BuildCompat.isAtLeastS()) setChannels(builder, channels) else {
|
||||
requireSingleBand()
|
||||
@Suppress("DEPRECATION")
|
||||
val (band, channel) = requireSingleBand()
|
||||
if (channel == 0) setBand(builder, band) else setChannel(builder, channel, band)
|
||||
}
|
||||
setBssid(builder, bssid?.toPlatform())
|
||||
|
||||
@@ -10,13 +10,16 @@ import android.os.Parcelable
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.Base64
|
||||
import android.util.SparseIntArray
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Spinner
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.os.BuildCompat
|
||||
import androidx.core.view.isGone
|
||||
import be.mygod.librootkotlinx.toByteArray
|
||||
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.widget.SmartSnackbar
|
||||
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
|
||||
@@ -40,27 +44,30 @@ import kotlinx.parcelize.Parcelize
|
||||
* Related: https://android.googlesource.com/platform/packages/apps/Settings/+/defb1183ecb00d6231bac7d934d07f58f90261ea
|
||||
*/
|
||||
class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiApDialogFragment.Arg>(), TextWatcher,
|
||||
Toolbar.OnMenuItemClickListener {
|
||||
Toolbar.OnMenuItemClickListener, AdapterView.OnItemSelectedListener {
|
||||
companion object {
|
||||
private const val BASE64_FLAGS = Base64.NO_PADDING or Base64.NO_WRAP
|
||||
private val nonMacChars = "[^0-9a-fA-F:]+".toRegex()
|
||||
private val channels by lazy {
|
||||
val list = ArrayList<BandOption.Channel>()
|
||||
for (chan in 1..14) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_2GHZ, chan))
|
||||
for (chan in 1..196) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_5GHZ, chan))
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
for (chan in 1..253) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_6GHZ, chan))
|
||||
}
|
||||
list
|
||||
private val baseOptions by lazy { listOf(ChannelOption.Disabled, ChannelOption.Auto) }
|
||||
private val channels2G by lazy {
|
||||
baseOptions + (1..14).map { ChannelOption(it, SoftApConfigurationCompat.BAND_2GHZ) }
|
||||
}
|
||||
private val channels5G by lazy {
|
||||
baseOptions + (1..196).map { ChannelOption(it, SoftApConfigurationCompat.BAND_5GHZ) }
|
||||
}
|
||||
@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
|
||||
*/
|
||||
private val p2pChannels by lazy {
|
||||
(1..165).map {
|
||||
val band = if (it <= 14) SoftApConfigurationCompat.BAND_2GHZ else SoftApConfigurationCompat.BAND_5GHZ
|
||||
BandOption.Channel(band, it)
|
||||
}
|
||||
baseOptions + (15..165).map { ChannelOption(it, SoftApConfigurationCompat.BAND_5GHZ) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,35 +80,20 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
*/
|
||||
val p2pMode: Boolean = false) : Parcelable
|
||||
|
||||
private sealed class BandOption {
|
||||
open val band get() = SoftApConfigurationCompat.BAND_ANY
|
||||
open val channel get() = 0
|
||||
|
||||
object BandAny : BandOption() {
|
||||
private open class ChannelOption(val channel: Int = 0, val band: Int = 0) {
|
||||
object Disabled : ChannelOption(-1) {
|
||||
override fun toString() = app.getString(R.string.wifi_ap_choose_disabled)
|
||||
}
|
||||
object Auto : ChannelOption() {
|
||||
override fun toString() = app.getString(R.string.wifi_ap_choose_auto)
|
||||
}
|
||||
object Band2GHz : BandOption() {
|
||||
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)"
|
||||
}
|
||||
override fun toString() = "${SoftApConfigurationCompat.channelToFrequency(band, channel)} MHz ($channel)"
|
||||
}
|
||||
|
||||
private lateinit var dialogView: DialogWifiApBinding
|
||||
private lateinit var bandOptions: MutableList<BandOption>
|
||||
private lateinit var base: SoftApConfigurationCompat
|
||||
private var started = false
|
||||
private val currentChannels5G get() = if (arg.p2pMode && !RepeaterService.safeMode) p2pChannels else channels5G
|
||||
override val ret get() = Arg(generateConfig())
|
||||
|
||||
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 (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
||||
val bandOption = dialogView.band.selectedItem as BandOption
|
||||
setChannel(bandOption.channel, bandOption.band)
|
||||
val channels = SparseIntArray(4)
|
||||
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) {
|
||||
MacAddressCompat.fromString(dialogView.bssid.text.toString())
|
||||
@@ -131,6 +130,10 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
.filter { it.isNotEmpty() }.map { MacAddressCompat.fromString(it).toPlatform() }
|
||||
blockedClientList = (dialogView.blockedList.text ?: "").split(nonMacChars)
|
||||
.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)
|
||||
dialogView.timeout.addTextChangedListener(this@WifiApDialogFragment)
|
||||
} else dialogView.timeoutWrapper.isGone = true
|
||||
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) dialogView.band.apply {
|
||||
bandOptions = mutableListOf<BandOption>().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 {
|
||||
fun Spinner.configure(options: List<ChannelOption>) {
|
||||
adapter = ArrayAdapter(activity, android.R.layout.simple_spinner_item, 0, options).apply {
|
||||
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)
|
||||
if (arg.p2pMode) dialogView.hiddenSsid.isGone = true
|
||||
if (arg.p2pMode || Build.VERSION.SDK_INT < 30) {
|
||||
@@ -196,10 +195,25 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
dialogView.blockedList.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
|
||||
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() {
|
||||
dialogView.ssid.setText(base.ssid)
|
||||
if (!arg.p2pMode) dialogView.security.setSelection(base.securityType)
|
||||
@@ -207,10 +221,10 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
dialogView.autoShutdown.isChecked = base.isAutoShutdownEnabled
|
||||
dialogView.timeout.setText(base.shutdownTimeoutMillis.let { if (it == 0L) "" else it.toString() })
|
||||
if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) {
|
||||
val selection = if (base.channel != 0) {
|
||||
bandOptions.indexOfFirst { it.channel == base.channel }
|
||||
} else bandOptions.indexOfFirst { it.band == base.band }
|
||||
dialogView.band.setSelection(if (selection == -1) 0 else selection)
|
||||
dialogView.band2G.setSelection(locate(SoftApConfigurationCompat.BAND_2GHZ, channels2G))
|
||||
dialogView.band5G.setSelection(locate(SoftApConfigurationCompat.BAND_5GHZ, currentChannels5G))
|
||||
dialogView.band6G.setSelection(locate(SoftApConfigurationCompat.BAND_6GHZ, channels6G))
|
||||
dialogView.band60G.setSelection(locate(SoftApConfigurationCompat.BAND_60GHZ, channels60G))
|
||||
}
|
||||
dialogView.bssid.setText(base.bssid?.toString())
|
||||
dialogView.hiddenSsid.isChecked = base.isHiddenSsid
|
||||
@@ -218,6 +232,11 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
dialogView.clientUserControl.isChecked = base.isClientControlByUserEnabled
|
||||
dialogView.blockedList.setText(base.blockedClientList.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() {
|
||||
@@ -253,6 +272,29 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
}
|
||||
}
|
||||
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
|
||||
val bssidValid = dialogView.bssid.length() == 0 || try {
|
||||
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 &&
|
||||
allowedListError == null
|
||||
(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
|
||||
}
|
||||
|
||||
@@ -297,6 +339,9 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
||||
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 {
|
||||
return when (item?.itemId) {
|
||||
android.R.id.copy -> {
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
android:maxLength="19" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/band_wrapper"
|
||||
android:id="@+id/band_wrapper_2G"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dip"
|
||||
@@ -129,14 +129,71 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/wifi_item_label"
|
||||
android:text="@string/wifi_hotspot_ap_band_title" />
|
||||
android:text="@string/wifi_ap_choose_2G" />
|
||||
<Spinner
|
||||
android:id="@+id/band"
|
||||
android:id="@+id/band_2G"
|
||||
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_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>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/bssid_wrapper"
|
||||
@@ -216,6 +273,38 @@
|
||||
style="@style/wifi_item_edit_content"
|
||||
android:inputType="textMultiLine|textNoSuggestions" />
|
||||
</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>
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -172,16 +172,22 @@
|
||||
<string name="wifi_hotspot_timeout">关闭延迟</string>
|
||||
<string name="wifi_hotspot_timeout_default">默认延迟:%d 毫秒</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_2G" msgid="8724267386885036210">"2.4 GHz 频段"</string>
|
||||
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">"5.0 GHz 频段"</string>
|
||||
<string name="wifi_ap_choose_6G">6.0 GHz 频段</string>
|
||||
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">"5 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_hidden_network" msgid="973162091800925000">"隐藏的网络"</string>
|
||||
<string name="wifi_max_clients">允许连接设备数上限</string>
|
||||
<string name="wifi_client_user_control">过滤可以连接的设备</string>
|
||||
<string name="wifi_blocked_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>
|
||||
|
||||
<!-- 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_default">默認延遲:%d 毫秒</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_2G" msgid="8724267386885036210">2.4 GHz 頻帶</string>
|
||||
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">5.0 GHz 頻帶</string>
|
||||
<string name="wifi_ap_choose_6G">6.0 GHz 頻帶</string>
|
||||
<string name="wifi_ap_choose_5G" msgid="8813128641914385634">5 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_hidden_network" msgid="973162091800925000">"隱藏的網路"</string>
|
||||
<string name="wifi_max_clients">允許的連接裝置數量</string>
|
||||
<string name="wifi_client_user_control">過濾可以連接的裝置</string>
|
||||
<string name="wifi_blocked_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>
|
||||
|
||||
<!-- 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_default">Default timeout: %dms</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_2G">2.4 GHz Band</string>
|
||||
<string name="wifi_ap_choose_5G">5.0 GHz Band</string>
|
||||
<string name="wifi_ap_choose_6G">6.0 GHz Band</string>
|
||||
<string name="wifi_ap_choose_5G">5 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_hidden_network">Hidden network</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_blocked_list">Blocked 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>
|
||||
|
||||
<!-- Based on: https://github.com/PrivacyApps/donations/blob/747d36a18433c7e9329691054122a8ad337a62d2/Donations/src/main/res/values/donations__strings.xml -->
|
||||
|
||||
Reference in New Issue
Block a user