Correctly handle callSuper for Proxy
This commit is contained in:
@@ -18,6 +18,7 @@ import androidx.core.os.BuildCompat
|
|||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.R
|
import be.mygod.vpnhotspot.R
|
||||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||||
|
import be.mygod.vpnhotspot.util.callSuper
|
||||||
import be.mygod.vpnhotspot.util.ensureReceiverUnregistered
|
import be.mygod.vpnhotspot.util.ensureReceiverUnregistered
|
||||||
import com.android.dx.stock.ProxyBuilder
|
import com.android.dx.stock.ProxyBuilder
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@@ -259,25 +260,22 @@ object TetheringManager {
|
|||||||
build.invoke(builder)
|
build.invoke(builder)
|
||||||
}
|
}
|
||||||
val proxy = Proxy.newProxyInstance(interfaceStartTetheringCallback.classLoader,
|
val proxy = Proxy.newProxyInstance(interfaceStartTetheringCallback.classLoader,
|
||||||
arrayOf(interfaceStartTetheringCallback)) { proxy, method, args ->
|
arrayOf(interfaceStartTetheringCallback), object : InvocationHandler {
|
||||||
|
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
|
||||||
@Suppress("NAME_SHADOWING") val callback = reference.get()
|
@Suppress("NAME_SHADOWING") val callback = reference.get()
|
||||||
when (val name = method.name) {
|
return when (val name = method.name) {
|
||||||
"onTetheringStarted" -> {
|
"onTetheringStarted" -> {
|
||||||
if (!args.isNullOrEmpty()) Timber.w("Unexpected args for $name: $args")
|
if (!args.isNullOrEmpty()) Timber.w("Unexpected args for $name: $args")
|
||||||
callback?.onTetheringStarted()
|
callback?.onTetheringStarted()
|
||||||
null
|
|
||||||
}
|
}
|
||||||
"onTetheringFailed" -> {
|
"onTetheringFailed" -> {
|
||||||
if (args?.size != 1) Timber.w("Unexpected args for $name: $args")
|
if (args?.size != 1) Timber.w("Unexpected args for $name: $args")
|
||||||
callback?.onTetheringFailed(args?.getOrNull(0) as? Int?)
|
callback?.onTetheringFailed(args?.getOrNull(0) as? Int?)
|
||||||
null
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
Timber.w("Unexpected method, calling super: $method")
|
|
||||||
ProxyBuilder.callSuper(proxy, method, args)
|
|
||||||
}
|
}
|
||||||
|
else -> callSuper(interfaceStartTetheringCallback, proxy, method, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
startTethering.invoke(instance, request, handler.makeExecutor(), proxy)
|
startTethering.invoke(instance, request, handler.makeExecutor(), proxy)
|
||||||
return
|
return
|
||||||
} catch (e: InvocationTargetException) {
|
} catch (e: InvocationTargetException) {
|
||||||
@@ -297,10 +295,7 @@ object TetheringManager {
|
|||||||
callback?.onTetheringFailed()
|
callback?.onTetheringFailed()
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
else -> {
|
else -> ProxyBuilder.callSuper(proxy, method, args)
|
||||||
Timber.w("Unexpected method, calling super: $method")
|
|
||||||
ProxyBuilder.callSuper(proxy, method, args)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.build()
|
}.build()
|
||||||
@@ -460,7 +455,7 @@ object TetheringManager {
|
|||||||
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
|
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
|
||||||
@Suppress("NAME_SHADOWING") val callback = reference.get()
|
@Suppress("NAME_SHADOWING") val callback = reference.get()
|
||||||
val noArgs = args?.size ?: 0
|
val noArgs = args?.size ?: 0
|
||||||
when (val name = method.name) {
|
return when (val name = method.name) {
|
||||||
"onTetheringSupported" -> {
|
"onTetheringSupported" -> {
|
||||||
if (noArgs != 1) Timber.w("Unexpected args for $name: $args")
|
if (noArgs != 1) Timber.w("Unexpected args for $name: $args")
|
||||||
callback?.onTetheringSupported(args!![0] as Boolean)
|
callback?.onTetheringSupported(args!![0] as Boolean)
|
||||||
@@ -495,13 +490,9 @@ object TetheringManager {
|
|||||||
if (noArgs != 1) Timber.w("Unexpected args for $name: $args")
|
if (noArgs != 1) Timber.w("Unexpected args for $name: $args")
|
||||||
callback?.onOffloadStatusChanged(args!![0] as Int)
|
callback?.onOffloadStatusChanged(args!![0] as Int)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> callSuper(interfaceTetheringEventCallback, proxy, method, args)
|
||||||
Timber.w("Unexpected method, calling super: $method")
|
|
||||||
return ProxyBuilder.callSuper(proxy, method, args)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import android.net.wifi.WpsInfo
|
|||||||
import android.net.wifi.p2p.WifiP2pGroup
|
import android.net.wifi.p2p.WifiP2pGroup
|
||||||
import android.net.wifi.p2p.WifiP2pManager
|
import android.net.wifi.p2p.WifiP2pManager
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import com.android.dx.stock.ProxyBuilder
|
import be.mygod.vpnhotspot.util.callSuper
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.lang.reflect.InvocationHandler
|
||||||
|
import java.lang.reflect.Method
|
||||||
import java.lang.reflect.Proxy
|
import java.lang.reflect.Proxy
|
||||||
|
|
||||||
object WifiP2pManagerHelper {
|
object WifiP2pManagerHelper {
|
||||||
@@ -90,17 +92,15 @@ object WifiP2pManagerHelper {
|
|||||||
fun WifiP2pManager.requestPersistentGroupInfo(c: WifiP2pManager.Channel,
|
fun WifiP2pManager.requestPersistentGroupInfo(c: WifiP2pManager.Channel,
|
||||||
listener: (Collection<WifiP2pGroup>) -> Unit) {
|
listener: (Collection<WifiP2pGroup>) -> Unit) {
|
||||||
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
|
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
|
||||||
arrayOf(interfacePersistentGroupInfoListener)) { proxy, method, args ->
|
arrayOf(interfacePersistentGroupInfoListener), object : InvocationHandler {
|
||||||
if (method.name == "onPersistentGroupInfoAvailable") {
|
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? = when (method.name) {
|
||||||
|
"onPersistentGroupInfoAvailable" -> {
|
||||||
if (args?.size != 1) Timber.w(IllegalArgumentException("Unexpected args: $args"))
|
if (args?.size != 1) Timber.w(IllegalArgumentException("Unexpected args: $args"))
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST") listener(getGroupList.invoke(args!![0]) as Collection<WifiP2pGroup>)
|
||||||
listener(getGroupList.invoke(args[0]) as Collection<WifiP2pGroup>)
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
Timber.w(IllegalArgumentException("Unexpected method, calling super: $method"))
|
|
||||||
ProxyBuilder.callSuper(proxy, method, args)
|
|
||||||
}
|
}
|
||||||
|
else -> callSuper(interfacePersistentGroupInfoListener, proxy, method, args)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
requestPersistentGroupInfo.invoke(this, c, proxy)
|
requestPersistentGroupInfo.invoke(this, c, proxy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package be.mygod.vpnhotspot.util
|
package be.mygod.vpnhotspot.util
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.annotation.TargetApi
|
||||||
import android.content.*
|
import android.content.*
|
||||||
import android.net.InetAddresses
|
import android.net.InetAddresses
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@@ -13,6 +14,7 @@ import android.view.MenuItem
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.BindingAdapter
|
import androidx.databinding.BindingAdapter
|
||||||
@@ -21,6 +23,9 @@ import androidx.fragment.app.FragmentManager
|
|||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
|
import java.lang.invoke.MethodHandles
|
||||||
|
import java.lang.reflect.InvocationHandler
|
||||||
|
import java.lang.reflect.Method
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
@@ -129,3 +134,25 @@ var MenuItem.isNotGone: Boolean
|
|||||||
isVisible = value
|
isVisible = value
|
||||||
isEnabled = value
|
isEnabled = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@get:RequiresApi(26)
|
||||||
|
private val newLookup by lazy @TargetApi(26) {
|
||||||
|
MethodHandles.Lookup::class.java.getDeclaredConstructor(Class::class.java, Int::class.java).apply {
|
||||||
|
isAccessible = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call interface super method.
|
||||||
|
*
|
||||||
|
* See also: https://stackoverflow.com/a/49532463/2245107
|
||||||
|
*/
|
||||||
|
fun InvocationHandler.callSuper(interfaceClass: Class<*>, proxy: Any, method: Method, args: Array<out Any?>?) = when {
|
||||||
|
Build.VERSION.SDK_INT >= 26 -> newLookup.newInstance(interfaceClass, 0xf) // ALL_MODES
|
||||||
|
.`in`(interfaceClass).unreflectSpecial(method, interfaceClass).bindTo(proxy).run {
|
||||||
|
if (args == null) invokeWithArguments() else invokeWithArguments(*args)
|
||||||
|
}
|
||||||
|
// only Java 8+ has default interface methods; otherwise, we just redispatch it to InvocationHandler
|
||||||
|
args == null -> method(this)
|
||||||
|
else -> method(this, *args)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user