Refactor SoftApCapability
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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"))
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user