Support reading AP clients from framework

This commit is contained in:
Mygod
2021-05-28 23:07:07 -04:00
parent 257e4497cc
commit 4a0e4537e5
4 changed files with 37 additions and 24 deletions

View File

@@ -5,6 +5,9 @@ import android.content.IntentFilter
import android.content.ServiceConnection import android.content.ServiceConnection
import android.net.wifi.p2p.WifiP2pDevice import android.net.wifi.p2p.WifiP2pDevice
import android.os.IBinder import android.os.IBinder
import android.os.Parcelable
import androidx.annotation.RequiresApi
import androidx.core.os.BuildCompat
import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
@@ -13,13 +16,19 @@ import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.RepeaterService import be.mygod.vpnhotspot.RepeaterService
import be.mygod.vpnhotspot.net.IpNeighbour import be.mygod.vpnhotspot.net.IpNeighbour
import be.mygod.vpnhotspot.net.MacAddressCompat import be.mygod.vpnhotspot.net.MacAddressCompat
import be.mygod.vpnhotspot.net.MacAddressCompat.Companion.toCompat
import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.net.TetheringManager import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.TetheringManager.localOnlyTetheredIfaces import be.mygod.vpnhotspot.net.TetheringManager.localOnlyTetheredIfaces
import be.mygod.vpnhotspot.net.TetheringManager.tetheredIfaces import be.mygod.vpnhotspot.net.TetheringManager.tetheredIfaces
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.wifi.WifiApManager
import be.mygod.vpnhotspot.net.wifi.WifiClient
import be.mygod.vpnhotspot.root.WifiApCommands
import be.mygod.vpnhotspot.util.broadcastReceiver import be.mygod.vpnhotspot.util.broadcastReceiver
class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callback, DefaultLifecycleObserver { class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callback, DefaultLifecycleObserver,
WifiApManager.SoftApCallbackCompat {
private var tetheredInterfaces = emptySet<String>() private var tetheredInterfaces = emptySet<String>()
private val receiver = broadcastReceiver { _, intent -> private val receiver = broadcastReceiver { _, intent ->
tetheredInterfaces = (intent.tetheredIfaces ?: return@broadcastReceiver).toSet() + tetheredInterfaces = (intent.tetheredIfaces ?: return@broadcastReceiver).toSet() +
@@ -29,6 +38,7 @@ class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callb
private var repeater: RepeaterService.Binder? = null private var repeater: RepeaterService.Binder? = null
private var p2p: Collection<WifiP2pDevice> = emptyList() private var p2p: Collection<WifiP2pDevice> = emptyList()
private var wifiAp = emptyList<Pair<String, MacAddressCompat>>()
private var neighbours: Collection<IpNeighbour> = emptyList() private var neighbours: Collection<IpNeighbour> = emptyList()
val clients = MutableLiveData<List<Client>>() val clients = MutableLiveData<List<Client>>()
val fullMode = object : DefaultLifecycleObserver { val fullMode = object : DefaultLifecycleObserver {
@@ -42,11 +52,18 @@ class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callb
private fun populateClients() { private fun populateClients() {
val clients = HashMap<Pair<String, MacAddressCompat>, Client>() val clients = HashMap<Pair<String, MacAddressCompat>, Client>()
val group = repeater?.group repeater?.group?.`interface`?.let { p2pInterface ->
val p2pInterface = group?.`interface` for (client in p2p) {
if (p2pInterface != null) { val addr = MacAddressCompat.fromString(client.deviceAddress!!)
for (client in p2p) clients[p2pInterface to MacAddressCompat.fromString(client.deviceAddress)] = clients[p2pInterface to addr] = object : Client(addr, p2pInterface) {
WifiP2pClient(p2pInterface, client) override val icon: Int get() = TetherType.WIFI_P2P.icon
}
}
}
for (client in wifiAp) {
clients[client] = object : Client(client.second, client.first) {
override val icon: Int get() = TetherType.WIFI.icon
}
} }
for (neighbour in neighbours) { for (neighbour in neighbours) {
val key = neighbour.dev to neighbour.lladdr val key = neighbour.dev to neighbour.lladdr
@@ -70,8 +87,10 @@ class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callb
override fun onStart(owner: LifecycleOwner) { override fun onStart(owner: LifecycleOwner) {
app.registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED)) app.registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
IpNeighbourMonitor.registerCallback(this, false) IpNeighbourMonitor.registerCallback(this, false)
if (BuildCompat.isAtLeastS()) WifiApCommands.registerSoftApCallback(this)
} }
override fun onStop(owner: LifecycleOwner) { override fun onStop(owner: LifecycleOwner) {
if (BuildCompat.isAtLeastS()) WifiApCommands.unregisterSoftApCallback(this)
IpNeighbourMonitor.unregisterCallback(this) IpNeighbourMonitor.unregisterCallback(this)
app.unregisterReceiver(receiver) app.unregisterReceiver(receiver)
} }
@@ -94,4 +113,12 @@ class ClientViewModel : ViewModel(), ServiceConnection, IpNeighbourMonitor.Callb
this.neighbours = neighbours this.neighbours = neighbours
populateClients() populateClients()
} }
@RequiresApi(31)
override fun onConnectedClientsChanged(clients: List<Parcelable>) {
wifiAp = clients.mapNotNull {
val client = WifiClient(it)
client.apInstanceIdentifier?.run { this to client.macAddress.toCompat() }
}
}
} }

View File

@@ -1,10 +0,0 @@
package be.mygod.vpnhotspot.client
import android.net.wifi.p2p.WifiP2pDevice
import be.mygod.vpnhotspot.net.MacAddressCompat
import be.mygod.vpnhotspot.net.TetherType
class WifiP2pClient(p2pInterface: String, p2p: WifiP2pDevice) :
Client(MacAddressCompat.fromString(p2p.deviceAddress!!), p2pInterface) {
override val icon: Int get() = TetherType.WIFI_P2P.icon
}

View File

@@ -88,10 +88,7 @@ object WifiApManager {
* @param clients the currently connected clients * @param clients the currently connected clients
*/ */
@RequiresApi(30) @RequiresApi(30)
fun onConnectedClientsChanged(clients: List<Parcelable>) { fun onConnectedClientsChanged(clients: List<Parcelable>) = onNumClientsChanged(clients.size)
@Suppress("DEPRECATION")
onNumClientsChanged(clients.size)
}
/** /**
* Called when information of softap changes. * Called when information of softap changes.

View File

@@ -25,7 +25,6 @@ object WifiApCommands {
} }
@Parcelize @Parcelize
data class OnNumClientsChanged(val numClients: Int) : SoftApCallbackParcel() { data class OnNumClientsChanged(val numClients: Int) : SoftApCallbackParcel() {
@Suppress("DEPRECATION")
override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) = override fun dispatch(callback: WifiApManager.SoftApCallbackCompat) =
callback.onNumClientsChanged(numClients) callback.onNumClientsChanged(numClients)
} }
@@ -121,7 +120,7 @@ object WifiApCommands {
is SoftApCallbackParcel.OnInfoChanged -> synchronized(callbacks) { lastCallback.info = parcel } is SoftApCallbackParcel.OnInfoChanged -> synchronized(callbacks) { lastCallback.info = parcel }
is SoftApCallbackParcel.OnCapabilityChanged -> synchronized(callbacks) { lastCallback.capability = parcel } is SoftApCallbackParcel.OnCapabilityChanged -> synchronized(callbacks) { lastCallback.capability = parcel }
} }
for (callback in synchronized(callbacks) { callbacks }) parcel.dispatch(callback) for (callback in synchronized(callbacks) { callbacks.toList() }) parcel.dispatch(callback)
} }
@RequiresApi(28) @RequiresApi(28)
fun registerSoftApCallback(callback: WifiApManager.SoftApCallbackCompat) = synchronized(callbacks) { fun registerSoftApCallback(callback: WifiApManager.SoftApCallbackCompat) = synchronized(callbacks) {
@@ -137,8 +136,8 @@ object WifiApCommands {
SmartSnackbar.make(e).show() SmartSnackbar.make(e).show()
} }
} }
lastCallback null
} else null } else lastCallback
}?.toSequence()?.forEach { it?.dispatch(callback) } }?.toSequence()?.forEach { it?.dispatch(callback) }
@RequiresApi(28) @RequiresApi(28)
fun unregisterSoftApCallback(callback: WifiApManager.SoftApCallbackCompat) = synchronized(callbacks) { fun unregisterSoftApCallback(callback: WifiApManager.SoftApCallbackCompat) = synchronized(callbacks) {