From 7a40927bcc7c7e5f4178b33930876d8b9cb2e169 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 26 May 2021 19:11:20 -0400 Subject: [PATCH] Support new onInfoChanged method --- README.md | 1 + .../mygod/vpnhotspot/manage/TetherManager.kt | 22 ++++++++------ .../mygod/vpnhotspot/net/wifi/SoftApInfo.kt | 20 +++++++++++++ .../vpnhotspot/net/wifi/WifiApManager.kt | 29 +++++++++---------- .../mygod/vpnhotspot/root/WifiApCommands.kt | 8 ++--- 5 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt diff --git a/README.md b/README.md index cfea16ac..d51975fd 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded * (since API 30) `Landroid/net/wifi/WifiManager$SoftApCallback;->onCapabilityChanged(Landroid/net/wifi/SoftApCapability;)V,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/WifiManager$SoftApCallback;->onConnectedClientsChanged(Ljava/util/List;)V,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/WifiManager$SoftApCallback;->onInfoChanged(Landroid/net/wifi/SoftApInfo;)V,sdk,system-api,test-api` +* (since API 31) `Landroid/net/wifi/WifiManager$SoftApCallback;->onInfoChanged(Ljava/util/List;)V,sdk,system-api,test-api` * (since API 28) `Landroid/net/wifi/WifiManager$SoftApCallback;->onStateChanged(II)V,sdk,system-api,test-api` * (since API 30) `Landroid/net/wifi/WifiManager;->SAP_CLIENT_BLOCK_REASON_CODE_*:I,sdk,system-api,test-api` * (since API 28) `Landroid/net/wifi/WifiManager;->SAP_START_FAILURE_*:I,sdk,system-api,test-api` 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 151a0a85..b25cd043 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt @@ -8,6 +8,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.net.MacAddress import android.os.Build +import android.os.Parcelable import android.provider.Settings import android.view.View import android.widget.Toast @@ -25,6 +26,7 @@ import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding import be.mygod.vpnhotspot.net.TetherType import be.mygod.vpnhotspot.net.TetheringManager import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat +import be.mygod.vpnhotspot.net.wifi.SoftApInfo import be.mygod.vpnhotspot.net.wifi.WifiApManager import be.mygod.vpnhotspot.root.WifiApCommands import be.mygod.vpnhotspot.util.readableMessage @@ -137,8 +139,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(), WifiApManager.SoftApCallbackCompat { private var failureReason: Int? = null private var numClients: Int? = null - private var frequency = 0 - private var bandwidth = WifiApManager.CHANNEL_WIDTH_INVALID + private var info = emptyList() private var capability: Pair? = null init { @@ -166,9 +167,8 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(), this.numClients = numClients if (Build.VERSION.SDK_INT >= 30) data.notifyChange() // only emits when onCapabilityChanged can be called } - override fun onInfoChanged(frequency: Int, bandwidth: Int) { - this.frequency = frequency - this.bandwidth = bandwidth + override fun onInfoChanged(info: List) { + this.info = info data.notifyChange() } override fun onCapabilityChanged(maxSupportedClients: Int, supportedFeatures: Long) { @@ -189,11 +189,15 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(), override val tetherType get() = TetherType.WIFI override val type get() = VIEW_TYPE_WIFI override val text get() = listOfNotNull(failureReason?.let { WifiApManager.failureReasonLookup(it) }, baseError, - if (frequency != 0 || bandwidth != WifiApManager.CHANNEL_WIDTH_INVALID) { - parent.getString(R.string.tethering_manage_wifi_info, frequency, + info.run { + if (isEmpty()) null else joinToString("\n") @TargetApi(30) { + val info = SoftApInfo(it) + val frequency = info.frequency + parent.getString(R.string.tethering_manage_wifi_info, frequency, SoftApConfigurationCompat.frequencyToChannel(frequency), - WifiApManager.channelWidthLookup(bandwidth, true)) - } else null, + SoftApInfo.channelWidthLookup(info.bandwidth, true)) + } + }, capability?.let { (maxSupportedClients, supportedFeatures) -> app.resources.getQuantityString(R.plurals.tethering_manage_wifi_capabilities, maxSupportedClients, numClients ?: "?", maxSupportedClients, sequence { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt new file mode 100644 index 00000000..c5de91de --- /dev/null +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/SoftApInfo.kt @@ -0,0 +1,20 @@ +package be.mygod.vpnhotspot.net.wifi + +import android.os.Parcelable +import androidx.annotation.RequiresApi +import be.mygod.vpnhotspot.util.ConstantLookup + +@JvmInline +@RequiresApi(30) +value class SoftApInfo(val inner: Parcelable) { + companion object { + private val classSoftApInfo by lazy { Class.forName("android.net.wifi.SoftApInfo") } + private val getFrequency by lazy { classSoftApInfo.getDeclaredMethod("getFrequency") } + private val getBandwidth by lazy { classSoftApInfo.getDeclaredMethod("getBandwidth") } + + val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { classSoftApInfo } + } + + val frequency get() = getFrequency.invoke(inner) as Int + val bandwidth get() = getBandwidth.invoke(inner) as 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 67bf6a0b..565c2eb5 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 @@ -8,6 +8,7 @@ import android.net.wifi.SoftApConfiguration import android.net.wifi.WifiManager import android.os.Build import android.os.Handler +import android.os.Parcelable import androidx.annotation.RequiresApi import androidx.core.os.BuildCompat import be.mygod.vpnhotspot.App.Companion.app @@ -87,7 +88,7 @@ object WifiApManager { } @RequiresApi(30) - fun onInfoChanged(frequency: Int, bandwidth: Int) { } + fun onInfoChanged(info: List) { } @RequiresApi(30) fun onCapabilityChanged(maxSupportedClients: Int, supportedFeatures: Long) { } @@ -116,13 +117,6 @@ object WifiApManager { Class.forName("android.net.wifi.WifiClient").getDeclaredMethod("getMacAddress") } - private val classSoftApInfo by lazy { Class.forName("android.net.wifi.SoftApInfo") } - private val getFrequency by lazy { classSoftApInfo.getDeclaredMethod("getFrequency") } - private val getBandwidth by lazy { classSoftApInfo.getDeclaredMethod("getBandwidth") } - @RequiresApi(30) - val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { classSoftApInfo } - const val CHANNEL_WIDTH_INVALID = 0 - private val classSoftApCapability by lazy { Class.forName("android.net.wifi.SoftApCapability") } private val getMaxSupportedClients by lazy { classSoftApCapability.getDeclaredMethod("getMaxSupportedClients") } private val areFeaturesSupported by lazy { @@ -141,9 +135,6 @@ object WifiApManager { null // no return value as of API 30 } else invokeActual(proxy, method, args) - @RequiresApi(30) - private fun dispatchInfoChanged(softApInfo: Any?) = - callback.onInfoChanged(getFrequency(softApInfo) as Int, getBandwidth(softApInfo) as Int) private fun invokeActual(proxy: Any, method: Method, args: Array?): Any? { val noArgs = args?.size ?: 0 return when (val name = method.name) { @@ -172,14 +163,22 @@ object WifiApManager { }.map { getMacAddress(it) as MacAddress }) } "onInfoChanged" -> @TargetApi(30) { - if (Build.VERSION.SDK_INT < 30) Timber.w(Exception("Unexpected onInfoChanged")) if (noArgs != 1) Timber.w("Unexpected args for $name: ${args?.contentToString()}") val arg = args!![0] if (arg is List<*>) { if (!BuildCompat.isAtLeastS()) Timber.w(Exception("Unexpected onInfoChanged API 31+")) - if (arg.size != 1) Timber.w("Unexpected args for $name: ${args.contentToString()}") - else dispatchInfoChanged(arg[0]) - } else dispatchInfoChanged(arg) + @Suppress("UNCHECKED_CAST") + callback.onInfoChanged(arg as List) + } else { + when (Build.VERSION.SDK_INT) { + 30 -> { } + in 31..Int.MAX_VALUE -> return null // ignore old version calls + else -> Timber.w(Exception("Unexpected onInfoChanged API 30")) + } + 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)) + } } "onCapabilityChanged" -> @TargetApi(30) { if (Build.VERSION.SDK_INT < 30) Timber.w(Exception("Unexpected onCapabilityChanged")) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt b/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt index 29cb1e24..2883bf47 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/root/WifiApCommands.kt @@ -38,9 +38,8 @@ object WifiApCommands { } @Parcelize @RequiresApi(30) - data class OnInfoChanged(val frequency: Int, val bandwidth: Int) : SoftApCallbackParcel() { - override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) = - callback.onInfoChanged(frequency, bandwidth) + data class OnInfoChanged(val info: List) : SoftApCallbackParcel() { + override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) = callback.onInfoChanged(info) } @Parcelize @RequiresApi(30) @@ -78,8 +77,7 @@ object WifiApCommands { override fun onConnectedClientsChanged(clients: List) = push(SoftApCallbackParcel.OnConnectedClientsChanged(clients)) @RequiresApi(30) - override fun onInfoChanged(frequency: Int, bandwidth: Int) = - push(SoftApCallbackParcel.OnInfoChanged(frequency, bandwidth)) + override fun onInfoChanged(info: List) = push(SoftApCallbackParcel.OnInfoChanged(info)) @RequiresApi(30) override fun onCapabilityChanged(maxSupportedClients: Int, supportedFeatures: Long) = push(SoftApCallbackParcel.OnCapabilityChanged(maxSupportedClients, supportedFeatures))