Fix tethering stability issues
This commit is contained in:
@@ -1,34 +1,33 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.Binder
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v4.content.LocalBroadcastManager
|
||||
import android.widget.Toast
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.net.NetUtils
|
||||
import be.mygod.vpnhotspot.net.Routing
|
||||
import be.mygod.vpnhotspot.net.VpnMonitor
|
||||
import be.mygod.vpnhotspot.net.*
|
||||
|
||||
class TetheringService : Service(), VpnMonitor.Callback {
|
||||
class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Callback {
|
||||
companion object {
|
||||
const val ACTION_ACTIVE_INTERFACES_CHANGED = "be.mygod.vpnhotspot.TetheringService.ACTIVE_INTERFACES_CHANGED"
|
||||
const val CHANNEL = "tethering"
|
||||
const val CHANNEL_ID = 2
|
||||
const val EXTRA_ADD_INTERFACE = "interface.add"
|
||||
const val EXTRA_REMOVE_INTERFACE = "interface.remove"
|
||||
private const val KEY_ACTIVE = "persist.service.tether.active"
|
||||
|
||||
private var alive = false
|
||||
var active: Set<String>
|
||||
get() = if (alive) app.pref.getStringSet(KEY_ACTIVE, null) ?: emptySet() else {
|
||||
app.pref.edit().remove(KEY_ACTIVE).apply()
|
||||
emptySet()
|
||||
}
|
||||
private set(value) {
|
||||
app.pref.edit().putStringSet(KEY_ACTIVE, value).apply()
|
||||
LocalBroadcastManager.getInstance(app).sendBroadcast(Intent(ACTION_ACTIVE_INTERFACES_CHANGED))
|
||||
}
|
||||
}
|
||||
|
||||
inner class TetheringBinder : Binder() {
|
||||
val active get() = routings.keys
|
||||
var fragment: TetheringFragment? = null
|
||||
}
|
||||
|
||||
private val binder = TetheringBinder()
|
||||
private val routings = HashMap<String, Routing?>()
|
||||
private var neighbours = emptyList<IpNeighbour>()
|
||||
private var upstream: String? = null
|
||||
private var receiverRegistered = false
|
||||
private val receiver = broadcastReceiver { _, intent ->
|
||||
@@ -47,6 +46,7 @@ class TetheringService : Service(), VpnMonitor.Callback {
|
||||
private fun updateRoutings() {
|
||||
if (routings.isEmpty()) {
|
||||
unregisterReceiver()
|
||||
stopForeground(true)
|
||||
stopSelf()
|
||||
} else {
|
||||
val upstream = upstream
|
||||
@@ -65,29 +65,24 @@ class TetheringService : Service(), VpnMonitor.Callback {
|
||||
registerReceiver(receiver, intentFilter(NetUtils.ACTION_TETHER_STATE_CHANGED))
|
||||
LocalBroadcastManager.getInstance(this)
|
||||
.registerReceiver(receiver, intentFilter(App.ACTION_CLEAN_ROUTINGS))
|
||||
IpNeighbourMonitor.registerCallback(this)
|
||||
VpnMonitor.registerCallback(this)
|
||||
receiverRegistered = true
|
||||
}
|
||||
}
|
||||
active = routings.keys
|
||||
postIpNeighbourAvailable()
|
||||
app.handler.post { binder.fragment?.adapter?.notifyDataSetChanged() }
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
alive = true
|
||||
}
|
||||
override fun onBind(intent: Intent?) = binder
|
||||
|
||||
override fun onBind(intent: Intent?) = null
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (intent != null) { // otw service is recreated after being killed
|
||||
val iface = intent.getStringExtra(EXTRA_ADD_INTERFACE)
|
||||
if (iface != null) routings.put(iface, null)
|
||||
if (routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.stop() == false)
|
||||
Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
|
||||
} else active.forEach { routings.put(it, null) }
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
val iface = intent.getStringExtra(EXTRA_ADD_INTERFACE)
|
||||
if (iface != null) routings[iface] = null
|
||||
if (routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.stop() == false)
|
||||
Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
|
||||
updateRoutings()
|
||||
return START_STICKY
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onAvailable(ifname: String) {
|
||||
@@ -107,9 +102,31 @@ class TetheringService : Service(), VpnMonitor.Callback {
|
||||
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onIpNeighbourAvailable(neighbours: Map<String, IpNeighbour>) {
|
||||
this.neighbours = neighbours.values.toList()
|
||||
}
|
||||
override fun postIpNeighbourAvailable() {
|
||||
val builder = NotificationCompat.Builder(this, CHANNEL)
|
||||
.setWhen(0)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
|
||||
.setContentTitle("VPN tethering active")
|
||||
.setSmallIcon(R.drawable.ic_device_wifi_tethering)
|
||||
.setContentIntent(PendingIntent.getActivity(this, 0,
|
||||
Intent(this, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||
val content = neighbours.groupBy { it.dev }
|
||||
.filter { (dev, _) -> routings.contains(dev) }
|
||||
.mapValues { (_, neighbours) -> neighbours.size }
|
||||
.toList()
|
||||
.joinToString(", ") { (dev, size) ->
|
||||
resources.getQuantityString(R.plurals.notification_connected_devices, size, size, dev)
|
||||
}
|
||||
if (content.isNotEmpty()) builder.setContentText(content)
|
||||
startForeground(CHANNEL_ID, builder.build())
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
unregisterReceiver()
|
||||
alive = false
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user