Merge "[Catalyst] Migrate Wi-Fi switch preference" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
0496fc2de5
@@ -53,6 +53,7 @@
|
|||||||
android:key="main_toggle_wifi"
|
android:key="main_toggle_wifi"
|
||||||
android:title="@string/wifi"
|
android:title="@string/wifi"
|
||||||
settings:keywords="@string/keywords_wifi"
|
settings:keywords="@string/keywords_wifi"
|
||||||
|
settings:restrictedSwitchSummary="@string/not_allowed_by_ent"
|
||||||
settings:allowDividerAbove="true"/>
|
settings:allowDividerAbove="true"/>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
@@ -20,6 +20,7 @@ import android.os.UserManager
|
|||||||
import com.android.settings.PreferenceRestrictionMixin
|
import com.android.settings.PreferenceRestrictionMixin
|
||||||
import com.android.settings.R
|
import com.android.settings.R
|
||||||
import com.android.settings.flags.Flags
|
import com.android.settings.flags.Flags
|
||||||
|
import com.android.settings.wifi.WifiSwitchPreference
|
||||||
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
|
||||||
import com.android.settingslib.metadata.ProvidePreferenceScreen
|
import com.android.settingslib.metadata.ProvidePreferenceScreen
|
||||||
import com.android.settingslib.metadata.preferenceHierarchy
|
import com.android.settingslib.metadata.preferenceHierarchy
|
||||||
@@ -54,7 +55,9 @@ class NetworkProviderScreen :
|
|||||||
|
|
||||||
override fun fragmentClass() = NetworkProviderSettings::class.java
|
override fun fragmentClass() = NetworkProviderSettings::class.java
|
||||||
|
|
||||||
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
|
override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
|
||||||
|
+WifiSwitchPreference()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KEY = "internet_settings"
|
const val KEY = "internet_settings"
|
||||||
|
@@ -429,6 +429,10 @@ public class NetworkProviderSettings extends RestrictedDashboardFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addWifiSwitchPreferenceController() {
|
private void addWifiSwitchPreferenceController() {
|
||||||
|
if (isCatalystEnabled()) {
|
||||||
|
Log.i(TAG, "WifiSwitchPreferenceController bypassed since Catalyst is enabled!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!hasWifiManager()) return;
|
if (!hasWifiManager()) return;
|
||||||
if (mWifiSwitchPreferenceController == null) {
|
if (mWifiSwitchPreferenceController == null) {
|
||||||
mWifiSwitchPreferenceController =
|
mWifiSwitchPreferenceController =
|
||||||
|
@@ -38,6 +38,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||||||
/**
|
/**
|
||||||
* This controller helps to manage the state of wifi switch preference.
|
* This controller helps to manage the state of wifi switch preference.
|
||||||
*/
|
*/
|
||||||
|
// LINT.IfChange
|
||||||
public class WifiSwitchPreferenceController extends AbstractPreferenceController implements
|
public class WifiSwitchPreferenceController extends AbstractPreferenceController implements
|
||||||
LifecycleObserver {
|
LifecycleObserver {
|
||||||
|
|
||||||
@@ -125,3 +126,4 @@ public class WifiSwitchPreferenceController extends AbstractPreferenceController
|
|||||||
return wifiManager.isWifiEnabled();
|
return wifiManager.isWifiEnabled();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// LINT.ThenChange(WifiSwitchPreference.kt)
|
||||||
|
144
src/com/android/settings/wifi/WifiSwitchPreference.kt
Normal file
144
src/com/android/settings/wifi/WifiSwitchPreference.kt
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.wifi
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.wifi.WifiManager
|
||||||
|
import android.os.UserManager
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import com.android.settings.PreferenceRestrictionMixin
|
||||||
|
import com.android.settings.R
|
||||||
|
import com.android.settings.network.SatelliteRepository
|
||||||
|
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
|
||||||
|
import com.android.settings.widget.GenericSwitchController
|
||||||
|
import com.android.settingslib.RestrictedSwitchPreference
|
||||||
|
import com.android.settingslib.WirelessUtils
|
||||||
|
import com.android.settingslib.datastore.KeyValueStore
|
||||||
|
import com.android.settingslib.datastore.NoOpKeyedObservable
|
||||||
|
import com.android.settingslib.metadata.*
|
||||||
|
import com.android.settingslib.preference.SwitchPreferenceBinding
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
// LINT.IfChange
|
||||||
|
class WifiSwitchPreference :
|
||||||
|
SwitchPreference(KEY, R.string.wifi),
|
||||||
|
SwitchPreferenceBinding,
|
||||||
|
PreferenceLifecycleProvider,
|
||||||
|
PreferenceRestrictionMixin {
|
||||||
|
|
||||||
|
// TODO(b/372733639) Remove WifiEnabler and migrate to catalyst
|
||||||
|
private var wifiEnabler: WifiEnabler? = null
|
||||||
|
|
||||||
|
override val keywords: Int
|
||||||
|
get() = R.string.keywords_wifi
|
||||||
|
|
||||||
|
override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context)
|
||||||
|
|
||||||
|
override val restrictionKeys
|
||||||
|
get() = arrayOf(UserManager.DISALLOW_CHANGE_WIFI_STATE)
|
||||||
|
|
||||||
|
override val useAdminDisabledSummary: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
|
||||||
|
ReadWritePermit.ALLOW
|
||||||
|
|
||||||
|
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
|
||||||
|
when {
|
||||||
|
isRadioAllowed(context, value) && !isSatelliteOn(context) -> ReadWritePermit.ALLOW
|
||||||
|
else -> ReadWritePermit.DISALLOW
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun storage(context: Context): KeyValueStore = WifiSwitchStore(context)
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private class WifiSwitchStore(private val context: Context) :
|
||||||
|
NoOpKeyedObservable<String>(),
|
||||||
|
KeyValueStore {
|
||||||
|
|
||||||
|
override fun contains(key: String) =
|
||||||
|
key == KEY && context.getSystemService(WifiManager::class.java) != null
|
||||||
|
|
||||||
|
override fun <T : Any> getValue(key: String, valueType: Class<T>): T? =
|
||||||
|
context.getSystemService(WifiManager::class.java)?.isWifiEnabled as T?
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
|
||||||
|
if (value is Boolean) {
|
||||||
|
context.getSystemService(WifiManager::class.java)?.isWifiEnabled = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(context: PreferenceLifecycleContext) {
|
||||||
|
context.requirePreference<RestrictedSwitchPreference>(KEY).let {
|
||||||
|
it.onPreferenceChangeListener =
|
||||||
|
Preference.OnPreferenceChangeListener { _: Preference, newValue: Any ->
|
||||||
|
if (!isRadioAllowed(context, newValue as Boolean?)) {
|
||||||
|
Log.w(TAG, "Don't set APM, AIRPLANE_MODE_RADIOS is not allowed")
|
||||||
|
return@OnPreferenceChangeListener false
|
||||||
|
}
|
||||||
|
if (isSatelliteOn(context)) {
|
||||||
|
Log.w(TAG, "Don't set APM, the satellite is on")
|
||||||
|
return@OnPreferenceChangeListener false
|
||||||
|
}
|
||||||
|
return@OnPreferenceChangeListener true
|
||||||
|
}
|
||||||
|
val widget = GenericSwitchController(it)
|
||||||
|
wifiEnabler = WifiEnabler(context, widget, featureFactory.metricsFeatureProvider)
|
||||||
|
Log.i(TAG, "Create WifiEnabler:$wifiEnabler")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume(context: PreferenceLifecycleContext) {
|
||||||
|
wifiEnabler?.resume(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause(context: PreferenceLifecycleContext) {
|
||||||
|
wifiEnabler?.pause()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy(context: PreferenceLifecycleContext) {
|
||||||
|
wifiEnabler?.teardownSwitchController()
|
||||||
|
wifiEnabler = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isRadioAllowed(context: Context, newValue: Boolean?): Boolean {
|
||||||
|
newValue?.let { if (!it) return true } ?: return false
|
||||||
|
return WirelessUtils.isRadioAllowed(context, Settings.Global.RADIO_WIFI)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isSatelliteOn(context: Context): Boolean {
|
||||||
|
try {
|
||||||
|
return SatelliteRepository(context)
|
||||||
|
.requestIsSessionStarted(Executors.newSingleThreadExecutor())
|
||||||
|
.get(2000, TimeUnit.MILLISECONDS)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Error to get satellite status : $e")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "WifiSwitchPreference"
|
||||||
|
const val KEY = "main_toggle_wifi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// LINT.ThenChange(WifiSwitchPreferenceController.java)
|
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.wifi
|
||||||
|
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.net.wifi.WifiManager
|
||||||
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import com.android.settingslib.preference.createAndBindWidget
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import org.mockito.kotlin.stub
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class WifiSwitchPreferenceTest {
|
||||||
|
|
||||||
|
private var mockWifiManager = mock<WifiManager>()
|
||||||
|
|
||||||
|
private val context =
|
||||||
|
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
|
||||||
|
override fun getSystemService(name: String): Any? =
|
||||||
|
when (name) {
|
||||||
|
getSystemServiceName(WifiManager::class.java) -> mockWifiManager
|
||||||
|
else -> super.getSystemService(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val wifiSwitchPreference = WifiSwitchPreference()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getValue_defaultOn_returnOn() {
|
||||||
|
mockWifiManager.stub { on { isWifiEnabled } doReturn true }
|
||||||
|
|
||||||
|
val getValue = wifiSwitchPreference
|
||||||
|
.storage(context)
|
||||||
|
.getValue(WifiSwitchPreference.KEY, Boolean::class.javaObjectType)
|
||||||
|
|
||||||
|
assertThat(getValue).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getValue_defaultOff_returnOff() {
|
||||||
|
mockWifiManager.stub { on { isWifiEnabled } doReturn false }
|
||||||
|
|
||||||
|
val getValue = wifiSwitchPreference
|
||||||
|
.storage(context)
|
||||||
|
.getValue(WifiSwitchPreference.KEY, Boolean::class.javaObjectType)
|
||||||
|
|
||||||
|
assertThat(getValue).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun performClick_defaultOn_checkedIsFalse() {
|
||||||
|
mockWifiManager.stub { on { isWifiEnabled } doReturn true }
|
||||||
|
|
||||||
|
val preference = getSwitchPreference().apply { performClick() }
|
||||||
|
|
||||||
|
assertThat(preference.isChecked).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun performClick_defaultOff_checkedIsTrue() {
|
||||||
|
mockWifiManager.stub { on { isWifiEnabled } doReturn false }
|
||||||
|
|
||||||
|
val preference = getSwitchPreference().apply { performClick() }
|
||||||
|
|
||||||
|
assertThat(preference.isChecked).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSwitchPreference(): SwitchPreferenceCompat =
|
||||||
|
wifiSwitchPreference.createAndBindWidget(context)
|
||||||
|
}
|
Reference in New Issue
Block a user