Allow user to turn off safe mode on Android 10 (Mar 2020 or newer)
Fixes #153. Basically, this "forward"-ports a workaround for Android 9- thanks to Jimmy Chen. As a consequence, #31 might reoccur if you turn off safe mode.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
@@ -24,11 +25,13 @@ import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupI
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
|
||||
import be.mygod.vpnhotspot.net.wifi.configuration.channelToFrequency
|
||||
import be.mygod.vpnhotspot.room.macToString
|
||||
import be.mygod.vpnhotspot.util.*
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import kotlinx.coroutines.*
|
||||
import timber.log.Timber
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
import java.net.NetworkInterface
|
||||
|
||||
/**
|
||||
* Service for handling Wi-Fi P2P. `supported` must be checked before this service is started otherwise it would crash.
|
||||
@@ -36,6 +39,9 @@ import java.lang.reflect.InvocationTargetException
|
||||
class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
companion object {
|
||||
const val KEY_SAFE_MODE = "service.repeater.safeMode"
|
||||
private const val KEY_LAST_MAC = "service.repeater.lastMac"
|
||||
|
||||
private const val KEY_NETWORK_NAME = "service.repeater.networkName"
|
||||
private const val KEY_PASSPHRASE = "service.repeater.passphrase"
|
||||
private const val KEY_OPERATING_BAND = "service.repeater.band"
|
||||
@@ -57,9 +63,19 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
}
|
||||
}
|
||||
val supported get() = p2pManager != null
|
||||
@Deprecated("Not initialized and no use at all since API 29")
|
||||
var persistentSupported = false
|
||||
|
||||
private val hasP2pValidateName by lazy {
|
||||
val (y, m, _) = Build.VERSION.SECURITY_PATCH.split('-', limit = 3).map { it.toInt() }
|
||||
y > 2020 || y == 2020 && m >= 3
|
||||
}
|
||||
val safeModeConfigurable get() = Build.VERSION.SDK_INT >= 29 && hasP2pValidateName
|
||||
val safeMode get() = Build.VERSION.SDK_INT >= 29 &&
|
||||
(!hasP2pValidateName || app.pref.getBoolean(KEY_SAFE_MODE, true))
|
||||
var lastMac: String?
|
||||
get() = app.pref.getString(KEY_LAST_MAC, null)
|
||||
private set(value) = app.pref.edit { putString(KEY_LAST_MAC, value) }
|
||||
|
||||
var networkName: String?
|
||||
get() = app.pref.getString(KEY_NETWORK_NAME, null)
|
||||
set(value) = app.pref.edit { putString(KEY_NETWORK_NAME, value) }
|
||||
@@ -94,7 +110,6 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
}
|
||||
}
|
||||
val groupChanged = StickyEvent1 { group }
|
||||
@Deprecated("Not initialized and no use at all since API 29")
|
||||
var thisDevice: WifiP2pDevice? = null
|
||||
|
||||
fun startWps(pin: String? = null) {
|
||||
@@ -136,13 +151,11 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP))
|
||||
}
|
||||
}
|
||||
@Deprecated("No longer used since API 29")
|
||||
@Suppress("DEPRECATION")
|
||||
private val deviceListener = broadcastReceiver { _, intent ->
|
||||
when (intent.action) {
|
||||
WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> binder.thisDevice =
|
||||
intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
|
||||
WifiP2pManagerHelper.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION -> onPersistentGroupsChanged()
|
||||
WifiP2pManagerHelper.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION -> if (!safeMode) onPersistentGroupsChanged()
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -174,17 +187,13 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
onChannelDisconnected()
|
||||
if (Build.VERSION.SDK_INT < 29) @Suppress("DEPRECATION") {
|
||||
registerReceiver(deviceListener, intentFilter(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION,
|
||||
WifiP2pManagerHelper.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION))
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
registerReceiver(deviceListener, intentFilter(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION,
|
||||
WifiP2pManagerHelper.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION))
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent) = binder
|
||||
|
||||
@Deprecated("No longer used since API 29")
|
||||
@Suppress("DEPRECATION")
|
||||
private fun setOperatingChannel(oc: Int = operatingChannel) = try {
|
||||
val channel = channel
|
||||
if (channel == null) SmartSnackbar.make(R.string.repeater_failure_disconnected).show()
|
||||
@@ -207,21 +216,17 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
channel = null
|
||||
if (status != Status.DESTROYED) try {
|
||||
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
||||
if (Build.VERSION.SDK_INT < 29) @Suppress("DEPRECATION") setOperatingChannel()
|
||||
if (!safeMode) setOperatingChannel()
|
||||
} catch (e: RuntimeException) {
|
||||
Timber.w(e)
|
||||
handler.postDelayed(this::onChannelDisconnected, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("No longer used since API 29")
|
||||
@Suppress("DEPRECATION")
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == KEY_OPERATING_CHANNEL) setOperatingChannel()
|
||||
if (!safeMode && key == KEY_OPERATING_CHANNEL) setOperatingChannel()
|
||||
}
|
||||
|
||||
@Deprecated("No longer used since API 29")
|
||||
@Suppress("DEPRECATION")
|
||||
private fun onPersistentGroupsChanged() {
|
||||
val channel = channel ?: return
|
||||
val device = binder.thisDevice ?: return
|
||||
@@ -300,43 +305,45 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
val networkName = networkName
|
||||
val passphrase = passphrase
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < 29 || networkName == null || passphrase == null) {
|
||||
if (!safeMode || networkName == null || passphrase == null) {
|
||||
persistNextGroup = true
|
||||
p2pManager.createGroup(channel, listener)
|
||||
} else p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply {
|
||||
setNetworkName(PLACEHOLDER_NETWORK_NAME)
|
||||
setPassphrase(passphrase)
|
||||
operatingChannel.let { oc ->
|
||||
if (oc == 0) setGroupOperatingBand(operatingBand)
|
||||
else setGroupOperatingFrequency(channelToFrequency(oc))
|
||||
}
|
||||
}.build().run {
|
||||
useParcel { p ->
|
||||
p.writeParcelable(this, 0)
|
||||
val end = p.dataPosition()
|
||||
p.setDataPosition(0)
|
||||
val creator = p.readString()
|
||||
val deviceAddress = p.readString()
|
||||
val wps = p.readParcelable<WpsInfo>(javaClass.classLoader)
|
||||
val long = p.readLong()
|
||||
check(p.readString() == PLACEHOLDER_NETWORK_NAME)
|
||||
check(p.readString() == passphrase)
|
||||
val extrasLength = end - p.dataPosition()
|
||||
check(extrasLength and 3 == 0) // parcel should be padded
|
||||
if (extrasLength != 4) Timber.w(Exception("Unexpected extrasLength $extrasLength"))
|
||||
val extras = (0 until extrasLength / 4).map { p.readInt() }
|
||||
p.setDataPosition(0)
|
||||
p.writeString(creator)
|
||||
p.writeString(deviceAddress)
|
||||
p.writeParcelable(wps, 0)
|
||||
p.writeLong(long)
|
||||
p.writeString(networkName)
|
||||
p.writeString(passphrase)
|
||||
extras.forEach(p::writeInt)
|
||||
p.setDataPosition(0)
|
||||
p.readParcelable<WifiP2pConfig>(javaClass.classLoader)
|
||||
}
|
||||
}, listener)
|
||||
} else @TargetApi(29) {
|
||||
p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply {
|
||||
setNetworkName(PLACEHOLDER_NETWORK_NAME)
|
||||
setPassphrase(passphrase)
|
||||
operatingChannel.let { oc ->
|
||||
if (oc == 0) setGroupOperatingBand(operatingBand)
|
||||
else setGroupOperatingFrequency(channelToFrequency(oc))
|
||||
}
|
||||
}.build().run {
|
||||
useParcel { p ->
|
||||
p.writeParcelable(this, 0)
|
||||
val end = p.dataPosition()
|
||||
p.setDataPosition(0)
|
||||
val creator = p.readString()
|
||||
val deviceAddress = p.readString()
|
||||
val wps = p.readParcelable<WpsInfo>(javaClass.classLoader)
|
||||
val long = p.readLong()
|
||||
check(p.readString() == PLACEHOLDER_NETWORK_NAME)
|
||||
check(p.readString() == passphrase)
|
||||
val extrasLength = end - p.dataPosition()
|
||||
check(extrasLength and 3 == 0) // parcel should be padded
|
||||
if (extrasLength != 4) Timber.w(Exception("Unexpected extrasLength $extrasLength"))
|
||||
val extras = (0 until extrasLength / 4).map { p.readInt() }
|
||||
p.setDataPosition(0)
|
||||
p.writeString(creator)
|
||||
p.writeString(deviceAddress)
|
||||
p.writeParcelable(wps, 0)
|
||||
p.writeLong(long)
|
||||
p.writeString(networkName)
|
||||
p.writeString(passphrase)
|
||||
extras.forEach(p::writeInt)
|
||||
p.setDataPosition(0)
|
||||
p.readParcelable<WifiP2pConfig>(javaClass.classLoader)
|
||||
}
|
||||
}, listener)
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
Timber.w(e)
|
||||
startFailure(e.readableMessage)
|
||||
@@ -371,7 +378,11 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
persistNextGroup = false
|
||||
}
|
||||
check(routingManager == null)
|
||||
routingManager = RoutingManager.LocalOnly(this, group.`interface`!!).apply { start() }
|
||||
routingManager = object : RoutingManager.LocalOnly(this, group.`interface`!!) {
|
||||
override fun ifaceHandler(iface: NetworkInterface) {
|
||||
iface.hardwareAddress?.asIterable()?.macToString()?.let { lastMac = it }
|
||||
}
|
||||
}.apply { start() }
|
||||
status = Status.ACTIVE
|
||||
showNotification(group)
|
||||
}
|
||||
@@ -426,10 +437,8 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
||||
cancel()
|
||||
dispatcher.close()
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < 29) @Suppress("DEPRECATION") {
|
||||
app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
||||
unregisterReceiver(deviceListener)
|
||||
}
|
||||
app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
||||
unregisterReceiver(deviceListener)
|
||||
status = Status.DESTROYED
|
||||
if (Build.VERSION.SDK_INT >= 27) channel?.close()
|
||||
super.onDestroy()
|
||||
|
||||
Reference in New Issue
Block a user