diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt index db80c986..87bf7403 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt @@ -1,7 +1,9 @@ package be.mygod.vpnhotspot.manage import android.annotation.TargetApi +import android.content.ClipData import android.content.Intent +import android.net.MacAddress import android.os.Build import android.provider.Settings import android.view.View @@ -161,6 +163,14 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(), capability = maxSupportedClients to supportedFeatures data.notifyChange() } + override fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) { + SmartSnackbar.make(parent.getString(R.string.tethering_manage_wifi_client_blocked, client, + WifiApManager.clientBlockLookup(blockedReason, true))).apply { + action(R.string.tethering_manage_wifi_copy_mac) { + app.clipboard.setPrimaryClip(ClipData.newPlainText(null, client.toString())) + } + }.show() + } override val title get() = parent.getString(R.string.tethering_manage_wifi) override val tetherType get() = TetherType.WIFI diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt index 62f3b61c..460a3dd3 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApConfigurationCompat.kt @@ -33,9 +33,9 @@ data class SoftApConfigurationCompat( @TargetApi(30) var isClientControlByUserEnabled: Boolean = false, @RequiresApi(30) - var blockedClientList: List = emptyList(), + var blockedClientList: List = emptyList(), @RequiresApi(30) - var allowedClientList: List = emptyList(), + var allowedClientList: List = emptyList(), var underlying: Parcelable? = null) : Parcelable { companion object { const val BAND_2GHZ = 1 @@ -238,8 +238,8 @@ data class SoftApConfigurationCompat( isAutoShutdownEnabled(this) as Boolean, getShutdownTimeoutMillis(this) as Long, isClientControlByUserEnabled(this) as Boolean, - getBlockedClientList(this) as List, - getAllowedClientList(this) as List, + getBlockedClientList(this) as List, + getAllowedClientList(this) as List, this) } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt index 2d4a9b84..09b827b0 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApDialogFragment.kt @@ -1,8 +1,10 @@ package be.mygod.vpnhotspot.net.wifi import android.annotation.SuppressLint +import android.annotation.TargetApi import android.content.ClipData import android.content.DialogInterface +import android.net.MacAddress import android.net.wifi.SoftApConfiguration import android.os.Build import android.os.Parcelable @@ -42,6 +44,7 @@ class WifiApDialogFragment : AlertDialogFragment() for (chan in 1..14) list.add(BandOption.Channel(SoftApConfigurationCompat.BAND_2GHZ, chan)) @@ -109,7 +112,7 @@ class WifiApDialogFragment : AlertDialogFragment if (text.isNullOrEmpty()) 0 else text.toString().toLong() @@ -120,6 +123,14 @@ class WifiApDialogFragment : AlertDialogFragment + if (text.isNullOrEmpty()) 0 else text.toString().toInt() + } + isClientControlByUserEnabled = dialogView.clientUserControl.isChecked + allowedClientList = (dialogView.allowedList.text ?: "").split(nonMacChars) + .filter { it.isNotEmpty() }.map { MacAddress.fromString(it) } + blockedClientList = (dialogView.blockedList.text ?: "").split(nonMacChars) + .filter { it.isNotEmpty() }.map { MacAddress.fromString(it) } } } @@ -150,7 +161,7 @@ class WifiApDialogFragment : AlertDialogFragment= 30) { dialogView.timeoutWrapper.helperText = getString(R.string.wifi_hotspot_timeout_default, TetherTimeoutMonitor.defaultTimeout) - if (!arg.readOnly) dialogView.timeout.addTextChangedListener(this@WifiApDialogFragment) + dialogView.timeout.addTextChangedListener(this@WifiApDialogFragment) } else dialogView.timeoutWrapper.isGone = true if (Build.VERSION.SDK_INT >= 23 || arg.p2pMode) dialogView.band.apply { bandOptions = mutableListOf().apply { @@ -175,6 +186,16 @@ class WifiApDialogFragment : AlertDialogFragment + if (text.isNullOrEmpty()) null else try { + text.toString().toInt() + null + } catch (e: NumberFormatException) { + e.readableMessage + } + } + dialogView.maxClientWrapper.error = maxClientError + val blockedListError = try { + (dialogView.blockedList.text ?: "").split(nonMacChars) + .filter { it.isNotEmpty() }.forEach { MacAddress.fromString(it) } + null + } catch (e: IllegalArgumentException) { + e.readableMessage + } + dialogView.blockedListWrapper.error = blockedListError + val allowedListError = try { + (dialogView.allowedList.text ?: "").split(nonMacChars) + .filter { it.isNotEmpty() }.forEach { MacAddress.fromString(it) } + null + } catch (e: IllegalArgumentException) { + e.readableMessage + } + dialogView.allowedListWrapper.error = allowedListError + val canCopy = timeoutError == null && bssidValid && maxClientError == null && blockedListError == null && + allowedListError == null (dialog as? AlertDialog)?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = - ssidLength in 1..32 && passwordValid && timeoutError == null && bssidValid - dialogView.toolbar.menu.findItem(android.R.id.copy).isEnabled = timeoutError == null && bssidValid + ssidLength in 1..32 && passwordValid && canCopy + dialogView.toolbar.menu.findItem(android.R.id.copy).isEnabled = canCopy } override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt index f8e99241..87c18477 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiApManager.kt @@ -97,6 +97,8 @@ object WifiApManager { @RequiresApi(28) val failureReasonLookup = ConstantLookup("SAP_START_FAILURE_", "SAP_START_FAILURE_GENERAL", "SAP_START_FAILURE_NO_CHANNEL") + @get:RequiresApi(30) + val clientBlockLookup by lazy { ConstantLookup("SAP_CLIENT_") } private val interfaceSoftApCallback by lazy { Class.forName("android.net.wifi.WifiManager\$SoftApCallback") } private val registerSoftApCallback by lazy { diff --git a/mobile/src/main/res/layout/dialog_wifi_ap.xml b/mobile/src/main/res/layout/dialog_wifi_ap.xml index 27ce539e..bd01d2c8 100644 --- a/mobile/src/main/res/layout/dialog_wifi_ap.xml +++ b/mobile/src/main/res/layout/dialog_wifi_ap.xml @@ -143,6 +143,7 @@ android:layout_marginTop="8dip" app:counterEnabled="true" app:counterMaxLength="17" + app:errorEnabled="true" android:hint="@string/wifi_advanced_mac_address_title"> + + + + + + + + + + diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index a8d1c2ff..426d2a1d 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -70,6 +70,8 @@ %1$d MHz, channel %2$d, width %3$s %1$s/%2$d clients connected\nSupported features: %3$s None + Blocked %1$s: %2$s + Copy MAC " (connecting)" " (reachable)" @@ -184,6 +186,10 @@ 6.0 GHz Band MAC address Hidden network + Maximum number of clients + Control which client can use hotspot + Blocked list of clients + Allowed list of clients Save