From 3ba9a322c27a59388e599811a7890db095340431 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 22 Apr 2020 12:21:14 +0800 Subject: [PATCH] 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. --- .../be/mygod/vpnhotspot/RepeaterService.kt | 125 ++++++++++-------- .../be/mygod/vpnhotspot/RoutingManager.kt | 7 +- .../vpnhotspot/SettingsPreferenceFragment.kt | 4 + .../vpnhotspot/manage/RepeaterManager.kt | 13 +- .../java/be/mygod/vpnhotspot/net/Routing.kt | 8 +- .../net/wifi/WifiP2pManagerHelper.kt | 5 - .../P2pSupplicantConfiguration.kt | 12 +- .../configuration/WifiApDialogFragment.kt | 12 +- .../main/res/drawable/ic_alert_warning.xml | 10 ++ mobile/src/main/res/values-zh-rCN/strings.xml | 3 + mobile/src/main/res/values/strings.xml | 4 + mobile/src/main/res/xml/pref_settings.xml | 6 + 12 files changed, 121 insertions(+), 88 deletions(-) create mode 100644 mobile/src/main/res/drawable/ic_alert_warning.xml diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index a6de2d58..3c561c26 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -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(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(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(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(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() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RoutingManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RoutingManager.kt index fcd0e204..5beb538a 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RoutingManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RoutingManager.kt @@ -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) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt index 2ae034ff..90cbe2d5 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt @@ -74,6 +74,10 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() { } boot.isChecked = BootReceiver.enabled } else boot.parent!!.removePreference(boot) + if (!RepeaterService.supported || !RepeaterService.safeModeConfigurable) { + val safeMode = findPreference(RepeaterService.KEY_SAFE_MODE)!! + safeMode.parent!!.removePreference(safeMode) + } findPreference("service.clean")!!.setOnPreferenceClickListener { GlobalScope.launch { RoutingManager.clean() } true diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt index 17d1a1f1..c0d55109 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/RepeaterManager.kt @@ -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() 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 diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt index dbe5f1ff..1f9d31c2 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt @@ -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) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pManagerHelper.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pManagerHelper.kt index 4452b4ee..e78cbf5d 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pManagerHelper.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/WifiP2pManagerHelper.kt @@ -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) -> 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 } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/P2pSupplicantConfiguration.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/P2pSupplicantConfiguration.kt index a03e3066..74fafa2e 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/P2pSupplicantConfiguration.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/P2pSupplicantConfiguration.kt @@ -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 diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/WifiApDialogFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/WifiApDialogFragment.kt index 39fa091b..b5ce9f19 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/WifiApDialogFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/wifi/configuration/WifiApDialogFragment.kt @@ -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().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 dialogView.password.length() >= 8 else -> true // do not try to validate @@ -169,7 +170,8 @@ class WifiApDialogFragment : AlertDialogFragment + + diff --git a/mobile/src/main/res/values-zh-rCN/strings.xml b/mobile/src/main/res/values-zh-rCN/strings.xml index 83abe2c3..d77b32ea 100644 --- a/mobile/src/main/res/values-zh-rCN/strings.xml +++ b/mobile/src/main/res/values-zh-rCN/strings.xml @@ -87,6 +87,9 @@ 禁用 IPv6 共享 防止 VPN 通过 IPv6 泄漏。 开机自启动中继 + 中继安全模式 + 不对系统配置进行修改,但是可能须要较长的网络名称。 + 使用短名称可能需要关闭安全模式。 保持 Wi\u2011Fi 开启 系统默认 diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 9ae59eff..fbd108db 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -92,6 +92,10 @@ Disable IPv6 tethering Enabling this option will prevent VPN leaks via IPv6. Start repeater on boot + Repeater safe mode + Makes no changes to your system configuration but might + not work with short SSIDs. + Short SSIDs might require turning off safe mode. Keep Wi\u2011Fi alive System default On diff --git a/mobile/src/main/res/xml/pref_settings.xml b/mobile/src/main/res/xml/pref_settings.xml index 25635777..854e0e45 100644 --- a/mobile/src/main/res/xml/pref_settings.xml +++ b/mobile/src/main/res/xml/pref_settings.xml @@ -62,6 +62,12 @@ app:key="service.repeater.startOnBoot" app:icon="@drawable/ic_action_autorenew" app:title="@string/settings_service_repeater_start_on_boot"/> +