Support new fields in SoftApInfo
This commit is contained in:
@@ -154,6 +154,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 30) `Landroid/net/TetheringManager;->TETHERING_WIGIG:I,blocked`
|
||||
* (since API 31) `Landroid/net/wifi/SoftApInfo;->getApInstanceIdentifier()Ljava/lang/String;,blocked`
|
||||
* (prior to API 30) `Landroid/net/wifi/WifiConfiguration$KeyMgmt;->FT_PSK:I,lo-prio,max-target-o`
|
||||
* (prior to API 30) `Landroid/net/wifi/WifiConfiguration$KeyMgmt;->WPA_PSK_SHA256:I,blocked`
|
||||
* (since API 23, prior to API 30) `Landroid/net/wifi/WifiConfiguration;->AP_BAND_2GHZ:I,lo-prio,max-target-o`
|
||||
@@ -176,6 +177,7 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded
|
||||
* (since API 30) `Lcom/android/server/wifi/WifiContext;->ACTION_RESOURCES_APK:Ljava/lang/String;`
|
||||
* (since API 29) `Lcom/android/server/wifi/p2p/WifiP2pServiceImpl;->ANONYMIZED_DEVICE_ADDRESS:Ljava/lang/String;`
|
||||
* (since API 30) `Lcom/android/server/SystemServer;->TETHERING_CONNECTOR_CLASS:Ljava/lang/String;`
|
||||
* (since API 31) `Ldalvik/system/VMDebug;->allowHiddenApiReflectionFrom(Ljava/lang/Class;)V,unsupported`
|
||||
* (since API 26) `Ljava/lang/invoke/MethodHandles$Lookup;-><init>(Ljava/lang/Class;I)V,unsupported`
|
||||
* (since API 26) `Ljava/lang/invoke/MethodHandles$Lookup;->ALL_MODES:I,lo-prio,max-target-o`
|
||||
* (prior to API 29) `Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;,core-platform-api,max-target-p`
|
||||
@@ -256,8 +258,11 @@ Greylisted/blacklisted APIs or internal constants: (some constants are hardcoded
|
||||
* (since API 30) `Landroid/net/wifi/SoftApConfiguration;->isClientControlByUserEnabled()Z,sdk,system-api,test-api`
|
||||
* (since API 30) `Landroid/net/wifi/SoftApInfo;->CHANNEL_WIDTH_*:I,sdk,system-api,test-api`
|
||||
* (since 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 31) `Landroid/net/wifi/SoftApInfo;->getBssid()Landroid/net/MacAddress;,sdk,system-api,test-api`
|
||||
* (since API 30) `Landroid/net/wifi/SoftApInfo;->getBandwidth()I,system-api,whitelist`
|
||||
* (since API 30) `Landroid/net/wifi/SoftApInfo;->getFrequency()I,system-api,whitelist`
|
||||
* (since API 31) `Landroid/net/wifi/SoftApInfo;->getWifiStandard()I,sdk,system-api,test-api`
|
||||
* (since API 30) `Landroid/net/wifi/WifiClient;->getMacAddress()Landroid/net/MacAddress;,sdk,system-api,test-api`
|
||||
* (prior to API 30) `Landroid/net/wifi/WifiConfiguration$KeyMgmt;->WPA2_PSK:I,sdk,system-api,test-api`
|
||||
* (since API 30) `Landroid/net/wifi/WifiManager$SoftApCallback;->onBlockedClientConnecting(Landroid/net/wifi/WifiClient;I)V,sdk,system-api,test-api`
|
||||
|
||||
@@ -10,6 +10,8 @@ import android.net.MacAddress
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import android.provider.Settings
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.format.DateUtils
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
@@ -29,6 +31,9 @@ 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.format
|
||||
import be.mygod.vpnhotspot.util.joinToSpanned
|
||||
import be.mygod.vpnhotspot.util.makeMacSpan
|
||||
import be.mygod.vpnhotspot.util.readableMessage
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -188,28 +193,40 @@ 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
|
||||
override val text get() = listOfNotNull(failureReason?.let { WifiApManager.failureReasonLookup(it) }, baseError,
|
||||
info.run {
|
||||
if (isEmpty()) null else joinToString("\n") @TargetApi(30) {
|
||||
val info = SoftApInfo(it)
|
||||
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 ->
|
||||
val info = SoftApInfo(parcel)
|
||||
val frequency = info.frequency
|
||||
parent.getString(R.string.tethering_manage_wifi_info, frequency,
|
||||
SoftApConfigurationCompat.frequencyToChannel(frequency),
|
||||
SoftApInfo.channelWidthLookup(info.bandwidth, true))
|
||||
val channel = SoftApConfigurationCompat.frequencyToChannel(frequency)
|
||||
val bandwidth = SoftApInfo.channelWidthLookup(info.bandwidth, true)
|
||||
if (BuildCompat.isAtLeastS()) {
|
||||
var bssid = makeMacSpan(info.bssid.toString())
|
||||
info.apInstanceIdentifier?.let { // take the fast route if possible
|
||||
bssid = if (bssid is String) "$bssid%$it" else SpannableStringBuilder(bssid).append("%$it")
|
||||
}
|
||||
},
|
||||
capability?.let { (maxSupportedClients, supportedFeatures) ->
|
||||
app.resources.getQuantityString(R.plurals.tethering_manage_wifi_capabilities, maxSupportedClients,
|
||||
numClients ?: "?", maxSupportedClients, sequence {
|
||||
val timeout = info.autoShutdownTimeoutMillis
|
||||
parent.getText(if (timeout == 0L) {
|
||||
R.string.tethering_manage_wifi_info_timeout_disabled
|
||||
} else R.string.tethering_manage_wifi_info_timeout_enabled).format(locale,
|
||||
frequency, channel, bandwidth, bssid, info.wifiStandard,
|
||||
// http://unicode.org/cldr/trac/ticket/3407
|
||||
DateUtils.formatElapsedTime(timeout / 1000))
|
||||
} 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) yield(parent.getString(R.string.tethering_manage_wifi_no_features))
|
||||
else while (features != 0L) {
|
||||
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")
|
||||
}
|
||||
}.joinToString())
|
||||
}).joinToString("\n")
|
||||
|
||||
override fun start() = TetheringManager.startTethering(TetheringManager.TETHERING_WIFI, true, this)
|
||||
override fun stop() = TetheringManager.stopTethering(TetheringManager.TETHERING_WIFI, this::onException)
|
||||
|
||||
@@ -1,20 +1,47 @@
|
||||
package be.mygod.vpnhotspot.net.wifi
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.net.MacAddress
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.RequiresApi
|
||||
import be.mygod.vpnhotspot.util.ConstantLookup
|
||||
import be.mygod.vpnhotspot.util.UnblockCentral
|
||||
import timber.log.Timber
|
||||
|
||||
@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") }
|
||||
private val clazz by lazy { Class.forName("android.net.wifi.SoftApInfo") }
|
||||
private val getFrequency by lazy { clazz.getDeclaredMethod("getFrequency") }
|
||||
private val getBandwidth by lazy { clazz.getDeclaredMethod("getBandwidth") }
|
||||
@get:RequiresApi(31)
|
||||
private val getBssid by lazy { clazz.getDeclaredMethod("getBssid") }
|
||||
@get:RequiresApi(31)
|
||||
private val getWifiStandard by lazy { clazz.getDeclaredMethod("getWifiStandard") }
|
||||
@get:RequiresApi(31)
|
||||
private val getApInstanceIdentifier by lazy @TargetApi(31) {
|
||||
UnblockCentral.SoftApInfo_getApInstanceIdentifier(clazz)
|
||||
}
|
||||
@get:RequiresApi(31)
|
||||
private val getAutoShutdownTimeoutMillis by lazy { clazz.getDeclaredMethod("getAutoShutdownTimeoutMillis") }
|
||||
|
||||
val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { classSoftApInfo }
|
||||
val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { clazz }
|
||||
}
|
||||
|
||||
val frequency get() = getFrequency.invoke(inner) as Int
|
||||
val bandwidth get() = getBandwidth.invoke(inner) as Int
|
||||
@get:RequiresApi(31)
|
||||
val bssid get() = getBssid.invoke(inner) as MacAddress
|
||||
@get:RequiresApi(31)
|
||||
val wifiStandard get() = getWifiStandard.invoke(inner) as Int
|
||||
@get:RequiresApi(31)
|
||||
val apInstanceIdentifier get() = try {
|
||||
getApInstanceIdentifier.invoke(inner) as? String
|
||||
} catch (e: ReflectiveOperationException) {
|
||||
Timber.w(e)
|
||||
null
|
||||
}
|
||||
@get:RequiresApi(31)
|
||||
val autoShutdownTimeoutMillis get() = getAutoShutdownTimeoutMillis.invoke(inner) as Long
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package be.mygod.vpnhotspot.util
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.annotation.RequiresApi
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* The central object for accessing all the useful blocked APIs. Thanks Google!
|
||||
*/
|
||||
@SuppressLint("DiscouragedPrivateApi")
|
||||
@Suppress("FunctionName")
|
||||
object UnblockCentral {
|
||||
/**
|
||||
* Retrieve this property before doing dangerous shit.
|
||||
*/
|
||||
@get:RequiresApi(28)
|
||||
private val init by lazy {
|
||||
try {
|
||||
Class.forName("dalvik.system.VMDebug").getDeclaredMethod("allowHiddenApiReflectionFrom", Class::class.java)
|
||||
.invoke(null, UnblockCentral::class.java)
|
||||
true
|
||||
} catch (e: ReflectiveOperationException) {
|
||||
Timber.w(e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(31)
|
||||
fun SoftApInfo_getApInstanceIdentifier(clazz: Class<*>) = init.let {
|
||||
clazz.getDeclaredMethod("getApInstanceIdentifier")
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,15 @@ fun CharSequence.format(locale: Locale, vararg args: Any) = SpannableStringBuild
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> Iterable<T>.joinToSpanned(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "",
|
||||
limit: Int = -1, truncated: CharSequence = "...",
|
||||
transform: ((T) -> CharSequence)? = null) =
|
||||
joinTo(SpannableStringBuilder(), separator, prefix, postfix, limit, truncated, transform)
|
||||
fun <T> Sequence<T>.joinToSpanned(separator: CharSequence = ", ", prefix: CharSequence = "", postfix: CharSequence = "",
|
||||
limit: Int = -1, truncated: CharSequence = "...",
|
||||
transform: ((T) -> CharSequence)? = null) =
|
||||
joinTo(SpannableStringBuilder(), separator, prefix, postfix, limit, truncated, transform)
|
||||
|
||||
fun makeIpSpan(ip: InetAddress) = ip.hostAddress.let {
|
||||
// exclude all bogon IP addresses supported by Android APIs
|
||||
if (!app.hasTouch || ip.isMulticastAddress || ip.isAnyLocalAddress || ip.isLoopbackAddress ||
|
||||
|
||||
@@ -59,6 +59,10 @@
|
||||
<string name="tethering_manage_ncm">USB 网络共享 (NCM)</string>
|
||||
<string name="tethering_manage_wigig">WiGig 热点</string>
|
||||
<string name="tethering_manage_wifi_info">%1$d MHz, 频道 %2$d, 频宽 %3$s</string>
|
||||
<string name="tethering_manage_wifi_info_timeout_enabled">%4$s: Wi\u2011Fi %5$d, %1$d MHz, 频道 %2$d, 频宽 %3$s,
|
||||
关闭延迟 %6$s</string>
|
||||
<string name="tethering_manage_wifi_info_timeout_disabled">%4$s: Wi\u2011Fi %5$d, %1$d MHz, 频道 %2$d, 频宽 %3$s,
|
||||
不自动关闭</string>
|
||||
<plurals name="tethering_manage_wifi_capabilities">
|
||||
<item quantity="other">已连接 %1$s/%2$d 个设备\n支持功能:%3$s</item>
|
||||
</plurals>
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
<string name="tethering_manage_ncm">USB tethering (NCM)</string>
|
||||
<string name="tethering_manage_wigig">WiGig hotspot</string>
|
||||
<string name="tethering_manage_wifi_info">%1$d MHz, channel %2$d, width %3$s</string>
|
||||
<string name="tethering_manage_wifi_info_timeout_enabled">%4$s: Wi\u2011Fi %5$d, %1$d MHz, channel %2$d,
|
||||
width %3$s, idle timeout in %6$s</string>
|
||||
<string name="tethering_manage_wifi_info_timeout_disabled">%4$s: Wi\u2011Fi %5$d, %1$d MHz, channel %2$d,
|
||||
width %3$s, idle timeout disabled</string>
|
||||
<plurals name="tethering_manage_wifi_capabilities">
|
||||
<item quantity="one">%1$s/%2$d client connected\nSupported features: %3$s</item>
|
||||
<item quantity="other">%1$s/%2$d clients connected\nSupported features: %3$s</item>
|
||||
|
||||
Reference in New Issue
Block a user