Support latest SACC features

This commit is contained in:
Mygod
2021-05-30 01:03:18 -04:00
parent ada55a1bf6
commit a6819a1def
7 changed files with 260 additions and 90 deletions

View File

@@ -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
} }

View File

@@ -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())

View File

@@ -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 -> {

View File

@@ -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>

View File

@@ -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 -->

View File

@@ -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 -->

View File

@@ -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 -->