Add support for requestPersistentGroupInfo
This commit is contained in:
@@ -59,8 +59,8 @@ class RepeaterFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClickL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ssid @Bindable get() = binder?.service?.ssid ?: getText(R.string.repeater_inactive)
|
val ssid @Bindable get() = binder?.ssid ?: getText(R.string.repeater_inactive)
|
||||||
val password @Bindable get() = binder?.service?.password ?: ""
|
val password @Bindable get() = binder?.password ?: ""
|
||||||
val addresses @Bindable get(): String {
|
val addresses @Bindable get(): String {
|
||||||
return try {
|
return try {
|
||||||
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
|
NetworkInterface.getByName(p2pInterface ?: return "")?.formatAddresses() ?: ""
|
||||||
|
|||||||
@@ -18,80 +18,20 @@ import android.widget.Toast
|
|||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.net.Routing
|
import be.mygod.vpnhotspot.net.Routing
|
||||||
import be.mygod.vpnhotspot.net.VpnMonitor
|
import be.mygod.vpnhotspot.net.VpnMonitor
|
||||||
|
import be.mygod.vpnhotspot.net.WifiP2pManagerHelper
|
||||||
|
import be.mygod.vpnhotspot.net.WifiP2pManagerHelper.deletePersistentGroup
|
||||||
|
import be.mygod.vpnhotspot.net.WifiP2pManagerHelper.netId
|
||||||
|
import be.mygod.vpnhotspot.net.WifiP2pManagerHelper.requestPersistentGroupInfo
|
||||||
|
import be.mygod.vpnhotspot.net.WifiP2pManagerHelper.setWifiP2pChannels
|
||||||
|
import be.mygod.vpnhotspot.net.WifiP2pManagerHelper.startWps
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Callback,
|
class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Callback,
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_STATUS_CHANGED = "be.mygod.vpnhotspot.RepeaterService.STATUS_CHANGED"
|
const val ACTION_STATUS_CHANGED = "be.mygod.vpnhotspot.RepeaterService.STATUS_CHANGED"
|
||||||
const val KEY_NET_ID = "netId"
|
|
||||||
private const val TAG = "RepeaterService"
|
private const val TAG = "RepeaterService"
|
||||||
private const val TEMPORARY_NET_ID = -1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches the output of dumpsys wifip2p. This part is available since Android 4.2.
|
|
||||||
*
|
|
||||||
* Related sources:
|
|
||||||
* https://android.googlesource.com/platform/frameworks/base/+/f0afe4144d09aa9b980cffd444911ab118fa9cbe%5E%21/wifi/java/android/net/wifi/p2p/WifiP2pService.java
|
|
||||||
* https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/a8d5e40/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java#639
|
|
||||||
*
|
|
||||||
* https://android.googlesource.com/platform/frameworks/base.git/+/android-5.0.0_r1/core/java/android/net/NetworkInfo.java#433
|
|
||||||
* https://android.googlesource.com/platform/frameworks/base.git/+/220871a/core/java/android/net/NetworkInfo.java#415
|
|
||||||
*/
|
|
||||||
private val patternNetworkInfo = "^mNetworkInfo .* (isA|a)vailable: (true|false)".toPattern(Pattern.MULTILINE)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Available since Android 4.4.
|
|
||||||
*
|
|
||||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.4_r1/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#994
|
|
||||||
* Implementation: https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/d72d2f4/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java#1159
|
|
||||||
*/
|
|
||||||
private val setWifiP2pChannels by lazy {
|
|
||||||
WifiP2pManager::class.java.getDeclaredMethod("setWifiP2pChannels", WifiP2pManager.Channel::class.java,
|
|
||||||
Int::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
|
||||||
}
|
|
||||||
private fun WifiP2pManager.setWifiP2pChannels(c: WifiP2pManager.Channel, lc: Int, oc: Int,
|
|
||||||
listener: WifiP2pManager.ActionListener) {
|
|
||||||
setWifiP2pChannels.invoke(this, c, lc, oc, listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Available since Android 4.3.
|
|
||||||
*
|
|
||||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r0.9/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#958
|
|
||||||
*/
|
|
||||||
private val startWps by lazy {
|
|
||||||
WifiP2pManager::class.java.getDeclaredMethod("startWps",
|
|
||||||
WifiP2pManager.Channel::class.java, WpsInfo::class.java, WifiP2pManager.ActionListener::class.java)
|
|
||||||
}
|
|
||||||
private fun WifiP2pManager.startWps(c: WifiP2pManager.Channel, wps: WpsInfo,
|
|
||||||
listener: WifiP2pManager.ActionListener) {
|
|
||||||
startWps.invoke(this, c, wps, listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Available since Android 4.2.
|
|
||||||
*
|
|
||||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.2_r1/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#1353
|
|
||||||
*/
|
|
||||||
private val deletePersistentGroup by lazy {
|
|
||||||
WifiP2pManager::class.java.getDeclaredMethod("deletePersistentGroup",
|
|
||||||
WifiP2pManager.Channel::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
|
||||||
}
|
|
||||||
private fun WifiP2pManager.deletePersistentGroup(c: WifiP2pManager.Channel, netId: Int,
|
|
||||||
listener: WifiP2pManager.ActionListener) {
|
|
||||||
deletePersistentGroup.invoke(this, c, netId, listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Available since Android 4.2.
|
|
||||||
*
|
|
||||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.2_r1/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java#253
|
|
||||||
*/
|
|
||||||
private val getNetworkId by lazy { WifiP2pGroup::class.java.getDeclaredMethod("getNetworkId") }
|
|
||||||
private val WifiP2pGroup.netId get() = getNetworkId.invoke(this) as Int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Status {
|
enum class Status {
|
||||||
@@ -103,8 +43,11 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
var data: RepeaterFragment.Data? = null
|
var data: RepeaterFragment.Data? = null
|
||||||
val active get() = status == Status.ACTIVE
|
val active get() = status == Status.ACTIVE
|
||||||
|
|
||||||
|
val ssid get() = group?.networkName
|
||||||
|
val password get() = group?.passphrase
|
||||||
|
|
||||||
fun startWps(pin: String? = null) {
|
fun startWps(pin: String? = null) {
|
||||||
if (status != Status.ACTIVE) return
|
if (!active) return
|
||||||
val wps = WpsInfo()
|
val wps = WpsInfo()
|
||||||
if (pin == null) wps.setup = WpsInfo.PBC else {
|
if (pin == null) wps.setup = WpsInfo.PBC else {
|
||||||
wps.setup = WpsInfo.KEYPAD
|
wps.setup = WpsInfo.KEYPAD
|
||||||
@@ -120,13 +63,11 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shutdown() {
|
fun shutdown() {
|
||||||
if (status == Status.ACTIVE) removeGroup()
|
if (active) removeGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetCredentials() {
|
fun resetCredentials() {
|
||||||
val netId = app.pref.getInt(KEY_NET_ID, TEMPORARY_NET_ID)
|
p2pManager.deletePersistentGroup(channel, (group ?: return).netId, object : WifiP2pManager.ActionListener {
|
||||||
if (netId == TEMPORARY_NET_ID) return
|
|
||||||
p2pManager.deletePersistentGroup(channel, netId, object : WifiP2pManager.ActionListener {
|
|
||||||
override fun onSuccess() = Toast.makeText(this@RepeaterService,
|
override fun onSuccess() = Toast.makeText(this@RepeaterService,
|
||||||
R.string.repeater_reset_credentials_success, Toast.LENGTH_SHORT).show()
|
R.string.repeater_reset_credentials_success, Toast.LENGTH_SHORT).show()
|
||||||
override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService,
|
override fun onFailure(reason: Int) = Toast.makeText(this@RepeaterService,
|
||||||
@@ -140,7 +81,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
var group: WifiP2pGroup? = null
|
var group: WifiP2pGroup? = null
|
||||||
private set(value) {
|
private set(value) {
|
||||||
field = value
|
field = value
|
||||||
if (value != null) app.pref.edit().putInt(KEY_NET_ID, value.netId).apply()
|
binder.data?.onGroupChanged(group)
|
||||||
}
|
}
|
||||||
private val binder = RepeaterBinder()
|
private val binder = RepeaterBinder()
|
||||||
private var receiverRegistered = false
|
private var receiverRegistered = false
|
||||||
@@ -161,9 +102,6 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ssid get() = if (status == Status.ACTIVE) group?.networkName else null
|
|
||||||
val password get() = if (status == Status.ACTIVE) group?.passphrase else null
|
|
||||||
|
|
||||||
private var upstream: String? = null
|
private var upstream: String? = null
|
||||||
private var dns: List<InetAddress> = emptyList()
|
private var dns: List<InetAddress> = emptyList()
|
||||||
private var routing: Routing? = null
|
private var routing: Routing? = null
|
||||||
@@ -214,6 +152,18 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
override fun onChannelDisconnected() {
|
override fun onChannelDisconnected() {
|
||||||
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
||||||
setOperatingChannel(true)
|
setOperatingChannel(true)
|
||||||
|
try {
|
||||||
|
p2pManager.requestPersistentGroupInfo(channel, {
|
||||||
|
when (it.size) {
|
||||||
|
0 -> { }
|
||||||
|
1 -> group = it.single()
|
||||||
|
else -> Log.w(TAG, "Unexpected groups: $it")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||||
@@ -239,7 +189,8 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
* startService 2nd stop
|
* startService 2nd stop
|
||||||
*/
|
*/
|
||||||
private fun setup(ifname: String? = null, dns: List<InetAddress> = emptyList()) {
|
private fun setup(ifname: String? = null, dns: List<InetAddress> = emptyList()) {
|
||||||
val matcher = patternNetworkInfo.matcher(loggerSu("dumpsys ${Context.WIFI_P2P_SERVICE}") ?: "")
|
val matcher = WifiP2pManagerHelper.patternNetworkInfo.matcher(
|
||||||
|
loggerSu("dumpsys ${Context.WIFI_P2P_SERVICE}") ?: "")
|
||||||
when {
|
when {
|
||||||
!matcher.find() -> startFailure(getString(R.string.root_unavailable))
|
!matcher.find() -> startFailure(getString(R.string.root_unavailable))
|
||||||
matcher.group(2) == "true" -> {
|
matcher.group(2) == "true" -> {
|
||||||
@@ -323,7 +274,6 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
|||||||
return
|
return
|
||||||
} else showNotification(group)
|
} else showNotification(group)
|
||||||
this.group = group
|
this.group = group
|
||||||
binder.data?.onGroupChanged(group)
|
|
||||||
}
|
}
|
||||||
private fun initRouting(upstream: String?, downstream: String,
|
private fun initRouting(upstream: String?, downstream: String,
|
||||||
owner: InetAddress, dns: List<InetAddress>): Boolean {
|
owner: InetAddress, dns: List<InetAddress>): Boolean {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class RepeaterTileService : TileService(), ServiceConnection {
|
|||||||
RepeaterService.Status.ACTIVE -> {
|
RepeaterService.Status.ACTIVE -> {
|
||||||
qsTile.state = Tile.STATE_ACTIVE
|
qsTile.state = Tile.STATE_ACTIVE
|
||||||
qsTile.icon = tileOn
|
qsTile.icon = tileOn
|
||||||
qsTile.label = binder?.service?.ssid
|
qsTile.label = binder?.ssid
|
||||||
}
|
}
|
||||||
null -> {
|
null -> {
|
||||||
qsTile.state = Tile.STATE_UNAVAILABLE
|
qsTile.state = Tile.STATE_UNAVAILABLE
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package be.mygod.vpnhotspot.net
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.net.wifi.WpsInfo
|
||||||
|
import android.net.wifi.p2p.WifiP2pGroup
|
||||||
|
import android.net.wifi.p2p.WifiP2pManager
|
||||||
|
import android.util.Log
|
||||||
|
import com.android.dx.stock.ProxyBuilder
|
||||||
|
import java.lang.reflect.Proxy
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
|
object WifiP2pManagerHelper {
|
||||||
|
/** Interface for callback invocation when stored group info list is available {@hide} */
|
||||||
|
interface PersistentGroupInfoListener {
|
||||||
|
/**
|
||||||
|
* The requested stored p2p group info list is available
|
||||||
|
* @param groups Wi-Fi p2p group info list
|
||||||
|
*/
|
||||||
|
fun onPersistentGroupInfoAvailable(groups: Collection<WifiP2pGroup>)
|
||||||
|
}
|
||||||
|
|
||||||
|
const val TAG = "WifiP2pManagerHelper"
|
||||||
|
const val TEMPORARY_NET_ID = -1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the output of dumpsys wifip2p. This part is available since Android 4.2.
|
||||||
|
*
|
||||||
|
* Related sources:
|
||||||
|
* https://android.googlesource.com/platform/frameworks/base/+/f0afe4144d09aa9b980cffd444911ab118fa9cbe%5E%21/wifi/java/android/net/wifi/p2p/WifiP2pService.java
|
||||||
|
* https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/a8d5e40/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java#639
|
||||||
|
*
|
||||||
|
* https://android.googlesource.com/platform/frameworks/base.git/+/android-5.0.0_r1/core/java/android/net/NetworkInfo.java#433
|
||||||
|
* https://android.googlesource.com/platform/frameworks/base.git/+/220871a/core/java/android/net/NetworkInfo.java#415
|
||||||
|
*/
|
||||||
|
val patternNetworkInfo = "^mNetworkInfo .* (isA|a)vailable: (true|false)".toPattern(Pattern.MULTILINE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available since Android 4.4.
|
||||||
|
*
|
||||||
|
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.4_r1/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#994
|
||||||
|
* Implementation: https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/d72d2f4/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java#1159
|
||||||
|
*/
|
||||||
|
private val setWifiP2pChannels by lazy {
|
||||||
|
WifiP2pManager::class.java.getDeclaredMethod("setWifiP2pChannels", WifiP2pManager.Channel::class.java,
|
||||||
|
Int::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
||||||
|
}
|
||||||
|
fun WifiP2pManager.setWifiP2pChannels(c: WifiP2pManager.Channel, lc: Int, oc: Int,
|
||||||
|
listener: WifiP2pManager.ActionListener) {
|
||||||
|
setWifiP2pChannels.invoke(this, c, lc, oc, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available since Android 4.3.
|
||||||
|
*
|
||||||
|
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r0.9/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#958
|
||||||
|
*/
|
||||||
|
private val startWps by lazy {
|
||||||
|
WifiP2pManager::class.java.getDeclaredMethod("startWps",
|
||||||
|
WifiP2pManager.Channel::class.java, WpsInfo::class.java, WifiP2pManager.ActionListener::class.java)
|
||||||
|
}
|
||||||
|
fun WifiP2pManager.startWps(c: WifiP2pManager.Channel, wps: WpsInfo,
|
||||||
|
listener: WifiP2pManager.ActionListener) {
|
||||||
|
startWps.invoke(this, c, wps, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available since Android 4.2.
|
||||||
|
*
|
||||||
|
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.2_r1/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#1353
|
||||||
|
*/
|
||||||
|
private val deletePersistentGroup by lazy {
|
||||||
|
WifiP2pManager::class.java.getDeclaredMethod("deletePersistentGroup",
|
||||||
|
WifiP2pManager.Channel::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
||||||
|
}
|
||||||
|
fun WifiP2pManager.deletePersistentGroup(c: WifiP2pManager.Channel, netId: Int,
|
||||||
|
listener: WifiP2pManager.ActionListener) {
|
||||||
|
deletePersistentGroup.invoke(this, c, netId, listener)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val interfacePersistentGroupInfoListener by lazy @SuppressLint("PrivateApi") {
|
||||||
|
Class.forName("android.net.wifi.p2p.WifiP2pManager\$PersistentGroupInfoListener")
|
||||||
|
}
|
||||||
|
private val getGroupList by lazy @SuppressLint("PrivateApi") {
|
||||||
|
Class.forName("android.net.wifi.p2p.WifiP2pGroupList").getDeclaredMethod("getGroupList")
|
||||||
|
}
|
||||||
|
private val requestPersistentGroupInfo by lazy {
|
||||||
|
WifiP2pManager::class.java.getDeclaredMethod("requestPersistentGroupInfo",
|
||||||
|
WifiP2pManager.Channel::class.java, interfacePersistentGroupInfoListener)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Request a list of all the persistent p2p groups stored in system.
|
||||||
|
*
|
||||||
|
* @param c is the channel created at {@link #initialize}
|
||||||
|
* @param listener for callback when persistent group info list is available. Can be null.
|
||||||
|
*/
|
||||||
|
fun WifiP2pManager.requestPersistentGroupInfo(c: WifiP2pManager.Channel,
|
||||||
|
listener: (Collection<WifiP2pGroup>) -> Unit) {
|
||||||
|
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
|
||||||
|
arrayOf(interfacePersistentGroupInfoListener), { proxy, method, args ->
|
||||||
|
if (method.name == "onPersistentGroupInfoAvailable") {
|
||||||
|
if (args.size != 1) Log.w(TAG, "Unexpected args: $args")
|
||||||
|
listener(getGroupList.invoke(args[0]) as Collection<WifiP2pGroup>)
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Unexpected method, calling super: $method")
|
||||||
|
ProxyBuilder.callSuper(proxy, method, args)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
requestPersistentGroupInfo.invoke(this, c, proxy)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available since Android 4.2.
|
||||||
|
*
|
||||||
|
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.2_r1/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java#253
|
||||||
|
*/
|
||||||
|
private val getNetworkId by lazy { WifiP2pGroup::class.java.getDeclaredMethod("getNetworkId") }
|
||||||
|
val WifiP2pGroup.netId get() = getNetworkId.invoke(this) as Int
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user