Refactor SoftApCapability

This commit is contained in:
Mygod
2021-05-26 21:23:18 -04:00
parent 50de5a269c
commit 168c9ff6f1
4 changed files with 55 additions and 39 deletions

View File

@@ -27,6 +27,7 @@ import be.mygod.vpnhotspot.R
import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.wifi.SoftApCapability
import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat
import be.mygod.vpnhotspot.net.wifi.SoftApInfo
import be.mygod.vpnhotspot.net.wifi.WifiApManager
@@ -41,6 +42,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import timber.log.Timber
import java.lang.reflect.InvocationTargetException
import java.util.*
sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
TetheringManager.StartTetheringCallback {
@@ -145,7 +147,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
private var failureReason: Int? = null
private var numClients: Int? = null
private var info = emptyList<Parcelable>()
private var capability: Pair<Int, Long>? = null
private var capability: Parcelable? = null
init {
if (Build.VERSION.SDK_INT >= 28) parent.viewLifecycleOwner.lifecycle.addObserver(this)
@@ -176,8 +178,8 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
this.info = info
data.notifyChange()
}
override fun onCapabilityChanged(maxSupportedClients: Int, supportedFeatures: Long) {
capability = maxSupportedClients to supportedFeatures
override fun onCapabilityChanged(capability: Parcelable) {
this.capability = capability
data.notifyChange()
}
override fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) {
@@ -193,6 +195,22 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
override val title get() = parent.getString(R.string.tethering_manage_wifi)
override val tetherType get() = TetherType.WIFI
override val type get() = VIEW_TYPE_WIFI
@TargetApi(30)
private fun formatCapability(locale: Locale) = capability?.let {
val capability = SoftApCapability(it)
val maxClients = capability.maxSupportedClients
val supportedFeatures = capability.supportedFeatures
app.resources.getQuantityText(R.plurals.tethering_manage_wifi_capabilities, maxClients).format(locale,
numClients ?: "?", maxClients, sequence {
var features = supportedFeatures
if (features != 0L) while (features != 0L) {
val bit = features.takeLowestOneBit()
yield(SoftApCapability.featureLookup(bit, true))
features = features and bit.inv()
} else yield(parent.getText(R.string.tethering_manage_wifi_no_features))
}.joinToSpanned())
}
override val text get() = parent.resources.configuration.locale.let { locale ->
listOfNotNull(failureReason?.let { WifiApManager.failureReasonLookup(it) }, baseError, info.run {
if (isEmpty()) null else joinToSpanned("\n") @TargetApi(30) { parcel ->
@@ -215,17 +233,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
} else parent.getText(R.string.tethering_manage_wifi_info).format(locale,
frequency, channel, bandwidth)
}
}, capability?.let { (maxSupportedClients, supportedFeatures) ->
app.resources.getQuantityText(R.plurals.tethering_manage_wifi_capabilities,
maxSupportedClients).format(locale, numClients ?: "?", maxSupportedClients, sequence {
var features = supportedFeatures
if (features != 0L) while (features != 0L) {
val bit = features.takeLowestOneBit()
yield(WifiApManager.featureLookup(bit, true))
features = features and bit.inv()
} else yield(parent.getText(R.string.tethering_manage_wifi_no_features))
}.joinToSpanned())
}).joinToSpanned("\n")
}, formatCapability(locale)).joinToSpanned("\n")
}
override fun start() = TetheringManager.startTethering(TetheringManager.TETHERING_WIFI, true, this)

View File

@@ -0,0 +1,27 @@
package be.mygod.vpnhotspot.net.wifi
import android.os.Parcelable
import androidx.annotation.RequiresApi
import be.mygod.vpnhotspot.util.LongConstantLookup
@JvmInline
@RequiresApi(30)
value class SoftApCapability(val inner: Parcelable) {
companion object {
private val clazz by lazy { Class.forName("android.net.wifi.SoftApCapability") }
private val getMaxSupportedClients by lazy { clazz.getDeclaredMethod("getMaxSupportedClients") }
private val areFeaturesSupported by lazy { clazz.getDeclaredMethod("areFeaturesSupported", Long::class.java) }
val featureLookup by lazy { LongConstantLookup(clazz, "SOFTAP_FEATURE_") }
}
val maxSupportedClients get() = getMaxSupportedClients.invoke(inner) as Int
val supportedFeatures: Long get() {
var supportedFeatures = 0L
var probe = 1L
while (probe != 0L) {
if (areFeaturesSupported(inner, probe) as Boolean) supportedFeatures = supportedFeatures or probe
probe += probe
}
return supportedFeatures
}
}

