Support reading AP clients from framework
This commit is contained in:
@@ -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() }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user