Fix connected devices
This commit is contained in:
20
mobile/src/main/java/be/mygod/vpnhotspot/ArpCache.kt
Normal file
20
mobile/src/main/java/be/mygod/vpnhotspot/ArpCache.kt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package be.mygod.vpnhotspot
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class ArpCache(downstream: String) : HashMap<String, String>() {
|
||||||
|
companion object {
|
||||||
|
private val spaces = " +".toPattern()
|
||||||
|
private val mac = "^([0-9a-f]{2}:){5}[0-9a-f]{2}$".toPattern()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
File("/proc/net/arp").bufferedReader().useLines {
|
||||||
|
for (line in it) {
|
||||||
|
val parts = line.split(spaces)
|
||||||
|
// IP address HW type Flags HW address Mask Device
|
||||||
|
if (parts.size >= 6 && parts[5] == downstream && mac.matcher(parts[3]).matches()) put(parts[3], parts[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ import android.support.v4.app.NotificationCompat
|
|||||||
import android.support.v4.content.ContextCompat
|
import android.support.v4.content.ContextCompat
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import java.net.InetAddress
|
||||||
|
|
||||||
class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -46,7 +47,9 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
private lateinit var p2pManager: WifiP2pManager
|
private lateinit var p2pManager: WifiP2pManager
|
||||||
private lateinit var channel: WifiP2pManager.Channel
|
private lateinit var channel: WifiP2pManager.Channel
|
||||||
lateinit var group: WifiP2pGroup
|
lateinit var group: WifiP2pGroup
|
||||||
lateinit var clients: MutableCollection<WifiP2pDevice>
|
private set
|
||||||
|
var hostAddress: InetAddress? = null
|
||||||
|
private set
|
||||||
private val binder = HotspotBinder()
|
private val binder = HotspotBinder()
|
||||||
private var receiverRegistered = false
|
private var receiverRegistered = false
|
||||||
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
|
private val receiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
@@ -55,14 +58,11 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION ->
|
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION ->
|
||||||
if (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0) ==
|
if (intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, 0) ==
|
||||||
WifiP2pManager.WIFI_P2P_STATE_DISABLED) clean() // group may be enabled by other apps
|
WifiP2pManager.WIFI_P2P_STATE_DISABLED) clean() // group may be enabled by other apps
|
||||||
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION ->{
|
|
||||||
clients = intent.getParcelableExtra<WifiP2pDeviceList>(WifiP2pManager.EXTRA_P2P_DEVICE_LIST).deviceList
|
|
||||||
binder.data?.onClientsChanged()
|
|
||||||
}
|
|
||||||
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
|
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {
|
||||||
val info = intent.getParcelableExtra<WifiP2pInfo>(WifiP2pManager.EXTRA_WIFI_P2P_INFO)
|
val info = intent.getParcelableExtra<WifiP2pInfo>(WifiP2pManager.EXTRA_WIFI_P2P_INFO)
|
||||||
val net = intent.getParcelableExtra<NetworkInfo>(WifiP2pManager.EXTRA_NETWORK_INFO)
|
val net = intent.getParcelableExtra<NetworkInfo>(WifiP2pManager.EXTRA_NETWORK_INFO)
|
||||||
val group = intent.getParcelableExtra<WifiP2pGroup>(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)
|
val group = intent.getParcelableExtra<WifiP2pGroup>(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)
|
||||||
|
hostAddress = info.groupOwnerAddress
|
||||||
val downstream = group.`interface`
|
val downstream = group.`interface`
|
||||||
if (net.isConnected && downstream != null && this@HotspotService.downstream == null) {
|
if (net.isConnected && downstream != null && this@HotspotService.downstream == null) {
|
||||||
this@HotspotService.downstream = downstream
|
this@HotspotService.downstream = downstream
|
||||||
@@ -80,7 +80,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
doStart(group)
|
doStart(group)
|
||||||
} else startFailure("Something went wrong, please check logcat.")
|
} else startFailure("Something went wrong, please check logcat.")
|
||||||
}
|
}
|
||||||
group.`interface`
|
|
||||||
binder.data?.onGroupChanged()
|
binder.data?.onGroupChanged()
|
||||||
Log.d(TAG, "${intent.action}: $info, $net, $group")
|
Log.d(TAG, "${intent.action}: $info, $net, $group")
|
||||||
}
|
}
|
||||||
@@ -93,7 +92,8 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: do something to these hardcoded strings
|
// TODO: do something to these hardcoded strings
|
||||||
private var downstream: String? = null
|
var downstream: String? = null
|
||||||
|
private set
|
||||||
private val upstream = "tun0"
|
private val upstream = "tun0"
|
||||||
private val route = "192.168.49.0/24"
|
private val route = "192.168.49.0/24"
|
||||||
private val dns = "8.8.8.8:53"
|
private val dns = "8.8.8.8:53"
|
||||||
@@ -122,7 +122,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
if (!receiverRegistered) {
|
if (!receiverRegistered) {
|
||||||
registerReceiver(receiver, createIntentFilter(
|
registerReceiver(receiver, createIntentFilter(
|
||||||
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
|
WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION,
|
||||||
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION,
|
|
||||||
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION,
|
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION,
|
||||||
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION))
|
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION))
|
||||||
receiverRegistered = true
|
receiverRegistered = true
|
||||||
@@ -157,7 +156,6 @@ class HotspotService : Service(), WifiP2pManager.ChannelListener {
|
|||||||
})
|
})
|
||||||
private fun doStart(group: WifiP2pGroup) {
|
private fun doStart(group: WifiP2pGroup) {
|
||||||
this.group = group
|
this.group = group
|
||||||
clients = group.clientList
|
|
||||||
status = Status.ACTIVE
|
status = Status.ACTIVE
|
||||||
startForeground(1, NotificationCompat.Builder(this@HotspotService, CHANNEL)
|
startForeground(1, NotificationCompat.Builder(this@HotspotService, CHANNEL)
|
||||||
.setWhen(0)
|
.setWhen(0)
|
||||||
|
|||||||
@@ -47,31 +47,31 @@ class MainActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
val running get() = binder?.status == HotspotService.Status.ACTIVE
|
val running get() = binder?.status == HotspotService.Status.ACTIVE
|
||||||
val ssid: String @Bindable get() = if (running) binder!!.service.group.networkName else ""
|
val ssid: String @Bindable get() = if (running) binder!!.service.group.networkName else ""
|
||||||
val password: String @Bindable get() = if (running) binder!!.service.group.passphrase else ""
|
val password: String @Bindable get() = if (running) binder!!.service.group.passphrase else ""
|
||||||
val clients @Bindable get() = if (running) binder!!.service.clients else null
|
|
||||||
|
|
||||||
fun onStatusChanged() {
|
fun onStatusChanged() {
|
||||||
notifyPropertyChanged(BR.switchEnabled)
|
notifyPropertyChanged(BR.switchEnabled)
|
||||||
notifyPropertyChanged(BR.serviceStarted)
|
notifyPropertyChanged(BR.serviceStarted)
|
||||||
onGroupChanged()
|
onGroupChanged()
|
||||||
onClientsChanged()
|
|
||||||
}
|
}
|
||||||
fun onGroupChanged() {
|
fun onGroupChanged() {
|
||||||
notifyPropertyChanged(BR.ssid)
|
notifyPropertyChanged(BR.ssid)
|
||||||
notifyPropertyChanged(BR.password)
|
notifyPropertyChanged(BR.password)
|
||||||
|
adapter.fetchClients()
|
||||||
}
|
}
|
||||||
fun onClientsChanged() = adapter.fetchClients()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClientViewHolder(val binding: ClientBinding) : RecyclerView.ViewHolder(binding.root)
|
class ClientViewHolder(val binding: ClientBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
inner class ClientAdapter : RecyclerView.Adapter<ClientViewHolder>() {
|
inner class ClientAdapter : RecyclerView.Adapter<ClientViewHolder>() {
|
||||||
private var owner: WifiP2pDevice? = null
|
private var owner: WifiP2pDevice? = null
|
||||||
private lateinit var clients: MutableCollection<WifiP2pDevice>
|
private lateinit var clients: MutableCollection<WifiP2pDevice>
|
||||||
|
private lateinit var arpCache: ArpCache
|
||||||
|
|
||||||
fun fetchClients() {
|
fun fetchClients() {
|
||||||
val binder = binder!!
|
val binder = binder!!
|
||||||
if (data.running) {
|
if (data.running) {
|
||||||
owner = binder.service.group.owner
|
owner = binder.service.group.owner
|
||||||
clients = binder.service.clients
|
clients = binder.service.group.clientList
|
||||||
|
arpCache = ArpCache(binder.service.downstream!!)
|
||||||
} else owner = null
|
} else owner = null
|
||||||
notifyDataSetChanged() // recreate everything
|
notifyDataSetChanged() // recreate everything
|
||||||
}
|
}
|
||||||
@@ -80,10 +80,15 @@ class MainActivity : AppCompatActivity(), ServiceConnection {
|
|||||||
ClientViewHolder(ClientBinding.inflate(LayoutInflater.from(parent.context)))
|
ClientViewHolder(ClientBinding.inflate(LayoutInflater.from(parent.context)))
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ClientViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ClientViewHolder, position: Int) {
|
||||||
holder.binding.device = when (position) {
|
val device = when (position) {
|
||||||
0 -> owner
|
0 -> owner
|
||||||
else -> clients.elementAt(position - 1)
|
else -> clients.elementAt(position - 1)
|
||||||
}
|
}
|
||||||
|
holder.binding.device = device
|
||||||
|
holder.binding.ipAddress = when (position) {
|
||||||
|
0 -> binder?.service?.hostAddress?.hostAddress?.toString()
|
||||||
|
else -> arpCache[device?.deviceAddress]
|
||||||
|
}
|
||||||
holder.binding.executePendingBindings()
|
holder.binding.executePendingBindings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,44 +3,31 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<data>
|
<data>
|
||||||
|
<import type="android.view.View"/>
|
||||||
<variable
|
<variable
|
||||||
name="device"
|
name="device"
|
||||||
type="android.net.wifi.p2p.WifiP2pDevice"/>
|
type="android.net.wifi.p2p.WifiP2pDevice"/>
|
||||||
|
<variable
|
||||||
|
name="ipAddress"
|
||||||
|
type="String"/>
|
||||||
</data>
|
</data>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{device.deviceName}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
|
||||||
tools:text="Device name"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{device.deviceAddress}"
|
android:text="@{device.deviceAddress}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||||
tools:text="xx:xx:xx:xx:xx:xx"/>
|
tools:text="xx:xx:xx:xx:xx:xx"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{device.primaryDeviceType}"
|
android:visibility="@{ipAddress == null ? View.GONE : View.VISIBLE}"
|
||||||
tools:text="Primary type"/>
|
android:text="@{ipAddress}"
|
||||||
|
tools:text="192.168.49.123"/>
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{device.secondaryDeviceType}"
|
|
||||||
tools:text="Secondary type"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@{Integer.toString(device.status)}"
|
|
||||||
tools:text="Status"/>
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
Reference in New Issue
Block a user