View File

@@ -14,7 +14,6 @@ import androidx.core.os.BuildCompat
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat.Companion.toCompat
import be.mygod.vpnhotspot.util.ConstantLookup
import be.mygod.vpnhotspot.util.LongConstantLookup
import be.mygod.vpnhotspot.util.Services
import be.mygod.vpnhotspot.util.callSuper
import timber.log.Timber
@@ -91,7 +90,7 @@ object WifiApManager {
fun onInfoChanged(info: List<Parcelable>) { }
@RequiresApi(30)
fun onCapabilityChanged(maxSupportedClients: Int, supportedFeatures: Long) { }
fun onCapabilityChanged(capability: Parcelable) { }
@RequiresApi(30)
fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) { }
@@ -117,14 +116,6 @@ object WifiApManager {
Class.forName("android.net.wifi.WifiClient").getDeclaredMethod("getMacAddress")
}
private val classSoftApCapability by lazy { Class.forName("android.net.wifi.SoftApCapability") }
private val getMaxSupportedClients by lazy { classSoftApCapability.getDeclaredMethod("getMaxSupportedClients") }
private val areFeaturesSupported by lazy {
classSoftApCapability.getDeclaredMethod("areFeaturesSupported", Long::class.java)
}
@get:RequiresApi(30)
val featureLookup by lazy { LongConstantLookup(classSoftApCapability, "SOFTAP_FEATURE_") }
@RequiresApi(28)
fun registerSoftApCallback(callback: SoftApCallbackCompat, executor: Executor): Any {
val proxy = Proxy.newProxyInstance(interfaceSoftApCallback.classLoader,
@@ -183,16 +174,7 @@ object WifiApManager {
"onCapabilityChanged" -> @TargetApi(30) {
if (Build.VERSION.SDK_INT < 30) Timber.w(Exception("Unexpected onCapabilityChanged"))
if (noArgs != 1) Timber.w("Unexpected args for $name: ${args?.contentToString()}")
val softApCapability = args!![0]
var supportedFeatures = 0L
var probe = 1L
while (probe != 0L) {
if (areFeaturesSupported(softApCapability, probe) as Boolean) {
supportedFeatures = supportedFeatures or probe
}
probe += probe
}
callback.onCapabilityChanged(getMaxSupportedClients(softApCapability) as Int, supportedFeatures)
callback.onCapabilityChanged(args!![0] as Parcelable)
}
"onBlockedClientConnecting" -> @TargetApi(30) {
if (Build.VERSION.SDK_INT < 30) Timber.w(Exception("Unexpected onBlockedClientConnecting"))

View File

@@ -43,10 +43,9 @@ object WifiApCommands {
}
@Parcelize
@RequiresApi(30)
data class OnCapabilityChanged(val maxSupportedClients: Int,
val supportedFeatures: Long) : SoftApCallbackParcel() {
data class OnCapabilityChanged(val capability: Parcelable) : SoftApCallbackParcel() {
override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) =
callback.onCapabilityChanged(maxSupportedClients, supportedFeatures)
callback.onCapabilityChanged(capability)
}
@Parcelize
@RequiresApi(30)
@@ -79,8 +78,8 @@ object WifiApCommands {
@RequiresApi(30)
override fun onInfoChanged(info: List<Parcelable>) = push(SoftApCallbackParcel.OnInfoChanged(info))
@RequiresApi(30)
override fun onCapabilityChanged(maxSupportedClients: Int, supportedFeatures: Long) =
push(SoftApCallbackParcel.OnCapabilityChanged(maxSupportedClients, supportedFeatures))
override fun onCapabilityChanged(capability: Parcelable) =
push(SoftApCallbackParcel.OnCapabilityChanged(capability))
@RequiresApi(30)
override fun onBlockedClientConnecting(client: MacAddress, blockedReason: Int) =
push(SoftApCallbackParcel.OnBlockedClientConnecting(client, blockedReason))