From 8ff35f59ed332efe0f9e5bcc87833c2b171ac400 Mon Sep 17 00:00:00 2001 From: Mygod Date: Thu, 14 Jul 2022 22:23:34 -0400 Subject: [PATCH] Partial --- README.md | 15 +- .../vpnhotspot/manage/RepeaterManager.kt | 28 ++- .../net/monitor/TetherTimeoutMonitor.kt | 11 + .../net/wifi/SoftApConfigurationCompat.kt | 192 +++++++++++++----- .../net/wifi/WifiApDialogFragment.kt | 34 +++- .../vpnhotspot/net/wifi/WifiApManager.kt | 5 +- .../mygod/vpnhotspot/util/UnblockCentral.kt | 6 + mobile/src/main/res/layout/dialog_wifi_ap.xml | 33 ++- mobile/src/main/res/values/arrays.xml | 6 + mobile/src/main/res/values/strings.xml | 6 +- 10 files changed, 261 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 66ed38c6..d0b9ad51 100644 --- a/README.md +++ b/README.md @@ -152,7 +152,7 @@ _a.k.a. things that can go wrong if this app doesn't work._ This is a list of stuff that might impact this app's functionality if unavailable. This is only meant to be an index. You can read more in the source code. -API restrictions are updated up to [SHA-256 checksum `40674ff4291eb268f86561bf687e69dbd013df9ec9531a460404532a4ac9a761`](https://dl.google.com/developers/android/sc/non-sdk/hiddenapi-flags.csv). +API restrictions are updated up to [SHA-256 checksum `2886a24b6382be8751e86e3c355516c448987c3b0550eb8bb906a34490cfaa3c`](https://dl.google.com/developers/android/tm/non-sdk/hiddenapi-flags.csv). Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded or implicitly used) @@ -160,6 +160,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 30) `Landroid/net/ConnectivityModuleConnector;->IN_PROCESS_SUFFIX:Ljava/lang/String;` * (since API 30) `Landroid/net/TetheringManager$TetheringEventCallback;->onTetherableInterfaceRegexpsChanged(Landroid/net/TetheringManager$TetheringInterfaceRegexps;)V,blocked` * (since API 31) `Landroid/net/wifi/SoftApCapability;->getCountryCode()Ljava/lang/String;,blocked` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration$Builder;->setRandomizedMacAddress(Landroid/net/MacAddress;)Landroid/net/wifi/SoftApConfiguration$Builder;,blocked` * (since API 31) `Landroid/net/wifi/SoftApConfiguration$Builder;->setUserConfiguration(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,blocked` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->BAND_TYPES:[I,blocked` * (since API 31) `Landroid/net/wifi/SoftApInfo;->getApInstanceIdentifier()Ljava/lang/String;,blocked` @@ -249,11 +250,13 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->()V,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->(Landroid/net/wifi/SoftApConfiguration;)V,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->build()Landroid/net/wifi/SoftApConfiguration;,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration$Builder;->setAllowedAcsChannels(I[I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setAllowedClientList(Ljava/util/List;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setAutoShutdownEnabled(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (on API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBand(I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBlockedClientList(Ljava/util/List;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBridgedModeOpportunisticShutdownEnabled(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBridgedModeOpportunisticShutdownTimeoutMillis(J)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setBssid(Landroid/net/MacAddress;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (on API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setChannel(II)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration$Builder;->setChannels(Landroid/util/SparseIntArray;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` @@ -262,10 +265,12 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 31) `Landroid/net/wifi/SoftApConfiguration$Builder;->setIeee80211axEnabled(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 33) `Landroid/net/wifi/SoftApConfiguration$Builder;->setIeee80211beEnabled(Z)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration$Builder;->setMacRandomizationSetting(I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration$Builder;->setMaxChannelBandwidth(I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setMaxNumberOfClients(I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setPassphrase(Ljava/lang/String;I)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setShutdownTimeoutMillis(J)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration$Builder;->setSsid(Ljava/lang/String;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration$Builder;->setVendorElements(Ljava/util/List;)Landroid/net/wifi/SoftApConfiguration$Builder;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->BAND_2GHZ:I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->BAND_5GHZ:I,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->BAND_60GHZ:I,sdk,system-api,test-api` @@ -273,15 +278,21 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->BAND_*:I,sdk,system-api,test-api` * (since API 33) `Landroid/net/wifi/SoftApConfiguration;->DEFAULT_TIMEOUT:J,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->RANDOMIZATION_NONE:I,sdk,system-api,test-api` +* (since API 31) `Landroid/net/wifi/SoftApConfiguration;->RANDOMIZATION_NON_PERSISTENT:I,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->RANDOMIZATION_PERSISTENT:I,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration;->getAllowedAcsChannels(I)[I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getAllowedClientList()Ljava/util/List;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getBand()I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getBlockedClientList()Ljava/util/List;,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration;->getBridgedModeOpportunisticShutdownTimeoutMillis()J,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getChannel()I,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->getChannels()Landroid/util/SparseIntArray;,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->getMacRandomizationSetting()I,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration;->getMaxChannelBandwidth()I,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getMaxNumberOfClients()I,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration;->getPersistentRandomizedMacAddress()Landroid/net/MacAddress;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->getShutdownTimeoutMillis()J,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApConfiguration;->getVendorElements()Ljava/util/List;,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->isAutoShutdownEnabled()Z,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->isBridgedModeOpportunisticShutdownEnabled()Z,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApConfiguration;->isClientControlByUserEnabled()Z,sdk,system-api,test-api` @@ -289,6 +300,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 33) `Landroid/net/wifi/SoftApConfiguration;->isIeee80211beEnabled()Z,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApConfiguration;->isUserConfiguration()Z,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApInfo;->CHANNEL_WIDTH_*:I,sdk,system-api,test-api` +* (since API 33) `Landroid/net/wifi/SoftApInfo;->CHANNEL_WIDTH_AUTO:I,sdk,system-api,test-api` * (on API 30) `Landroid/net/wifi/SoftApInfo;->CHANNEL_WIDTH_INVALID:I,sdk,system-api,test-api` * (since API 31) `Landroid/net/wifi/SoftApInfo;->getAutoShutdownTimeoutMillis()J,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/SoftApInfo;->getBandwidth()I,sdk,system-api,test-api` @@ -339,6 +351,7 @@ Nonexported system resources: * (since API 30) `@com.android.networkstack.tethering:array/config_tether_wifi_regexs` * (since API 30) `@com.android.networkstack.tethering:array/config_tether_wigig_regexs` * (since API 30) `@com.android.wifi.resources:bool/config_wifi_p2p_mac_randomization_supported` +* (since API 31) `@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownIdleInstanceInBridgedModeTimeoutMillisecond` * (since API 30) `@com.android.wifi.resources:integer/config_wifiFrameworkSoftApShutDownTimeoutMilliseconds` Other: Activity `com.android.settings/.Settings$TetherSettingsActivity` is assumed to be exported. diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt index faa4f29e..0081be0a 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -191,25 +191,31 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic val passphrase = RepeaterService.passphrase if (networkName != null && passphrase != null) { return SoftApConfigurationCompat( - ssid = networkName, - passphrase = passphrase, - securityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, // is not actually used - isAutoShutdownEnabled = RepeaterService.isAutoShutdownEnabled, - shutdownTimeoutMillis = RepeaterService.shutdownTimeoutMillis).apply { + ssid = networkName, + passphrase = passphrase, + securityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, // is not actually used + isAutoShutdownEnabled = RepeaterService.isAutoShutdownEnabled, + shutdownTimeoutMillis = RepeaterService.shutdownTimeoutMillis, + macRandomizationSetting = if (WifiApManager.p2pMacRandomizationSupported) { + SoftApConfigurationCompat.RANDOMIZATION_NON_PERSISTENT + } else SoftApConfigurationCompat.RANDOMIZATION_NONE, + ).apply { bssid = RepeaterService.deviceAddress setChannel(RepeaterService.operatingChannel, RepeaterService.operatingBand) - setMacRandomizationEnabled(WifiApManager.p2pMacRandomizationSupported) } to false } } else binder?.let { binder -> val group = binder.group ?: binder.fetchPersistentGroup().let { binder.group } if (group != null) return SoftApConfigurationCompat( - ssid = group.networkName, - securityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, // is not actually used - isAutoShutdownEnabled = RepeaterService.isAutoShutdownEnabled, - shutdownTimeoutMillis = RepeaterService.shutdownTimeoutMillis).run { + ssid = group.networkName, + securityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK, // is not actually used + isAutoShutdownEnabled = RepeaterService.isAutoShutdownEnabled, + shutdownTimeoutMillis = RepeaterService.shutdownTimeoutMillis, + macRandomizationSetting = if (WifiApManager.p2pMacRandomizationSupported) { + SoftApConfigurationCompat.RANDOMIZATION_NON_PERSISTENT + } else SoftApConfigurationCompat.RANDOMIZATION_NONE, + ).run { setChannel(RepeaterService.operatingChannel) - setMacRandomizationEnabled(WifiApManager.p2pMacRandomizationSupported) try { val config = P2pSupplicantConfiguration(group) config.init(binder.obtainDeviceAddress()?.toString()) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/TetherTimeoutMonitor.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/TetherTimeoutMonitor.kt index 430c7bc3..35b413c9 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/TetherTimeoutMonitor.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/monitor/TetherTimeoutMonitor.kt @@ -58,6 +58,17 @@ class TetherTimeoutMonitor(private val timeout: Long = 0, MIN_SOFT_AP_TIMEOUT_DELAY_MS } else delay } + @get:RequiresApi(31) + val defaultTimeoutBridged: Int get() = try { + val info = WifiApManager.resolvedActivity.activityInfo + val resources = app.packageManager.getResourcesForApplication(info.applicationInfo) + resources.getInteger(resources.findIdentifier( + "config_wifiFrameworkSoftApShutDownIdleInstanceInBridgedModeTimeoutMillisecond", "integer", + WifiApManager.RESOURCES_PACKAGE, info.packageName)) + } catch (e: RuntimeException) { + Timber.w(e) + MIN_SOFT_AP_TIMEOUT_DELAY_MS + } } private var noClient = true 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 e264cd09..50bc267f 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 @@ -3,6 +3,7 @@ package be.mygod.vpnhotspot.net.wifi import android.annotation.SuppressLint import android.annotation.TargetApi import android.net.MacAddress +import android.net.wifi.ScanResult import android.net.wifi.SoftApConfiguration import android.os.Build import android.os.Parcelable @@ -16,45 +17,59 @@ import be.mygod.vpnhotspot.util.ConstantLookup import be.mygod.vpnhotspot.util.UnblockCentral import kotlinx.parcelize.Parcelize import timber.log.Timber +import java.lang.reflect.InvocationTargetException @Parcelize data class SoftApConfigurationCompat( - var ssid: String? = null, - @Deprecated("Workaround for using inline class with Parcelize, use bssid") - var bssidAddr: Long? = null, - var passphrase: String? = null, - var isHiddenSsid: Boolean = false, - /** - * You should probably set or modify this field directly only when you want to use bridged AP, - * see also [android.net.wifi.WifiManager.isBridgedApConcurrencySupported]. - * Otherwise, use [requireSingleBand] and [setChannel]. - */ - @TargetApi(23) - var channels: SparseIntArray = SparseIntArray(1).apply { append(BAND_2GHZ, 0) }, - var securityType: Int = SoftApConfiguration.SECURITY_TYPE_OPEN, - @TargetApi(30) - var maxNumberOfClients: Int = 0, - @TargetApi(28) - var isAutoShutdownEnabled: Boolean = true, - @TargetApi(28) - var shutdownTimeoutMillis: Long = 0, - @TargetApi(30) - var isClientControlByUserEnabled: Boolean = false, - @RequiresApi(30) - var blockedClientList: List = emptyList(), - @RequiresApi(30) - var allowedClientList: List = emptyList(), - @TargetApi(31) - var macRandomizationSetting: Int = RANDOMIZATION_PERSISTENT, - @TargetApi(31) - var isBridgedModeOpportunisticShutdownEnabled: Boolean = true, - @TargetApi(31) - var isIeee80211axEnabled: Boolean = true, - @TargetApi(33) - var isIeee80211beEnabled: Boolean = true, - @TargetApi(31) - var isUserConfiguration: Boolean = true, - var underlying: Parcelable? = null) : Parcelable { + var ssid: String? = null, + @Deprecated("Workaround for using inline class with Parcelize, use bssid") + var bssidAddr: Long? = null, + var passphrase: String? = null, + var isHiddenSsid: Boolean = false, + /** + * You should probably set or modify this field directly only when you want to use bridged AP, + * see also [android.net.wifi.WifiManager.isBridgedApConcurrencySupported]. + * Otherwise, use [requireSingleBand] and [setChannel]. + */ + @TargetApi(23) + var channels: SparseIntArray = SparseIntArray(1).apply { append(BAND_2GHZ, 0) }, + var securityType: Int = SoftApConfiguration.SECURITY_TYPE_OPEN, + @TargetApi(30) + var maxNumberOfClients: Int = 0, + @TargetApi(28) + var isAutoShutdownEnabled: Boolean = true, + @TargetApi(28) + var shutdownTimeoutMillis: Long = 0, + @TargetApi(30) + var isClientControlByUserEnabled: Boolean = false, + @RequiresApi(30) + var blockedClientList: List = emptyList(), + @RequiresApi(30) + var allowedClientList: List = emptyList(), + @TargetApi(31) + var macRandomizationSetting: Int = if (Build.VERSION.SDK_INT >= 33) { + RANDOMIZATION_NON_PERSISTENT + } else RANDOMIZATION_PERSISTENT, + @TargetApi(31) + var isBridgedModeOpportunisticShutdownEnabled: Boolean = true, + @TargetApi(31) + var isIeee80211axEnabled: Boolean = true, + @TargetApi(33) + var isIeee80211beEnabled: Boolean = true, + @TargetApi(31) + var isUserConfiguration: Boolean = true, + @TargetApi(33) + var bridgedModeOpportunisticShutdownTimeoutMillis: Long = -1L, + @TargetApi(33) + var vendorElements: List = emptyList(), + @TargetApi(33) + var persistentRandomizedMacAddress: MacAddress? = null, + @TargetApi(33) + var allowedAcsChannels: Map> = emptyMap(), + @TargetApi(33) + var maxChannelBandwidth: Int = CHANNEL_WIDTH_AUTO, + var underlying: Parcelable? = null, +) : Parcelable { companion object { const val BAND_2GHZ = 1 const val BAND_5GHZ = 2 @@ -82,6 +97,13 @@ data class SoftApConfigurationCompat( const val RANDOMIZATION_NONE = 0 @TargetApi(31) const val RANDOMIZATION_PERSISTENT = 1 + @TargetApi(33) + const val RANDOMIZATION_NON_PERSISTENT = 2 + + @TargetApi(33) + const val CHANNEL_WIDTH_AUTO = -1 + @TargetApi(30) + const val CHANNEL_WIDTH_INVALID = 0 fun isLegacyEitherBand(band: Int) = band and BAND_LEGACY == BAND_LEGACY @@ -165,6 +187,10 @@ data class SoftApConfigurationCompat( android.net.wifi.WifiConfiguration::class.java.getDeclaredField("apChannel") } + @get:RequiresApi(33) + private val getAllowedAcsChannels by lazy @TargetApi(33) { + SoftApConfiguration::class.java.getDeclaredMethod("getAllowedAcsChannels", Int::class.java) + } @get:RequiresApi(30) private val getAllowedClientList by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getAllowedClientList") @@ -175,6 +201,10 @@ data class SoftApConfigurationCompat( private val getBlockedClientList by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getBlockedClientList") } + @get:RequiresApi(33) + private val getBridgedModeOpportunisticShutdownTimeoutMillis by lazy @TargetApi(33) { + SoftApConfiguration::class.java.getDeclaredMethod("getBridgedModeOpportunisticShutdownTimeoutMillis") + } @get:RequiresApi(30) private val getChannel by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getChannel") @@ -187,14 +217,26 @@ data class SoftApConfigurationCompat( private val getMacRandomizationSetting by lazy @TargetApi(31) { SoftApConfiguration::class.java.getDeclaredMethod("getMacRandomizationSetting") } + @get:RequiresApi(33) + private val getMaxChannelBandwidth by lazy @TargetApi(33) { + SoftApConfiguration::class.java.getDeclaredMethod("getMaxChannelBandwidth") + } @get:RequiresApi(30) private val getMaxNumberOfClients by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getMaxNumberOfClients") } + @get:RequiresApi(33) + private val getPersistentRandomizedMacAddress by lazy @TargetApi(33) { + SoftApConfiguration::class.java.getDeclaredMethod("getPersistentRandomizedMacAddress") + } @get:RequiresApi(30) private val getShutdownTimeoutMillis by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("getShutdownTimeoutMillis") } + @get:RequiresApi(33) + private val getVendorElements by lazy @TargetApi(33) { + SoftApConfiguration::class.java.getDeclaredMethod("getVendorElements") + } @get:RequiresApi(30) private val isAutoShutdownEnabled by lazy @TargetApi(30) { SoftApConfiguration::class.java.getDeclaredMethod("isAutoShutdownEnabled") @@ -226,6 +268,10 @@ data class SoftApConfigurationCompat( private val newBuilder by lazy @TargetApi(30) { classBuilder.getConstructor(SoftApConfiguration::class.java) } @get:RequiresApi(30) private val build by lazy @TargetApi(30) { classBuilder.getDeclaredMethod("build") } + @get:RequiresApi(33) + private val setAllowedAcsChannels by lazy @TargetApi(33) { + classBuilder.getDeclaredMethod("setAllowedAcsChannels", Int::class.java, IntArray::class.java) + } @get:RequiresApi(30) private val setAllowedClientList by lazy @TargetApi(30) { classBuilder.getDeclaredMethod("setAllowedClientList", java.util.List::class.java) @@ -244,6 +290,10 @@ data class SoftApConfigurationCompat( private val setBridgedModeOpportunisticShutdownEnabled by lazy @TargetApi(31) { classBuilder.getDeclaredMethod("setBridgedModeOpportunisticShutdownEnabled", Boolean::class.java) } + @get:RequiresApi(33) + private val setBridgedModeOpportunisticShutdownTimeoutMillis by lazy @TargetApi(33) { + classBuilder.getDeclaredMethod("setBridgedModeOpportunisticShutdownTimeoutMillis", Long::class.java) + } @get:RequiresApi(30) private val setBssid by lazy @TargetApi(30) { classBuilder.getDeclaredMethod("setBssid", MacAddress::class.java) @@ -276,6 +326,10 @@ data class SoftApConfigurationCompat( private val setMacRandomizationSetting by lazy @TargetApi(31) { classBuilder.getDeclaredMethod("setMacRandomizationSetting", Int::class.java) } + @get:RequiresApi(33) + private val setMaxChannelBandwidth by lazy @TargetApi(33) { + classBuilder.getDeclaredMethod("setMaxChannelBandwidth", Int::class.java) + } @get:RequiresApi(30) private val setMaxNumberOfClients by lazy @TargetApi(31) { classBuilder.getDeclaredMethod("setMaxNumberOfClients", Int::class.java) @@ -284,6 +338,10 @@ data class SoftApConfigurationCompat( private val setPassphrase by lazy @TargetApi(30) { classBuilder.getDeclaredMethod("setPassphrase", String::class.java, Int::class.java) } + @get:RequiresApi(33) + private val setRandomizedMacAddress by lazy @TargetApi(33) { + UnblockCentral.setRandomizedMacAddress(classBuilder) + } @get:RequiresApi(30) private val setShutdownTimeoutMillis by lazy @TargetApi(30) { classBuilder.getDeclaredMethod("setShutdownTimeoutMillis", Long::class.java) @@ -292,6 +350,10 @@ data class SoftApConfigurationCompat( private val setSsid by lazy @TargetApi(30) { classBuilder.getDeclaredMethod("setSsid", String::class.java) } @get:RequiresApi(31) private val setUserConfiguration by lazy @TargetApi(31) { UnblockCentral.setUserConfiguration(classBuilder) } + @get:RequiresApi(33) + private val setVendorElements by lazy @TargetApi(33) { + classBuilder.getDeclaredMethod("setVendorElements", java.util.List::class.java) + } @Deprecated("Class deprecated in framework") @Suppress("DEPRECATION") @@ -350,13 +412,29 @@ data class SoftApConfigurationCompat( isClientControlByUserEnabled(this) as Boolean, getBlockedClientList(this) as List, getAllowedClientList(this) as List, - if (Build.VERSION.SDK_INT >= 31) getMacRandomizationSetting(this) as Int else RANDOMIZATION_PERSISTENT, - Build.VERSION.SDK_INT < 31 || isBridgedModeOpportunisticShutdownEnabled(this) as Boolean, - Build.VERSION.SDK_INT < 31 || isIeee80211axEnabled(this) as Boolean, - Build.VERSION.SDK_INT < 33 || isIeee80211beEnabled(this) as Boolean, - Build.VERSION.SDK_INT < 31 || isUserConfiguration(this) as Boolean, - this, - ) + underlying = this, + ).also { + if (Build.VERSION.SDK_INT < 31) return@also + it.macRandomizationSetting = getMacRandomizationSetting(this) as Int + it.isBridgedModeOpportunisticShutdownEnabled = isBridgedModeOpportunisticShutdownEnabled(this) as Boolean + it.isIeee80211axEnabled = isIeee80211axEnabled(this) as Boolean + it.isUserConfiguration = isUserConfiguration(this) as Boolean + if (Build.VERSION.SDK_INT < 33) return@also + it.isIeee80211beEnabled = isIeee80211beEnabled(this) as Boolean + it.bridgedModeOpportunisticShutdownTimeoutMillis = + getBridgedModeOpportunisticShutdownTimeoutMillis(this) as Long + it.vendorElements = getVendorElements(this) as List + it.persistentRandomizedMacAddress = getPersistentRandomizedMacAddress(this) as MacAddress + it.allowedAcsChannels = BAND_TYPES.map { bandType -> + try { + bandType to (getAllowedAcsChannels(this, bandType) as IntArray).toSet() + } catch (e: InvocationTargetException) { + if (e.targetException !is IllegalArgumentException) throw e + null + } + }.filterNotNull().toMap() + it.maxChannelBandwidth = getMaxChannelBandwidth(this) as Int + } /** * Only single band/channel can be supplied on API 23-30 @@ -378,7 +456,10 @@ data class SoftApConfigurationCompat( @RequiresApi(30) fun testPlatformValidity(bssid: MacAddress) = setBssid(staticBuilder, bssid) @RequiresApi(30) - fun testPlatformValidity(timeout: Long) = setShutdownTimeoutMillis(staticBuilder, timeout) + fun testPlatformTimeoutValidity(timeout: Long) = setShutdownTimeoutMillis(staticBuilder, timeout) + @RequiresApi(33) + fun testPlatformBridgedTimeoutValidity(timeout: Long) = + setBridgedModeOpportunisticShutdownTimeoutMillis(staticBuilder, timeout) } @Suppress("DEPRECATION") @@ -398,10 +479,6 @@ data class SoftApConfigurationCompat( } } - fun setMacRandomizationEnabled(enabled: Boolean) { - macRandomizationSetting = if (enabled) RANDOMIZATION_PERSISTENT else RANDOMIZATION_NONE - } - /** * Based on: * https://android.googlesource.com/platform/packages/apps/Settings/+/android-5.0.0_r1/src/com/android/settings/wifi/WifiApDialog.java#88 @@ -478,6 +555,25 @@ data class SoftApConfigurationCompat( } catch (e: ReflectiveOperationException) { Timber.w(e) // as far as we are concerned, this field is not used anywhere so ignore for now } + if (Build.VERSION.SDK_INT >= 33) { + setBridgedModeOpportunisticShutdownTimeoutMillis(builder, bridgedModeOpportunisticShutdownTimeoutMillis) + setVendorElements(builder, vendorElements) + if (sac?.let { getPersistentRandomizedMacAddress(it) as MacAddress } != + persistentRandomizedMacAddress) try { + setRandomizedMacAddress(builder, persistentRandomizedMacAddress) + } catch (e: ReflectiveOperationException) { + Timber.w(e) + } + for (bandType in BAND_TYPES) { + val value = allowedAcsChannels[bandType] ?: emptySet() + try { + setAllowedAcsChannels(builder, bandType, value.toIntArray()) + } catch (e: InvocationTargetException) { + if (value.isNotEmpty()) throw e + } + } + setMaxChannelBandwidth(builder, maxChannelBandwidth) + } } return build(builder) as SoftApConfiguration } 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 77a5c285..81736452 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 @@ -145,11 +145,14 @@ class WifiApDialogFragment : AlertDialogFragment + if (text.isNullOrEmpty()) -1L else text.toString().toLong() + } } } @@ -225,8 +228,15 @@ class WifiApDialogFragment : AlertDialogFragment if (text.isNullOrEmpty()) null else try { - SoftApConfigurationCompat.testPlatformValidity(text.toString().toLong()) + SoftApConfigurationCompat.testPlatformTimeoutValidity(text.toString().toLong()) null } catch (e: Exception) { e.readableMessage @@ -355,7 +367,17 @@ class WifiApDialogFragment : AlertDialogFragment + if (text.isNullOrEmpty()) null else try { + SoftApConfigurationCompat.testPlatformBridgedTimeoutValidity(text.toString().toLong()) + null + } catch (e: Exception) { + e.readableMessage + } + } + dialogView.bridgedTimeoutWrapper.error = bridgedTimeoutError + val canCopy = timeoutError == null && bssidValid && maxClientError == null && listsNoError && + bridgedTimeoutError == null (dialog as? AlertDialog)?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = ssidLengthOk && passwordValid && bandError == null && canCopy dialogView.toolbar.menu.findItem(android.R.id.copy).isEnabled = canCopy 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 df21ef02..771b5597 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 @@ -11,7 +11,6 @@ import android.os.Handler import android.os.Parcelable import androidx.annotation.RequiresApi import be.mygod.vpnhotspot.App.Companion.app -import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat.Companion.toCompat import be.mygod.vpnhotspot.util.* import timber.log.Timber import java.lang.reflect.InvocationHandler @@ -289,8 +288,8 @@ object WifiApManager { if (Build.VERSION.SDK_INT >= 31) return null // ignore old version calls val arg = args!![0] val info = SoftApInfo(arg as Parcelable) - callback.onInfoChanged( // check for legacy empty info with CHANNEL_WIDTH_INVALID - if (info.frequency == 0 && info.bandwidth == 0) emptyList() else listOf(arg)) + callback.onInfoChanged(if (info.frequency == 0 && info.bandwidth == + SoftApConfigurationCompat.CHANNEL_WIDTH_INVALID) emptyList() else listOf(arg)) } Build.VERSION.SDK_INT >= 30 && method.matches("onCapabilityChanged", SoftApCapability.clazz) -> { callback.onCapabilityChanged(args!![0] as Parcelable) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt b/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt index 24abdfc6..ae384c83 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/util/UnblockCentral.kt @@ -1,6 +1,7 @@ package be.mygod.vpnhotspot.util import android.annotation.SuppressLint +import android.net.MacAddress import android.net.wifi.SoftApConfiguration import android.net.wifi.p2p.WifiP2pConfig import androidx.annotation.RequiresApi @@ -24,6 +25,11 @@ object UnblockCentral { @RequiresApi(33) fun getCountryCode(clazz: Class<*>) = init.let { clazz.getDeclaredMethod("getCountryCode") } + @RequiresApi(33) + fun setRandomizedMacAddress(clazz: Class<*>) = init.let { + clazz.getDeclaredMethod("setRandomizedMacAddress", MacAddress::class.java) + } + @RequiresApi(31) fun setUserConfiguration(clazz: Class<*>) = init.let { clazz.getDeclaredMethod("setUserConfiguration", Boolean::class.java) diff --git a/mobile/src/main/res/layout/dialog_wifi_ap.xml b/mobile/src/main/res/layout/dialog_wifi_ap.xml index 920823e6..f5c25f06 100644 --- a/mobile/src/main/res/layout/dialog_wifi_ap.xml +++ b/mobile/src/main/res/layout/dialog_wifi_ap.xml @@ -261,14 +261,19 @@ android:inputType="textNoSuggestions" android:maxLength="17" /> - + + + + + + @string/wifi_mac_randomization_none + @string/wifi_mac_randomization_persistent + @string/wifi_mac_randomization_non_persistent + + @string/settings_service_masquerade_none @string/settings_service_masquerade_simple diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index b69782e4..95056233 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -216,7 +216,11 @@ Blocked list of clients Allowed list of clients Use randomized MAC - Enable Bridged mode opportunistic shutdown + None + Persistent + Non-persistent + Enable opportunistic shutdown of an instance in bridged AP + Inactive timeout for a bridged instance Enable Wi\u2011Fi 6 Enable Wi\u2011Fi 7 User Supplied Configuration