Support Wi-Fi keep alives
This commit is contained in:
@@ -8,6 +8,7 @@ import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.manage.LocalOnlyHotspotManager
|
||||
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
|
||||
import be.mygod.vpnhotspot.net.TetheringManager
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import timber.log.Timber
|
||||
@@ -30,6 +31,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
||||
private val binder = Binder()
|
||||
private var reservation: WifiManager.LocalOnlyHotspotReservation? = null
|
||||
private var routingManager: LocalOnlyInterfaceManager? = null
|
||||
private var locked = false
|
||||
private var receiverRegistered = false
|
||||
private val receiver = broadcastReceiver { _, intent ->
|
||||
val ifaces = TetheringManager.getLocalOnlyTetheredIfaces(intent.extras ?: return@broadcastReceiver)
|
||||
@@ -63,6 +65,9 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
||||
override fun onStarted(reservation: WifiManager.LocalOnlyHotspotReservation?) {
|
||||
if (reservation == null) onFailed(-2) else {
|
||||
this@LocalOnlyHotspotService.reservation = reservation
|
||||
check(!locked)
|
||||
WifiDoubleLock.acquire()
|
||||
locked = true
|
||||
if (!receiverRegistered) {
|
||||
registerReceiver(receiver, IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED))
|
||||
receiverRegistered = true
|
||||
@@ -119,6 +124,10 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService() {
|
||||
private fun unregisterReceiver() {
|
||||
routingManager?.stop()
|
||||
routingManager = null
|
||||
if (locked) {
|
||||
WifiDoubleLock.release()
|
||||
locked = false
|
||||
}
|
||||
if (receiverRegistered) {
|
||||
unregisterReceiver(receiver)
|
||||
IpNeighbourMonitor.unregisterCallback(this)
|
||||
|
||||
@@ -15,6 +15,7 @@ import androidx.annotation.StringRes
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.postDelayed
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.netId
|
||||
@@ -123,6 +124,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
}
|
||||
}
|
||||
private var routingManager: LocalOnlyInterfaceManager? = null
|
||||
private var locked = false
|
||||
|
||||
var status = Status.IDLE
|
||||
private set(value) {
|
||||
@@ -261,6 +263,9 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
* startService Step 3
|
||||
*/
|
||||
private fun doStart(group: WifiP2pGroup) {
|
||||
check(!locked)
|
||||
WifiDoubleLock.acquire()
|
||||
locked = true
|
||||
binder.group = group
|
||||
check(routingManager == null)
|
||||
routingManager = LocalOnlyInterfaceManager(group.`interface`!!)
|
||||
@@ -297,6 +302,10 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
unregisterReceiver()
|
||||
routingManager?.stop()
|
||||
routingManager = null
|
||||
if (locked) {
|
||||
WifiDoubleLock.release()
|
||||
locked = false
|
||||
}
|
||||
status = Status.IDLE
|
||||
ServiceNotification.stopForeground(this)
|
||||
stopSelf()
|
||||
|
||||
@@ -5,8 +5,10 @@ import android.content.IntentFilter
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.manage.TetheringFragment
|
||||
import be.mygod.vpnhotspot.net.Routing
|
||||
import be.mygod.vpnhotspot.net.TetherType
|
||||
import be.mygod.vpnhotspot.net.TetheringManager
|
||||
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||
import be.mygod.vpnhotspot.util.broadcastReceiver
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import timber.log.Timber
|
||||
@@ -25,6 +27,7 @@ class TetheringService : IpNeighbourMonitoringService() {
|
||||
|
||||
private val binder = Binder()
|
||||
private val routings = HashMap<String, Routing?>()
|
||||
private var locked = false
|
||||
private var receiverRegistered = false
|
||||
private val receiver = broadcastReceiver { _, intent ->
|
||||
val extras = intent.extras ?: return@broadcastReceiver
|
||||
@@ -37,6 +40,10 @@ class TetheringService : IpNeighbourMonitoringService() {
|
||||
override val activeIfaces get() = synchronized(routings) { routings.keys.toList() }
|
||||
|
||||
private fun updateRoutingsLocked() {
|
||||
if (locked && routings.keys.all { !TetherType.ofInterface(it).isWifi }) {
|
||||
WifiDoubleLock.release()
|
||||
locked = false
|
||||
}
|
||||
if (routings.isEmpty()) {
|
||||
unregisterReceiver()
|
||||
ServiceNotification.stopForeground(this)
|
||||
@@ -92,7 +99,13 @@ class TetheringService : IpNeighbourMonitoringService() {
|
||||
if (intent != null) {
|
||||
val iface = intent.getStringExtra(EXTRA_ADD_INTERFACE)
|
||||
synchronized(routings) {
|
||||
if (iface != null) routings[iface] = null
|
||||
if (iface != null) {
|
||||
routings[iface] = null
|
||||
if (TetherType.ofInterface(iface).isWifi && !locked) {
|
||||
WifiDoubleLock.acquire()
|
||||
locked = true
|
||||
}
|
||||
}
|
||||
routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.revert()
|
||||
updateRoutingsLocked()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ enum class TetherType {
|
||||
BLUETOOTH -> R.drawable.ic_device_bluetooth
|
||||
else -> R.drawable.ic_device_wifi_tethering
|
||||
}
|
||||
val isWifi get() = when (this) {
|
||||
WIFI_P2P, WIFI, WIMAX -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val usbRegexes: List<Pattern>
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package be.mygod.vpnhotspot.net.wifi
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.PowerManager
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
|
||||
/**
|
||||
* This mechanism is used to maximize profit. Source: https://stackoverflow.com/a/29657230/2245107
|
||||
*/
|
||||
class WifiDoubleLock(lockType: Int) : AutoCloseable {
|
||||
companion object : SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private const val KEY = "service.wifiLock"
|
||||
private val lockType get() =
|
||||
WifiDoubleLock.Mode.valueOf(app.pref.getString(KEY, WifiDoubleLock.Mode.Full.toString()) ?: "").lockType
|
||||
private val service by lazy { app.getSystemService<PowerManager>()!! }
|
||||
|
||||
private var referenceCount = 0
|
||||
private var lock: WifiDoubleLock? = null
|
||||
|
||||
fun acquire() = synchronized(this) {
|
||||
if (referenceCount == 0) {
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
val lockType = lockType
|
||||
if (lockType != null) lock = WifiDoubleLock(lockType)
|
||||
}
|
||||
referenceCount += 1
|
||||
}
|
||||
fun release() = synchronized(this) {
|
||||
referenceCount -= 1
|
||||
if (referenceCount == 0) {
|
||||
lock?.close()
|
||||
lock = null
|
||||
app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == KEY) synchronized(this) {
|
||||
lock?.close()
|
||||
val lockType = lockType
|
||||
lock = if (lockType == null) null else WifiDoubleLock(lockType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Mode(val lockType: Int? = null) {
|
||||
None, Full(WifiManager.WIFI_MODE_FULL), HighPerf(WifiManager.WIFI_MODE_FULL_HIGH_PERF)
|
||||
}
|
||||
|
||||
private val wifi = app.wifi.createWifiLock(lockType, "vpnhotspot:wifi").apply { acquire() }
|
||||
@SuppressLint("WakelockTimeout")
|
||||
private val power = service.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "vpnhotspot:power").apply { acquire() }
|
||||
|
||||
override fun close() {
|
||||
wifi.release()
|
||||
power.release()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user