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()
|
||||
|
||||
@@ -7,6 +7,7 @@ import be.mygod.vpnhotspot.net.Routing
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import timber.log.Timber
|
||||
import java.net.NetworkInterface
|
||||
|
||||
abstract class RoutingManager(private val caller: Any, val downstream: String, private val isWifi: Boolean) {
|
||||
companion object {
|
||||
@@ -42,7 +43,7 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
|
||||
/**
|
||||
* Both repeater and local-only hotspot are Wi-Fi based.
|
||||
*/
|
||||
class LocalOnly(caller: Any, downstream: String) : RoutingManager(caller, downstream, true) {
|
||||
open class LocalOnly(caller: Any, downstream: String) : RoutingManager(caller, downstream, true) {
|
||||
override fun Routing.configure() {
|
||||
ipForward() // local only interfaces need to enable ip_forward
|
||||
forward()
|
||||
@@ -63,8 +64,10 @@ abstract class RoutingManager(private val caller: Any, val downstream: String, p
|
||||
else -> error("Double routing detected for $downstream from $caller != ${other.caller}")
|
||||
}
|
||||
|
||||
open fun ifaceHandler(iface: NetworkInterface) { }
|
||||
|
||||
private fun initRouting() = try {
|
||||
routing = Routing(caller, downstream).apply {
|
||||
routing = Routing(caller, downstream, this::ifaceHandler).apply {
|
||||
try {
|
||||
configure()
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -74,6 +74,10 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
boot.isChecked = BootReceiver.enabled
|
||||
} else boot.parent!!.removePreference(boot)
|
||||
if (!RepeaterService.supported || !RepeaterService.safeModeConfigurable) {
|
||||
val safeMode = findPreference<Preference>(RepeaterService.KEY_SAFE_MODE)!!
|
||||
safeMode.parent!!.removePreference(safeMode)
|
||||
}
|
||||
findPreference<Preference>("service.clean")!!.setOnPreferenceClickListener {
|
||||
GlobalScope.launch { RoutingManager.clean() }
|
||||
true
|
||||
|
||||
@@ -56,7 +56,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
|
||||
val title: CharSequence @Bindable get() {
|
||||
if (Build.VERSION.SDK_INT >= 29) binder?.group?.frequency?.let {
|
||||
return parent.getString(R.string.repeater_channel, it, frequencyToChannel(it))
|
||||
if (it != 0) return parent.getString(R.string.repeater_channel, it, frequencyToChannel(it))
|
||||
}
|
||||
return parent.getString(R.string.title_repeater)
|
||||
}
|
||||
@@ -120,8 +120,6 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("No longer used since API 29")
|
||||
@Suppress("DEPRECATION")
|
||||
class ConfigHolder : ViewModel() {
|
||||
var config: P2pSupplicantConfiguration? = null
|
||||
}
|
||||
@@ -134,7 +132,6 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
private val data = Data()
|
||||
internal var binder: RepeaterService.Binder? = null
|
||||
private var p2pInterface: String? = null
|
||||
@Suppress("DEPRECATION")
|
||||
private val holder by parent.viewModels<ConfigHolder>()
|
||||
|
||||
override fun bindTo(viewHolder: RecyclerView.ViewHolder) {
|
||||
@@ -164,7 +161,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
}
|
||||
|
||||
val configuration: WifiConfiguration? get() {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
if (RepeaterService.safeMode) {
|
||||
val networkName = RepeaterService.networkName
|
||||
val passphrase = RepeaterService.passphrase
|
||||
if (networkName != null && passphrase != null) {
|
||||
@@ -179,7 +176,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
apChannel = RepeaterService.operatingChannel
|
||||
}
|
||||
}
|
||||
} else @Suppress("DEPRECATION") {
|
||||
} else {
|
||||
val group = binder?.group
|
||||
if (group != null) try {
|
||||
val config = P2pSupplicantConfiguration(group, binder?.thisDevice?.deviceAddress)
|
||||
@@ -199,7 +196,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
return null
|
||||
}
|
||||
suspend fun updateConfiguration(config: WifiConfiguration) {
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
if (RepeaterService.safeMode) {
|
||||
RepeaterService.networkName = config.SSID
|
||||
RepeaterService.passphrase = config.preSharedKey
|
||||
RepeaterService.operatingBand = when (config.apBand) {
|
||||
@@ -208,7 +205,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
||||
AP_BAND_5GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_5GHZ
|
||||
else -> throw IllegalArgumentException("Unknown apBand")
|
||||
}
|
||||
} else @Suppress("DEPRECATION") holder.config?.let { master ->
|
||||
} else holder.config?.let { master ->
|
||||
if (binder?.group?.networkName != config.SSID || master.psk != config.preSharedKey) try {
|
||||
withContext(Dispatchers.Default) { master.update(config.SSID, config.preSharedKey) }
|
||||
binder!!.group = null
|
||||
|
||||
@@ -25,7 +25,8 @@ import java.net.SocketException
|
||||
*
|
||||
* Once revert is called, this object no longer serves any purpose.
|
||||
*/
|
||||
class Routing(private val caller: Any, private val downstream: String) : IpNeighbourMonitor.Callback {
|
||||
class Routing(private val caller: Any, private val downstream: String,
|
||||
ifaceHandler: (NetworkInterface) -> Unit) : IpNeighbourMonitor.Callback {
|
||||
companion object {
|
||||
/**
|
||||
* Since Android 5.0, RULE_PRIORITY_TETHERING = 18000.
|
||||
@@ -117,8 +118,9 @@ class Routing(private val caller: Any, private val downstream: String) : IpNeigh
|
||||
}
|
||||
|
||||
private val hostAddress = try {
|
||||
val addresses = NetworkInterface.getByName(downstream)!!.interfaceAddresses!!
|
||||
.filter { it.address is Inet4Address }
|
||||
val iface = NetworkInterface.getByName(downstream)!!
|
||||
ifaceHandler(iface)
|
||||
val addresses = iface.interfaceAddresses!!.filter { it.address is Inet4Address }
|
||||
if (addresses.size > 1) error("More than one addresses was found: $addresses")
|
||||
addresses.first()
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -11,7 +11,6 @@ import java.lang.reflect.Proxy
|
||||
|
||||
object WifiP2pManagerHelper {
|
||||
const val UNSUPPORTED = -2
|
||||
@Deprecated("No longer used since API 29")
|
||||
const val WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION = "android.net.wifi.p2p.PERSISTENT_GROUPS_CHANGED"
|
||||
|
||||
/**
|
||||
@@ -24,7 +23,6 @@ object WifiP2pManagerHelper {
|
||||
WifiP2pManager::class.java.getDeclaredMethod("setWifiP2pChannels", WifiP2pManager.Channel::class.java,
|
||||
Int::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
||||
}
|
||||
@Deprecated("No longer used since API 29")
|
||||
fun WifiP2pManager.setWifiP2pChannels(c: WifiP2pManager.Channel, lc: Int, oc: Int,
|
||||
listener: WifiP2pManager.ActionListener) {
|
||||
try {
|
||||
@@ -63,7 +61,6 @@ object WifiP2pManagerHelper {
|
||||
WifiP2pManager::class.java.getDeclaredMethod("deletePersistentGroup",
|
||||
WifiP2pManager.Channel::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
||||
}
|
||||
@Deprecated("No longer used since API 29")
|
||||
fun WifiP2pManager.deletePersistentGroup(c: WifiP2pManager.Channel, netId: Int,
|
||||
listener: WifiP2pManager.ActionListener) {
|
||||
try {
|
||||
@@ -90,7 +87,6 @@ object WifiP2pManagerHelper {
|
||||
* @param c is the channel created at {@link #initialize}
|
||||
* @param listener for callback when persistent group info list is available. Can be null.
|
||||
*/
|
||||
@Deprecated("No longer used since API 29")
|
||||
fun WifiP2pManager.requestPersistentGroupInfo(c: WifiP2pManager.Channel,
|
||||
listener: (Collection<WifiP2pGroup>) -> Unit) {
|
||||
val proxy = Proxy.newProxyInstance(interfacePersistentGroupInfoListener.classLoader,
|
||||
@@ -115,6 +111,5 @@ object WifiP2pManagerHelper {
|
||||
private val getNetworkId by lazy @SuppressLint("DiscouragedPrivateApi") {
|
||||
WifiP2pGroup::class.java.getDeclaredMethod("getNetworkId")
|
||||
}
|
||||
@Deprecated("No longer used since API 29")
|
||||
val WifiP2pGroup.netId get() = getNetworkId.invoke(this) as Int
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import java.io.File
|
||||
* https://android.googlesource.com/platform/external/wpa_supplicant_8/+/d2986c2/wpa_supplicant/config.c#488
|
||||
* https://android.googlesource.com/platform/external/wpa_supplicant_8/+/6fa46df/wpa_supplicant/config_file.c#182
|
||||
*/
|
||||
@Deprecated("No longer used since API 29")
|
||||
class P2pSupplicantConfiguration(private val group: WifiP2pGroup, ownerAddress: String?) {
|
||||
companion object {
|
||||
private const val TAG = "P2pSupplicantConfiguration"
|
||||
@@ -29,7 +28,7 @@ class P2pSupplicantConfiguration(private val group: WifiP2pGroup, ownerAddress:
|
||||
var pskLine: Int? = null
|
||||
var psk: String? = null
|
||||
var groupOwner = false
|
||||
var bssidMatches = false
|
||||
var bssid: String? = null
|
||||
|
||||
override fun toString() = joinToString("\n")
|
||||
}
|
||||
@@ -53,9 +52,9 @@ class P2pSupplicantConfiguration(private val group: WifiP2pGroup, ownerAddress:
|
||||
RootSession.checkOutput(command, shell, false, false)
|
||||
val parser = Parser(shell.out)
|
||||
try {
|
||||
val bssids = listOfNotNull(group.owner.deviceAddress, ownerAddress)
|
||||
val bssids = listOfNotNull(group.owner.deviceAddress, ownerAddress, RepeaterService.lastMac)
|
||||
.distinct()
|
||||
.filter { it != "00:00:00:00:00:00" }
|
||||
.filter { it != "00:00:00:00:00:00" && it != "02:00:00:00:00:00" }
|
||||
while (parser.next()) {
|
||||
if (parser.trimmed.startsWith("network={")) {
|
||||
val block = NetworkBlock()
|
||||
@@ -73,21 +72,20 @@ class P2pSupplicantConfiguration(private val group: WifiP2pGroup, ownerAddress:
|
||||
block.psk = match.groupValues[5].apply { check(length in 8..63) }
|
||||
}
|
||||
block.pskLine = block.size
|
||||
} else if (bssids.any { matchedBssid.equals(it, true) }) block.bssidMatches = true
|
||||
} else if (bssids.any { matchedBssid.equals(it, true) }) block.bssid = matchedBssid
|
||||
}
|
||||
}
|
||||
block.add(parser.line)
|
||||
}
|
||||
block.add(parser.line)
|
||||
result.add(block)
|
||||
if (block.bssidMatches && block.groupOwner && target == null) { // keep first only
|
||||
if (block.bssid != null && block.groupOwner && target == null) { // keep first only
|
||||
check(block.ssidLine != null && block.pskLine != null)
|
||||
target = block
|
||||
}
|
||||
} else result.add(parser.line)
|
||||
}
|
||||
if (target == null && !RepeaterService.persistentSupported) {
|
||||
val bssid = bssids.single()
|
||||
result.add("")
|
||||
result.add(NetworkBlock().apply {
|
||||
// generate a basic network block, it is likely that vendor is going to add more stuff here
|
||||
|
||||
@@ -28,7 +28,6 @@ import be.mygod.vpnhotspot.util.toByteArray
|
||||
import be.mygod.vpnhotspot.util.toParcelable
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import java.nio.charset.Charset
|
||||
|
||||
/**
|
||||
* Based on: https://android.googlesource.com/platform/packages/apps/Settings/+/39b4674/src/com/android/settings/wifi/WifiApDialog.java
|
||||
@@ -117,7 +116,7 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
bandOptions = mutableListOf<BandOption>().apply {
|
||||
if (arg.p2pMode) {
|
||||
add(BandOption.BandAny)
|
||||
if (Build.VERSION.SDK_INT >= 29) {
|
||||
if (RepeaterService.safeMode) {
|
||||
add(BandOption.Band2GHz)
|
||||
add(BandOption.Band5GHz)
|
||||
}
|
||||
@@ -160,8 +159,10 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
*/
|
||||
private fun validate() {
|
||||
if (!started) return
|
||||
val ssidValid = dialogView.ssid.length() != 0 &&
|
||||
Charset.forName("UTF-8").encode(dialogView.ssid.text.toString()).limit() <= 32
|
||||
val ssidLength = dialogView.ssid.text.toString().toByteArray().size
|
||||
dialogView.ssidWrapper.error = if (RepeaterService.safeModeConfigurable && ssidLength < 9) {
|
||||
requireContext().getString(R.string.settings_service_repeater_safe_mode_warning)
|
||||
} else null
|
||||
val passwordValid = when (selectedSecurity) {
|
||||
WifiConfiguration.KeyMgmt.WPA_PSK, WPA2_PSK -> dialogView.password.length() >= 8
|
||||
else -> true // do not try to validate
|
||||
@@ -169,7 +170,8 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
||||
dialogView.passwordWrapper.error = if (passwordValid) null else {
|
||||
requireContext().getString(R.string.credentials_password_too_short)
|
||||
}
|
||||
(dialog as? AlertDialog)?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = ssidValid && passwordValid
|
||||
(dialog as? AlertDialog)?.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled =
|
||||
ssidLength in 1..32 && passwordValid
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { }
|
||||
|
||||
10
mobile/src/main/res/drawable/ic_alert_warning.xml
Normal file
10
mobile/src/main/res/drawable/ic_alert_warning.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
|
||||
</vector>
|
||||
@@ -87,6 +87,9 @@
|
||||
<string name="settings_service_disable_ipv6">禁用 IPv6 共享</string>
|
||||
<string name="settings_service_disable_ipv6_summary">防止 VPN 通过 IPv6 泄漏。</string>
|
||||
<string name="settings_service_repeater_start_on_boot">开机自启动中继</string>
|
||||
<string name="settings_service_repeater_safe_mode">中继安全模式</string>
|
||||
<string name="settings_service_repeater_safe_mode_summary">不对系统配置进行修改,但是可能须要较长的网络名称。</string>
|
||||
<string name="settings_service_repeater_safe_mode_warning">使用短名称可能需要关闭安全模式。</string>
|
||||
<string name="settings_service_wifi_lock">保持 Wi\u2011Fi 开启</string>
|
||||
<string name="settings_service_wifi_lock_none">系统默认</string>
|
||||
<string name="settings_service_wifi_lock_full">开</string>
|
||||
|
||||
@@ -92,6 +92,10 @@
|
||||
<string name="settings_service_disable_ipv6">Disable IPv6 tethering</string>
|
||||
<string name="settings_service_disable_ipv6_summary">Enabling this option will prevent VPN leaks via IPv6.</string>
|
||||
<string name="settings_service_repeater_start_on_boot">Start repeater on boot</string>
|
||||
<string name="settings_service_repeater_safe_mode">Repeater safe mode</string>
|
||||
<string name="settings_service_repeater_safe_mode_summary">Makes no changes to your system configuration but might
|
||||
not work with short SSIDs.</string>
|
||||
<string name="settings_service_repeater_safe_mode_warning">Short SSIDs might require turning off safe mode.</string>
|
||||
<string name="settings_service_wifi_lock">Keep Wi\u2011Fi alive</string>
|
||||
<string name="settings_service_wifi_lock_none">System default</string>
|
||||
<string name="settings_service_wifi_lock_full">On</string>
|
||||
|
||||
@@ -62,6 +62,12 @@
|
||||
app:key="service.repeater.startOnBoot"
|
||||
app:icon="@drawable/ic_action_autorenew"
|
||||
app:title="@string/settings_service_repeater_start_on_boot"/>
|
||||
<SwitchPreference
|
||||
app:key="service.repeater.safeMode"
|
||||
app:icon="@drawable/ic_alert_warning"
|
||||
app:title="@string/settings_service_repeater_safe_mode"
|
||||
app:summary="@string/settings_service_repeater_safe_mode_summary"
|
||||
app:defaultValue="true"/>
|
||||
<com.takisoft.preferencex.SimpleMenuPreference
|
||||
app:key="service.ipMonitor"
|
||||
app:icon="@drawable/ic_hardware_device_hub"
|
||||
|
||||
Reference in New Issue
Block a user