Support new Wi-Fi locks in Android Q
This commit is contained in:
16
README.md
16
README.md
@@ -65,8 +65,20 @@ Default settings are picked to suit general use cases and maximize compatibility
|
||||
|
||||
* Keep Wi-Fi alive: Acquire Wi-Fi locks when repeater, temporary hotspot or system VPN hotspot is activated.
|
||||
- Choose "System default" to save battery life;
|
||||
- Choose "On" (default) if repeater/hotspot turns itself off automatically or stops working after a while;
|
||||
- Choose "High Performance Mode" to minimize packet loss and latency (will consume more power).
|
||||
- (up to Android 9) Choose "On" (default) if repeater/hotspot turns itself off automatically or stops working after a while;
|
||||
- (up to Android 9) Choose "High Performance Mode" to minimize packet loss and latency (will consume more power);
|
||||
- (since Android Q) Choose "Disable power save" to decrease packet latency.
|
||||
An example use case is when a voice connection needs to be kept active even after the device screen goes off.
|
||||
Using this mode may improve the call quality.
|
||||
Requires support from the hardware.
|
||||
- (since Android Q) Choose "Low latency mode" to optimize for reduced packet latency, and this might result in:
|
||||
1. Reduced battery life.
|
||||
2. Reduced throughput.
|
||||
3. Reduced frequency of Wi-Fi scanning.
|
||||
This may cause the device not roaming or switching to the AP with highest signal quality, and location accuracy may be reduced.
|
||||
Example use cases are real time gaming or virtual reality applications where low latency is a key factor for user experience.
|
||||
Requires support from the hardware.
|
||||
Note: Requires this app running in foreground with screen on.
|
||||
* Start repeater on boot: Self explanatory.
|
||||
* Network status monitor mode: This option controls how the app monitors connected devices as well as interface changes
|
||||
(when custom upstream is used).
|
||||
|
||||
@@ -15,6 +15,7 @@ import be.mygod.vpnhotspot.client.ClientViewModel
|
||||
import be.mygod.vpnhotspot.client.ClientsFragment
|
||||
import be.mygod.vpnhotspot.databinding.ActivityMainBinding
|
||||
import be.mygod.vpnhotspot.manage.TetheringFragment
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
|
||||
@@ -41,6 +42,7 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
||||
if (RepeaterService.supported) ServiceForegroundConnector(this, model, RepeaterService::class)
|
||||
model.clients.observe(this, Observer { badge.badgeNumber = it.size })
|
||||
SmartSnackbar.Register(lifecycle, binding.fragmentHolder)
|
||||
WifiDoubleLock.ActivityListener(this)
|
||||
}
|
||||
|
||||
override fun onNavigationItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.net.Routing.Companion.IPTABLES
|
||||
import be.mygod.vpnhotspot.net.monitor.IpMonitor
|
||||
import be.mygod.vpnhotspot.net.monitor.UpstreamMonitor
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiDoubleLock
|
||||
import be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat
|
||||
import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore
|
||||
import be.mygod.vpnhotspot.util.RootSession
|
||||
@@ -26,6 +27,7 @@ import java.net.SocketException
|
||||
|
||||
class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
WifiDoubleLock.mode = WifiDoubleLock.mode // handle complicated default value and possible system upgrades
|
||||
preferenceManager.preferenceDataStore = SharedPreferenceDataStore(app.pref)
|
||||
RoutingManager.masqueradeMode = RoutingManager.masqueradeMode // flush default value
|
||||
addPreferencesFromResource(R.xml.pref_settings)
|
||||
|
||||
@@ -4,7 +4,15 @@ import android.annotation.SuppressLint
|
||||
import android.content.SharedPreferences
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.PowerManager
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.BuildCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
|
||||
/**
|
||||
@@ -13,8 +21,12 @@ import be.mygod.vpnhotspot.App.Companion.app
|
||||
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
|
||||
var mode: Mode
|
||||
@Suppress("DEPRECATION")
|
||||
get() = Mode.valueOf(app.pref.getString(KEY, Mode.Full.toString()) ?: "").let {
|
||||
if (it == Mode.Full && BuildCompat.isAtLeastQ()) Mode.None else it
|
||||
}
|
||||
set(value) = app.pref.edit { putString(KEY, value.toString()) }
|
||||
private val service by lazy { app.getSystemService<PowerManager>()!! }
|
||||
|
||||
private var holders = mutableSetOf<Any>()
|
||||
@@ -23,7 +35,7 @@ class WifiDoubleLock(lockType: Int) : AutoCloseable {
|
||||
fun acquire(holder: Any) = synchronized(this) {
|
||||
if (holders.isEmpty()) {
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
val lockType = lockType
|
||||
val lockType = mode.lockType
|
||||
if (lockType != null) lock = WifiDoubleLock(lockType)
|
||||
}
|
||||
check(holders.add(holder))
|
||||
@@ -40,14 +52,45 @@ class WifiDoubleLock(lockType: Int) : AutoCloseable {
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == KEY) synchronized(this) {
|
||||
lock?.close()
|
||||
val lockType = lockType
|
||||
val lockType = mode.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)
|
||||
enum class Mode(val lockType: Int? = null, val keepScreenOn: Boolean = false) {
|
||||
None,
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("This constant was deprecated in API level Q.\n" +
|
||||
"This API is non-functional and will have no impact.")
|
||||
Full(WifiManager.WIFI_MODE_FULL),
|
||||
HighPerf(WifiManager.WIFI_MODE_FULL_HIGH_PERF),
|
||||
@RequiresApi(29)
|
||||
LowLatency(WifiManager.WIFI_MODE_FULL_LOW_LATENCY, true),
|
||||
}
|
||||
|
||||
class ActivityListener(val activity: ComponentActivity) :
|
||||
LifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private var keepScreenOn: Boolean = false
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
if (value) activity.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
else activity.window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
|
||||
init {
|
||||
activity.lifecycle.addObserver(this)
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
keepScreenOn = mode.keepScreenOn
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == KEY) keepScreenOn = mode.keepScreenOn
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
||||
fun shutdown() = app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
private val wifi = app.wifi.createWifiLock(lockType, "vpnhotspot:wifi").apply { acquire() }
|
||||
|
||||
13
mobile/src/main/res/values-v29/arrays.xml
Normal file
13
mobile/src/main/res/values-v29/arrays.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="settings_service_wifi_lock">
|
||||
<item>@string/settings_service_wifi_lock_none</item>
|
||||
<item>@string/settings_service_wifi_lock_high_perf_v29</item>
|
||||
<item>@string/settings_service_wifi_lock_low_latency</item>
|
||||
</string-array>
|
||||
<string-array name="settings_service_wifi_lock_values">
|
||||
<item>None</item>
|
||||
<item>HighPerf</item>
|
||||
<item>LowLatency</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
@@ -101,6 +101,8 @@
|
||||
<string name="settings_service_wifi_lock_none">System default</string>
|
||||
<string name="settings_service_wifi_lock_full">On</string>
|
||||
<string name="settings_service_wifi_lock_high_perf">High Performance Mode</string>
|
||||
<string name="settings_service_wifi_lock_high_perf_v29">Disable power save</string>
|
||||
<string name="settings_service_wifi_lock_low_latency">Low latency mode</string>
|
||||
<string name="settings_service_ip_monitor">Network status monitor mode</string>
|
||||
<string name="settings_service_ip_monitor_monitor">Netlink monitor</string>
|
||||
<string name="settings_service_ip_monitor_monitor_root">Netlink monitor with root</string>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
app:icon="@drawable/ic_device_wifi_lock"
|
||||
app:entries="@array/settings_service_wifi_lock"
|
||||
app:entryValues="@array/settings_service_wifi_lock_values"
|
||||
app:defaultValue="Full"
|
||||
app:title="@string/settings_service_wifi_lock"
|
||||
app:useSimpleSummaryProvider="true"/>
|
||||
<SwitchPreference
|
||||
|
||||
Reference in New Issue
Block a user