From a29a6ceab49a3cf0e0b96b7972785a3c42f4792d Mon Sep 17 00:00:00 2001 From: Almaz Mingaleev Date: Thu, 11 Mar 2021 15:26:31 +0000 Subject: [PATCH 01/28] Fix imports in LocationTimeZoneDetectionPreferenceController. Capabilities are extracted to separate class to reuse them in time API. Bug: 172891783 Test: m -j30 RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.datetime.LocationTimeZoneDetectionPreferenceControllerTest" Change-Id: If7351c4f022c69262ddffd26efacd449dc7238c5 --- .../LocationTimeZoneDetectionPreferenceController.java | 8 ++++---- ...ocationTimeZoneDetectionPreferenceControllerTest.java | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java index 1a45640c1df..0b0fa27f62c 100644 --- a/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java +++ b/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceController.java @@ -15,10 +15,10 @@ */ package com.android.settings.datetime; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_ALLOWED; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED; +import static android.app.time.Capabilities.CAPABILITY_NOT_ALLOWED; +import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE; +import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED; +import static android.app.time.Capabilities.CAPABILITY_POSSESSED; import android.app.time.TimeManager; import android.app.time.TimeZoneCapabilities; diff --git a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java index ae200b9a709..68b2990a03b 100644 --- a/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/LocationTimeZoneDetectionPreferenceControllerTest.java @@ -16,9 +16,9 @@ package com.android.settings.datetime; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_APPLICABLE; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_NOT_SUPPORTED; -import static android.app.time.TimeZoneCapabilities.CAPABILITY_POSSESSED; +import static android.app.time.Capabilities.CAPABILITY_NOT_APPLICABLE; +import static android.app.time.Capabilities.CAPABILITY_NOT_SUPPORTED; +import static android.app.time.Capabilities.CAPABILITY_POSSESSED; import static com.google.common.truth.Truth.assertThat; @@ -26,6 +26,7 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.time.Capabilities; import android.app.time.TimeManager; import android.app.time.TimeZoneCapabilities; import android.app.time.TimeZoneCapabilitiesAndConfig; @@ -142,7 +143,7 @@ public class LocationTimeZoneDetectionPreferenceControllerTest { } private static TimeZoneCapabilities createTimeZoneCapabilities( - @TimeZoneCapabilities.CapabilityState int geoDetectionCapability) { + @Capabilities.CapabilityState int geoDetectionCapability) { UserHandle arbitraryUserHandle = UserHandle.of(123); return new TimeZoneCapabilities.Builder(arbitraryUserHandle) .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED) From 68b0057f66f2253afeebe93ef69492a532ee7fa7 Mon Sep 17 00:00:00 2001 From: Weng Su Date: Fri, 12 Mar 2021 22:33:46 +0800 Subject: [PATCH 02/28] Smart Router settings UI changes - Remove "AP band" preference - Add "Maximize Compatibility" switch preference - Use bridged mode API for new devices (after P21) - Screenshot: https://screenshot.googleplex.com/84X9Av8gVj3idjB Bug: 168052744 Test: manual test atest WifiTetherMaximizeCompatibilityPreferenceControllerTest make RunSettingsRoboTests ROBOTEST_FILTER=WifiTetherSettingsTest Change-Id: Ib74156c0fa6eccdd13239854047b1fb4e49a293c --- res/values/strings.xml | 4 + res/xml/wifi_tether_settings.xml | 9 +- ...mizeCompatibilityPreferenceController.java | 124 ++++++++++ .../wifi/tether/WifiTetherSettings.java | 47 ++-- .../wifi/tether/WifiTetherSettingsTest.java | 4 +- ...CompatibilityPreferenceControllerTest.java | 217 ++++++++++++++++++ 6 files changed, 371 insertions(+), 34 deletions(-) create mode 100644 src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java create mode 100644 tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 6dfae4b4cdc..a6e618ab57f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2416,6 +2416,10 @@ Turn off hotspot automatically When no devices are connected + + Maximize compatibility + + This may reduce speed for devices connected to this hotspot and use more power Turning hotspot on\u2026 diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml index 34d8032cbb9..8648cff0f43 100644 --- a/res/xml/wifi_tether_settings.xml +++ b/res/xml/wifi_tether_settings.xml @@ -37,12 +37,13 @@ android:persistent="false" android:title="@string/wifi_hotspot_password_title"/> - - + + diff --git a/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java new file mode 100644 index 00000000000..bc87d5cc5d0 --- /dev/null +++ b/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2021 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.tether; + +import android.content.Context; +import android.net.wifi.SoftApConfiguration; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.SwitchPreference; + +/** + * This controller helps to manage the state of maximize compatibility switch preference. + */ +public class WifiTetherMaximizeCompatibilityPreferenceController extends + WifiTetherBasePreferenceController { + + private static final String TAG = "WifiTetherMaximizeCompatibilityPref"; + public static final String PREF_KEY = "wifi_tether_maximize_compatibility"; + + private boolean mIsChecked; + + public WifiTetherMaximizeCompatibilityPreferenceController(Context context, + WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) { + super(context, listener); + mIsChecked = isMaximizeCompatibilityEnabled(); + } + + @Override + public String getPreferenceKey() { + return PREF_KEY; + } + + @Override + public void updateDisplay() { + if (mPreference == null) { + return; + } + mPreference.setEnabled(is5GhzBandSupported()); + ((SwitchPreference) mPreference).setChecked(mIsChecked); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mIsChecked = (Boolean) newValue; + if (mListener != null) { + mListener.onTetherConfigUpdated(this); + } + return true; + } + + private boolean is5GhzBandSupported() { + if (mWifiManager == null) { + return false; + } + if (!mWifiManager.is5GHzBandSupported() || mWifiManager.getCountryCode() == null) { + return false; + } + return true; + } + + @VisibleForTesting + boolean isMaximizeCompatibilityEnabled() { + if (mWifiManager == null) { + return false; + } + final SoftApConfiguration config = mWifiManager.getSoftApConfiguration(); + if (config == null) { + return false; + } + if (mWifiManager.isBridgedApConcurrencySupported()) { + final boolean isEnabled = config.isBridgedModeOpportunisticShutdownEnabled(); + Log.d(TAG, "isBridgedModeOpportunisticShutdownEnabled:" + isEnabled); + return isEnabled; + } + + // If the BridgedAp Concurrency is not supported in early Pixel devices (e.g. Pixel 2~5), + // show toggle on if the band includes SoftApConfiguration.BAND_5GHZ. + final int band = config.getBand(); + Log.d(TAG, "getBand:" + band); + return (band & SoftApConfiguration.BAND_5GHZ) > 0; + } + + /** + * Setup the Maximize Compatibility setting to the SoftAp Configuration + * + * @param builder The builder to build the SoftApConfiguration. + */ + public void setupMaximizeCompatibility(SoftApConfiguration.Builder builder) { + if (builder == null) { + return; + } + final boolean enabled = mIsChecked; + if (mWifiManager.isBridgedApConcurrencySupported()) { + int[] bands = { + SoftApConfiguration.BAND_2GHZ, + SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ}; + builder.setBands(bands); + Log.d(TAG, "setBridgedModeOpportunisticShutdownEnabled:" + enabled); + builder.setBridgedModeOpportunisticShutdownEnabled(enabled); + } else { + int band = enabled + ? SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ + : SoftApConfiguration.BAND_2GHZ; + Log.d(TAG, "setBand:" + band); + builder.setBand(band); + } + } +} diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java index 939f0778943..e34255035e5 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java +++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java @@ -54,8 +54,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment private static final String TAG = "WifiTetherSettings"; private static final IntentFilter TETHER_STATE_CHANGE_FILTER; private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen"; - private static final int EXPANDED_CHILD_COUNT_WITH_SECURITY_NON = 3; - private static final int EXPANDED_CHILD_COUNT_DEFAULT = 4; + private static final int EXPANDED_CHILD_COUNT_DEFAULT = 3; @VisibleForTesting static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name"; @@ -64,13 +63,14 @@ public class WifiTetherSettings extends RestrictedDashboardFragment @VisibleForTesting static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off"; @VisibleForTesting - static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band"; + static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY = + WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY; private WifiTetherSwitchBarController mSwitchBarController; private WifiTetherSSIDPreferenceController mSSIDPreferenceController; private WifiTetherPasswordPreferenceController mPasswordPreferenceController; - private WifiTetherApBandPreferenceController mApBandPreferenceController; private WifiTetherSecurityPreferenceController mSecurityPreferenceController; + private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController; private WifiManager mWifiManager; private boolean mRestartWifiApAfterConfigChange; @@ -116,7 +116,8 @@ public class WifiTetherSettings extends RestrictedDashboardFragment mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class); mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class); mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class); - mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class); + mMaxCompatibilityPrefController = + use(WifiTetherMaximizeCompatibilityPreferenceController.class); } @Override @@ -180,10 +181,9 @@ public class WifiTetherSettings extends RestrictedDashboardFragment controllers.add(new WifiTetherSSIDPreferenceController(context, listener)); controllers.add(new WifiTetherSecurityPreferenceController(context, listener)); controllers.add(new WifiTetherPasswordPreferenceController(context, listener)); - controllers.add(new WifiTetherApBandPreferenceController(context, listener)); controllers.add( new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF)); - + controllers.add(new WifiTetherMaximizeCompatibilityPreferenceController(context, listener)); return controllers; } @@ -219,7 +219,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment mPasswordPreferenceController.getPasswordValidated(securityType), securityType); } - configBuilder.setBand(mApBandPreferenceController.getBandIndex()); + mMaxCompatibilityPrefController.setupMaximizeCompatibility(configBuilder); return configBuilder.build(); } @@ -229,14 +229,10 @@ public class WifiTetherSettings extends RestrictedDashboardFragment } private void updateDisplayWithNewConfig() { - use(WifiTetherSSIDPreferenceController.class) - .updateDisplay(); - use(WifiTetherSecurityPreferenceController.class) - .updateDisplay(); - use(WifiTetherPasswordPreferenceController.class) - .updateDisplay(); - use(WifiTetherApBandPreferenceController.class) - .updateDisplay(); + use(WifiTetherSSIDPreferenceController.class).updateDisplay(); + use(WifiTetherSecurityPreferenceController.class).updateDisplay(); + use(WifiTetherPasswordPreferenceController.class).updateDisplay(); + use(WifiTetherMaximizeCompatibilityPreferenceController.class).updateDisplay(); } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = @@ -250,7 +246,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment keys.add(KEY_WIFI_TETHER_NETWORK_NAME); keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD); keys.add(KEY_WIFI_TETHER_AUTO_OFF); - keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND); + keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY); } // Remove duplicate @@ -294,22 +290,17 @@ public class WifiTetherSettings extends RestrictedDashboardFragment private void reConfigInitialExpandedChildCount() { final PreferenceGroup screen = getPreferenceScreen(); - if (mSecurityPreferenceController.getSecurityType() - == SoftApConfiguration.SECURITY_TYPE_OPEN) { - screen.setInitialExpandedChildrenCount(EXPANDED_CHILD_COUNT_WITH_SECURITY_NON); - return; + if (screen != null) { + screen.setInitialExpandedChildrenCount(getInitialExpandedChildCount()); } - screen.setInitialExpandedChildrenCount(EXPANDED_CHILD_COUNT_DEFAULT); } @Override public int getInitialExpandedChildCount() { - if (mSecurityPreferenceController == null) { - return EXPANDED_CHILD_COUNT_DEFAULT; + if (mSecurityPreferenceController != null && mSecurityPreferenceController.getSecurityType() + == SoftApConfiguration.SECURITY_TYPE_OPEN) { + return (EXPANDED_CHILD_COUNT_DEFAULT - 1); } - - return (mSecurityPreferenceController.getSecurityType() - == SoftApConfiguration.SECURITY_TYPE_OPEN) - ? EXPANDED_CHILD_COUNT_WITH_SECURITY_NON : EXPANDED_CHILD_COUNT_DEFAULT; + return EXPANDED_CHILD_COUNT_DEFAULT; } } diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java index a2412961919..2ecc7d26d54 100644 --- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java +++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java @@ -101,7 +101,7 @@ public class WifiTetherSettingsTest { assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME); assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD); assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF); - assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND); + assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY); } @Test @@ -115,7 +115,7 @@ public class WifiTetherSettingsTest { assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME); assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD); assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF); - assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND); + assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY); } @Test diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java new file mode 100644 index 00000000000..a2b99bf614a --- /dev/null +++ b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2021 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.tether; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.net.wifi.SoftApConfiguration; +import android.net.wifi.WifiManager; +import android.os.Looper; + +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +@RunWith(AndroidJUnit4.class) +public class WifiTetherMaximizeCompatibilityPreferenceControllerTest { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock + private WifiManager mWifiManager; + @Mock + private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener; + + private WifiTetherMaximizeCompatibilityPreferenceController mController; + private SwitchPreference mPreference; + private SoftApConfiguration mConfig; + + @Before + public void setUp() { + final Context context = spy(ApplicationProvider.getApplicationContext()); + mConfig = new SoftApConfiguration.Builder() + .setSsid("test_Ssid") + .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN) + .setBridgedModeOpportunisticShutdownEnabled(true) + .build(); + doReturn(mWifiManager).when(context).getSystemService(Context.WIFI_SERVICE); + doReturn(true).when(mWifiManager).isBridgedApConcurrencySupported(); + doReturn(mConfig).when(mWifiManager).getSoftApConfiguration(); + + mController = new WifiTetherMaximizeCompatibilityPreferenceController(context, mListener); + if (Looper.myLooper() == null) { + Looper.prepare(); + } + final PreferenceManager preferenceManager = new PreferenceManager(context); + final PreferenceScreen screen = preferenceManager.createPreferenceScreen(context); + mPreference = new SwitchPreference(context); + mPreference.setKey(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY); + screen.addPreference(mPreference); + mController.displayPreference(screen); + } + + @Test + public void getPreferenceKey_shouldBeCorrect() { + assertThat(mController.getPreferenceKey()) + .isEqualTo(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY); + } + + @Test + public void updateDisplay_notSupport5GHzBand_setPreferenceDisabled() { + doReturn(false).when(mWifiManager).is5GHzBandSupported(); + + mController.updateDisplay(); + + assertThat(mPreference.isEnabled()).isEqualTo(false); + } + + @Test + public void updateDisplay_getNullCountryCode_setPreferenceDisabled() { + doReturn(null).when(mWifiManager).getCountryCode(); + + mController.updateDisplay(); + + assertThat(mPreference.isEnabled()).isEqualTo(false); + } + + @Test + public void updateDisplay_supported5GHzBandAndCountryCodeIsNotNull_setPreferenceEnabled() { + doReturn(true).when(mWifiManager).is5GHzBandSupported(); + doReturn("US").when(mWifiManager).getCountryCode(); + + mController.updateDisplay(); + + assertThat(mPreference.isEnabled()).isEqualTo(true); + } + + @Test + public void onPreferenceChange_callbackOnTetherConfigUpdated() { + mController.onPreferenceChange(mPreference, true); + verify(mListener).onTetherConfigUpdated(any()); + } + + @Test + public void isMaximizeCompatibilityEnabled_concurrencySupportedAndEnabled_returnTure() { + // The preconditions are ready in setup(). + + assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true); + } + + @Test + public void isMaximizeCompatibilityEnabled_concurrencySupportedAndDisabled_returnFalse() { + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBridgedModeOpportunisticShutdownEnabled(false) + .build(); + doReturn(config).when(mWifiManager).getSoftApConfiguration(); + + assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false); + } + + @Test + public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gOnly_returnFalse() { + doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported(); + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(SoftApConfiguration.BAND_2GHZ) + .build(); + doReturn(config).when(mWifiManager).getSoftApConfiguration(); + + assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false); + } + + @Test + public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand5gOnly_returnTrue() { + doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported(); + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(SoftApConfiguration.BAND_5GHZ) + .build(); + doReturn(config).when(mWifiManager).getSoftApConfiguration(); + + assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true); + } + + @Test + public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gAnd5g_returnTrue() { + doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported(); + SoftApConfiguration config = new SoftApConfiguration.Builder() + .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ) + .build(); + doReturn(config).when(mWifiManager).getSoftApConfiguration(); + + assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true); + } + + @Test + public void setupMaximizeCompatibility_concurrencySupportedAndDisabled_setDisabled() { + // The precondition of the concurrency supported is ready in setup(). + mController.onPreferenceChange(mPreference, false); + + SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder(); + mController.setupMaximizeCompatibility(builder); + + assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(false); + } + + @Test + public void setupMaximizeCompatibility_concurrencySupportedAndEnabled_setEnabled() { + // The precondition of the concurrency supported is ready in setup(). + mController.onPreferenceChange(mPreference, true); + + SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder(); + mController.setupMaximizeCompatibility(builder); + + assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(true); + } + + @Test + public void setupMaximizeCompatibility_noConcurrencyAndSetDisabled_setBand2gOnly() { + doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported(); + mController.onPreferenceChange(mPreference, false); + + SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder(); + mController.setupMaximizeCompatibility(builder); + + assertThat(builder.build().getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ); + } + + @Test + public void setupMaximizeCompatibility_noConcurrencyAndSetEnabled_setBand2gAnd5g() { + doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported(); + mController.onPreferenceChange(mPreference, true); + + SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder(); + mController.setupMaximizeCompatibility(builder); + + assertThat(builder.build().getBand()) + .isEqualTo(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ); + } +} From b16da1a9cafebbbb0f33f733a74d8213611e4935 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 17 Mar 2021 17:25:41 +0800 Subject: [PATCH 03/28] Replace the way to access StaticIpConfiguration StaticIpConfiguration is a part of incoming connectivity mainline module. The hidden variable is not accessible for module outside. The caller should use getter and builder to access it. Replace the usage with the formal way. Test: make RunSettingsRoboTests ROBOTEST_FILTER=\ com.android.settings.wifi.WifiConfigControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=\ com.android.settings.wifi.WifiConfigController2Test Change-Id: I2ccd427ba19a4ec7df863c38ee0b34cf0be87fa5 --- .../settings/wifi/WifiConfigController.java | 124 +++++++++------- .../settings/wifi/WifiConfigController2.java | 137 ++++++++++-------- 2 files changed, 146 insertions(+), 115 deletions(-) diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java index 6e96ae2fefa..80866689238 100644 --- a/src/com/android/settings/wifi/WifiConfigController.java +++ b/src/com/android/settings/wifi/WifiConfigController.java @@ -327,9 +327,9 @@ public class WifiConfigController implements TextWatcher, // Display IP address. StaticIpConfiguration staticConfig = config.getIpConfiguration() .getStaticIpConfiguration(); - if (staticConfig != null && staticConfig.ipAddress != null) { + if (staticConfig != null && staticConfig.getIpAddress() != null) { addRow(group, R.string.wifi_ip_address, - staticConfig.ipAddress.getAddress().getHostAddress()); + staticConfig.getIpAddress().getAddress().getHostAddress()); } } else { mIpSettingsSpinner.setSelection(DHCP); @@ -915,67 +915,81 @@ public class WifiConfigController implements TextWatcher, if (inetAddr == null || inetAddr.equals(Inet4Address.ANY)) { return R.string.wifi_ip_settings_invalid_ip_address; } - - int networkPrefixLength = -1; + // Copy all fields into the builder first and set desired value later with builder. + final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder() + .setDnsServers(staticIpConfiguration.getDnsServers()) + .setDomains(staticIpConfiguration.getDomains()) + .setGateway(staticIpConfiguration.getGateway()) + .setIpAddress(staticIpConfiguration.getIpAddress()); try { - networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString()); - if (networkPrefixLength < 0 || networkPrefixLength > 32) { - return R.string.wifi_ip_settings_invalid_network_prefix_length; - } - staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength); - } catch (NumberFormatException e) { - // Set the hint as default after user types in ip address - mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString( - R.string.wifi_network_prefix_length_hint)); - } catch (IllegalArgumentException e) { - return R.string.wifi_ip_settings_invalid_ip_address; - } - - String gateway = mGatewayView.getText().toString(); - if (TextUtils.isEmpty(gateway)) { + int networkPrefixLength = -1; try { - //Extract a default gateway from IP address - InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength); - byte[] addr = netPart.getAddress(); - addr[addr.length - 1] = 1; - mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress()); - } catch (RuntimeException ee) { - } catch (java.net.UnknownHostException u) { + networkPrefixLength = Integer.parseInt( + mNetworkPrefixLengthView.getText().toString()); + if (networkPrefixLength < 0 || networkPrefixLength > 32) { + return R.string.wifi_ip_settings_invalid_network_prefix_length; + } + staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength)); + } catch (NumberFormatException e) { + // Set the hint as default after user types in ip address + mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString( + R.string.wifi_network_prefix_length_hint)); + } catch (IllegalArgumentException e) { + return R.string.wifi_ip_settings_invalid_ip_address; } - } else { - InetAddress gatewayAddr = getIPv4Address(gateway); - if (gatewayAddr == null) { - return R.string.wifi_ip_settings_invalid_gateway; - } - if (gatewayAddr.isMulticastAddress()) { - return R.string.wifi_ip_settings_invalid_gateway; - } - staticIpConfiguration.gateway = gatewayAddr; - } - String dns = mDns1View.getText().toString(); - InetAddress dnsAddr = null; - - if (TextUtils.isEmpty(dns)) { - //If everything else is valid, provide hint as a default option - mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint)); - } else { - dnsAddr = getIPv4Address(dns); - if (dnsAddr == null) { - return R.string.wifi_ip_settings_invalid_dns; + String gateway = mGatewayView.getText().toString(); + if (TextUtils.isEmpty(gateway)) { + try { + //Extract a default gateway from IP address + InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength); + byte[] addr = netPart.getAddress(); + addr[addr.length - 1] = 1; + mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress()); + } catch (RuntimeException ee) { + } catch (java.net.UnknownHostException u) { + } + } else { + InetAddress gatewayAddr = getIPv4Address(gateway); + if (gatewayAddr == null) { + return R.string.wifi_ip_settings_invalid_gateway; + } + if (gatewayAddr.isMulticastAddress()) { + return R.string.wifi_ip_settings_invalid_gateway; + } + staticIPBuilder.setGateway(gatewayAddr); } - staticIpConfiguration.dnsServers.add(dnsAddr); - } - if (mDns2View.length() > 0) { - dns = mDns2View.getText().toString(); - dnsAddr = getIPv4Address(dns); - if (dnsAddr == null) { - return R.string.wifi_ip_settings_invalid_dns; + String dns = mDns1View.getText().toString(); + InetAddress dnsAddr = null; + final ArrayList dnsServers = new ArrayList<>(); + + if (TextUtils.isEmpty(dns)) { + //If everything else is valid, provide hint as a default option + mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint)); + } else { + dnsAddr = getIPv4Address(dns); + if (dnsAddr == null) { + return R.string.wifi_ip_settings_invalid_dns; + } + dnsServers.add(dnsAddr); } - staticIpConfiguration.dnsServers.add(dnsAddr); + + if (mDns2View.length() > 0) { + dns = mDns2View.getText().toString(); + dnsAddr = getIPv4Address(dns); + if (dnsAddr == null) { + return R.string.wifi_ip_settings_invalid_dns; + } + dnsServers.add(dnsAddr); + } + staticIPBuilder.setDnsServers(dnsServers); + return 0; + } finally { + // Caller of this method may rely on staticIpConfiguration, so build the final result + // at the end of the method. + staticIpConfiguration = staticIPBuilder.build(); } - return 0; } private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) { diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java index 467f32e60fe..0ba95432df8 100644 --- a/src/com/android/settings/wifi/WifiConfigController2.java +++ b/src/com/android/settings/wifi/WifiConfigController2.java @@ -317,9 +317,9 @@ public class WifiConfigController2 implements TextWatcher, // Display IP address. StaticIpConfiguration staticConfig = config.getIpConfiguration() .getStaticIpConfiguration(); - if (staticConfig != null && staticConfig.ipAddress != null) { + if (staticConfig != null && staticConfig.getIpAddress() != null) { addRow(group, R.string.wifi_ip_address, - staticConfig.ipAddress.getAddress().getHostAddress()); + staticConfig.getIpAddress().getAddress().getHostAddress()); } } else { mIpSettingsSpinner.setSelection(DHCP); @@ -898,66 +898,83 @@ public class WifiConfigController2 implements TextWatcher, return R.string.wifi_ip_settings_invalid_ip_address; } - int networkPrefixLength = -1; + // Copy all fields into the builder first and set desired value later with builder. + final StaticIpConfiguration.Builder staticIPBuilder = new StaticIpConfiguration.Builder() + .setDnsServers(staticIpConfiguration.getDnsServers()) + .setDomains(staticIpConfiguration.getDomains()) + .setGateway(staticIpConfiguration.getGateway()) + .setIpAddress(staticIpConfiguration.getIpAddress()); try { - networkPrefixLength = Integer.parseInt(mNetworkPrefixLengthView.getText().toString()); - if (networkPrefixLength < 0 || networkPrefixLength > 32) { - return R.string.wifi_ip_settings_invalid_network_prefix_length; - } - staticIpConfiguration.ipAddress = new LinkAddress(inetAddr, networkPrefixLength); - } catch (NumberFormatException e) { - // Set the hint as default after user types in ip address - mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString( - R.string.wifi_network_prefix_length_hint)); - } catch (IllegalArgumentException e) { - return R.string.wifi_ip_settings_invalid_ip_address; - } - - String gateway = mGatewayView.getText().toString(); - if (TextUtils.isEmpty(gateway)) { + int networkPrefixLength = -1; try { - //Extract a default gateway from IP address - InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength); - byte[] addr = netPart.getAddress(); - addr[addr.length - 1] = 1; - mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress()); - } catch (RuntimeException ee) { - } catch (java.net.UnknownHostException u) { + networkPrefixLength = + Integer.parseInt(mNetworkPrefixLengthView.getText().toString()); + if (networkPrefixLength < 0 || networkPrefixLength > 32) { + return R.string.wifi_ip_settings_invalid_network_prefix_length; + } + staticIPBuilder.setIpAddress(new LinkAddress(inetAddr, networkPrefixLength)); + } catch (NumberFormatException e) { + // Set the hint as default after user types in ip address + mNetworkPrefixLengthView.setText(mConfigUi.getContext().getString( + R.string.wifi_network_prefix_length_hint)); + } catch (IllegalArgumentException e) { + return R.string.wifi_ip_settings_invalid_ip_address; } - } else { - InetAddress gatewayAddr = getIPv4Address(gateway); - if (gatewayAddr == null) { - return R.string.wifi_ip_settings_invalid_gateway; - } - if (gatewayAddr.isMulticastAddress()) { - return R.string.wifi_ip_settings_invalid_gateway; - } - staticIpConfiguration.gateway = gatewayAddr; - } - String dns = mDns1View.getText().toString(); - InetAddress dnsAddr = null; - - if (TextUtils.isEmpty(dns)) { - //If everything else is valid, provide hint as a default option - mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint)); - } else { - dnsAddr = getIPv4Address(dns); - if (dnsAddr == null) { - return R.string.wifi_ip_settings_invalid_dns; + String gateway = mGatewayView.getText().toString(); + if (TextUtils.isEmpty(gateway)) { + try { + //Extract a default gateway from IP address + InetAddress netPart = NetUtils.getNetworkPart(inetAddr, networkPrefixLength); + byte[] addr = netPart.getAddress(); + addr[addr.length - 1] = 1; + mGatewayView.setText(InetAddress.getByAddress(addr).getHostAddress()); + } catch (RuntimeException ee) { + } catch (java.net.UnknownHostException u) { + } + } else { + InetAddress gatewayAddr = getIPv4Address(gateway); + if (gatewayAddr == null) { + return R.string.wifi_ip_settings_invalid_gateway; + } + if (gatewayAddr.isMulticastAddress()) { + return R.string.wifi_ip_settings_invalid_gateway; + } + staticIPBuilder.setGateway(gatewayAddr); } - staticIpConfiguration.dnsServers.add(dnsAddr); - } - if (mDns2View.length() > 0) { - dns = mDns2View.getText().toString(); - dnsAddr = getIPv4Address(dns); - if (dnsAddr == null) { - return R.string.wifi_ip_settings_invalid_dns; + String dns = mDns1View.getText().toString(); + InetAddress dnsAddr = null; + final ArrayList dnsServers = new ArrayList<>(); + + if (TextUtils.isEmpty(dns)) { + //If everything else is valid, provide hint as a default option + mDns1View.setText(mConfigUi.getContext().getString(R.string.wifi_dns1_hint)); + } else { + dnsAddr = getIPv4Address(dns); + if (dnsAddr == null) { + return R.string.wifi_ip_settings_invalid_dns; + } + dnsServers.add(dnsAddr); + staticIpConfiguration.dnsServers.add(dnsAddr); } - staticIpConfiguration.dnsServers.add(dnsAddr); + + if (mDns2View.length() > 0) { + dns = mDns2View.getText().toString(); + dnsAddr = getIPv4Address(dns); + if (dnsAddr == null) { + return R.string.wifi_ip_settings_invalid_dns; + } + dnsServers.add(dnsAddr); + staticIpConfiguration.dnsServers.add(dnsAddr); + } + staticIPBuilder.setDnsServers(dnsServers); + return 0; + } finally { + // Caller of this method may rely on staticIpConfiguration, so build the final result + // at the end of the method. + staticIpConfiguration = staticIPBuilder.build(); } - return 0; } private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) { @@ -1367,18 +1384,18 @@ public class WifiConfigController2 implements TextWatcher, StaticIpConfiguration staticConfig = config.getIpConfiguration() .getStaticIpConfiguration(); if (staticConfig != null) { - if (staticConfig.ipAddress != null) { + if (staticConfig.getIpAddress() != null) { mIpAddressView.setText( - staticConfig.ipAddress.getAddress().getHostAddress()); - mNetworkPrefixLengthView.setText(Integer.toString(staticConfig.ipAddress - .getPrefixLength())); + staticConfig.getIpAddress().getAddress().getHostAddress()); + mNetworkPrefixLengthView.setText(Integer.toString( + staticConfig.getIpAddress().getPrefixLength())); } if (staticConfig.gateway != null) { - mGatewayView.setText(staticConfig.gateway.getHostAddress()); + mGatewayView.setText(staticConfig.getGateway().getHostAddress()); } - Iterator dnsIterator = staticConfig.dnsServers.iterator(); + Iterator dnsIterator = staticConfig.getDnsServers().iterator(); if (dnsIterator.hasNext()) { mDns1View.setText(dnsIterator.next().getHostAddress()); } From e4b3b969db3acbd2d357ec934a277da5c8cf44ff Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Wed, 17 Mar 2021 01:14:00 +0800 Subject: [PATCH 04/28] Fix NPE of AppVersionPreferenceController Add null check for the package info before getting the version name. Fixes: 168333280 Test: robotests & manual Change-Id: If2e3d220c520d30e932478836ee2ea89f936d55c --- .../appinfo/AppVersionPreferenceController.java | 9 ++++++++- .../appinfo/AppVersionPreferenceControllerTest.java | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java index 205b6d275ee..23dd9602f77 100644 --- a/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppVersionPreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.applications.appinfo; import android.content.Context; +import android.content.pm.PackageInfo; import android.text.BidiFormatter; import com.android.settings.R; @@ -29,7 +30,13 @@ public class AppVersionPreferenceController extends AppInfoPreferenceControllerB @Override public CharSequence getSummary() { + // TODO(b/168333280): Review the null case in detail since this is just a quick + // workaround to fix NPE. + final PackageInfo packageInfo = mParent.getPackageInfo(); + if (packageInfo == null) { + return null; + } return mContext.getString(R.string.version_text, - BidiFormatter.getInstance().unicodeWrap(mParent.getPackageInfo().versionName)); + BidiFormatter.getInstance().unicodeWrap(packageInfo.versionName)); } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java index 1f513a36b41..d5e5080ac70 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppVersionPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.applications.appinfo; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -62,4 +64,13 @@ public class AppVersionPreferenceControllerTest { verify(mPreference).setSummary("version test1234"); } + + @Test + public void updateState_packageInfoNull_shouldNotCrash() { + when(mFragment.getPackageInfo()).thenReturn(null); + + mController.updateState(mPreference); + + assertThat(mController.getSummary()).isNull(); + } } From eb16ebd14ad5f011b22d841a953cd5871676c679 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 17 Mar 2021 20:37:48 +0800 Subject: [PATCH 05/28] Replace the hidden ProxyInfo methods usage The hidden ProxyInfo methods usage should be replaced because ProxyInfo is moving to connectivity mainline module. Setting will not be able to access it. Replace the usage with corresponding APIs. Bug: 172183305 Test: make RunSettingsRoboTests ROBOTEST_FILTER=\ com.android.settings.wifi.WifiConfigControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=\ com.android.settings.wifi.WifiConfigController2Test Test: manually update proxy from setting and check the result Change-Id: I59192d0d5d38c833eb83cc930e358a738ebe3d13 --- src/com/android/settings/ProxySelector.java | 6 +++++- src/com/android/settings/vpn2/ConfigDialog.java | 2 +- src/com/android/settings/wifi/WifiConfigController.java | 6 ++++-- src/com/android/settings/wifi/WifiConfigController2.java | 6 ++++-- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/ProxySelector.java b/src/com/android/settings/ProxySelector.java index a6858419726..57d3c6a75b8 100644 --- a/src/com/android/settings/ProxySelector.java +++ b/src/com/android/settings/ProxySelector.java @@ -44,6 +44,8 @@ import com.android.net.module.util.ProxyUtils; import com.android.settings.SettingsPreferenceFragment.SettingsDialogFragment; import com.android.settings.core.InstrumentedFragment; +import java.util.Arrays; + public class ProxySelector extends InstrumentedFragment implements DialogCreatable { private static final String TAG = "ProxySelector"; @@ -229,7 +231,9 @@ public class ProxySelector extends InstrumentedFragment implements DialogCreatab return false; } } - ProxyInfo p = new ProxyInfo(hostname, port, exclList); + + ProxyInfo p = ProxyInfo.buildDirectProxy( + hostname, port, Arrays.asList(exclList.split(","))); // FIXME: The best solution would be to make a better UI that would // disable editing of the text boxes if the user chooses to use the // default settings. i.e. checking a box to always use the default diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java index 42bc67dc15a..03e3613b9eb 100644 --- a/src/com/android/settings/vpn2/ConfigDialog.java +++ b/src/com/android/settings/vpn2/ConfigDialog.java @@ -592,7 +592,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // 0 is a last resort default, but the interface validates that the proxy port is // present and non-zero. int port = proxyPort.isEmpty() ? 0 : Integer.parseInt(proxyPort); - profile.proxy = new ProxyInfo(proxyHost, port, null); + profile.proxy = ProxyInfo.buildDirectProxy(proxyHost, port); } else { profile.proxy = null; } diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java index 80866689238..f6fda6def71 100644 --- a/src/com/android/settings/wifi/WifiConfigController.java +++ b/src/com/android/settings/wifi/WifiConfigController.java @@ -83,6 +83,7 @@ import com.android.settingslib.wifi.AccessPoint; import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -878,7 +879,8 @@ public class WifiConfigController implements TextWatcher, result = R.string.proxy_error_invalid_port; } if (result == 0) { - mHttpProxy = new ProxyInfo(host, port, exclusionList); + mHttpProxy = ProxyInfo.buildDirectProxy( + host, port, Arrays.asList(exclusionList.split(","))); } else { return false; } @@ -892,7 +894,7 @@ public class WifiConfigController implements TextWatcher, if (uri == null) { return false; } - mHttpProxy = new ProxyInfo(uri); + mHttpProxy = ProxyInfo.buildPacProxy(uri); } return true; } diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java index 0ba95432df8..06fbc88d6a4 100644 --- a/src/com/android/settings/wifi/WifiConfigController2.java +++ b/src/com/android/settings/wifi/WifiConfigController2.java @@ -83,6 +83,7 @@ import com.android.wifitrackerlib.WifiEntry.ConnectedInfo; import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -860,7 +861,8 @@ public class WifiConfigController2 implements TextWatcher, result = R.string.proxy_error_invalid_port; } if (result == 0) { - mHttpProxy = new ProxyInfo(host, port, exclusionList); + mHttpProxy = ProxyInfo.buildDirectProxy( + host, port, Arrays.asList(exclusionList.split(","))); } else { return false; } @@ -874,7 +876,7 @@ public class WifiConfigController2 implements TextWatcher, if (uri == null) { return false; } - mHttpProxy = new ProxyInfo(uri); + mHttpProxy = ProxyInfo.buildPacProxy(uri); } return true; } From 0c86903ec658f0f97c77cdd40f6ffee8af026441 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Tue, 9 Mar 2021 14:38:48 +0800 Subject: [PATCH 06/28] Moving the error messages from slice to panel's subtitle Bug: 180888831 Test: atest ProviderModelSliceTest atest ProviderModelSliceHelperTest atest NetworkProviderWorkerTest atest InternetConnectivityPanelTest make RunSettingsRoboTests -j Change-Id: I4572c8ad15effab0c95feaeac6a99f5aaabf6f90 --- .../settings/network/ProviderModelSlice.java | 25 --- .../network/ProviderModelSliceHelper.java | 32 +--- .../panel/InternetConnectivityPanel.java | 177 ++++++++++++++++-- .../network/ProviderModelSliceHelperTest.java | 17 -- .../network/ProviderModelSliceTest.java | 55 +----- .../panel/InternetConnectivityPanelTest.java | 68 ++++++- 6 files changed, 237 insertions(+), 137 deletions(-) diff --git a/src/com/android/settings/network/ProviderModelSlice.java b/src/com/android/settings/network/ProviderModelSlice.java index a1fdb1cebf4..18765a8e2fe 100644 --- a/src/com/android/settings/network/ProviderModelSlice.java +++ b/src/com/android/settings/network/ProviderModelSlice.java @@ -147,31 +147,6 @@ public class ProviderModelSlice extends WifiSlice { listBuilder.addRow(getWifiSliceItemRow(item)); } } - - // Fifth section: If device has connection problem, this row show the message for user. - // 1) show non_carrier_network_unavailable: - // - while no wifi item - // 2) show all_network_unavailable: - // - while no wifi item + no carrier - // - while no wifi item + no data capability - if (worker == null || wifiList == null || wifiList.size() == 0) { - log("no wifi item"); - int resId = R.string.non_carrier_network_unavailable; - if (!hasCarrier || !mHelper.isDataSimActive()) { - log("No carrier item or no carrier data."); - resId = R.string.all_network_unavailable; - } - - if (!hasCarrier && !hasEthernet) { - // If there is no item in ProviderModelItem, slice needs a header. - listBuilder.setHeader(mHelper.createHeader( - NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS)); - } - listBuilder.addGridRow( - mHelper.createMessageGridRow(resId, - NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS)); - } - return listBuilder.build(); } diff --git a/src/com/android/settings/network/ProviderModelSliceHelper.java b/src/com/android/settings/network/ProviderModelSliceHelper.java index 8ae4197c9fa..440d425fe26 100644 --- a/src/com/android/settings/network/ProviderModelSliceHelper.java +++ b/src/com/android/settings/network/ProviderModelSliceHelper.java @@ -36,7 +36,6 @@ import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.graphics.drawable.IconCompat; -import androidx.slice.builders.GridRowBuilder; import androidx.slice.builders.ListBuilder; import androidx.slice.builders.SliceAction; @@ -79,12 +78,6 @@ public class ProviderModelSliceHelper { Log.d(TAG, s); } - protected ListBuilder.HeaderBuilder createHeader(String intentAction) { - return new ListBuilder.HeaderBuilder() - .setTitle(mContext.getText(R.string.summary_placeholder)) - .setPrimaryAction(getPrimarySliceAction(intentAction)); - } - protected ListBuilder createListBuilder(Uri uri) { final ListBuilder builder = new ListBuilder(mContext, uri, ListBuilder.INFINITY) .setAccentColor(-1) @@ -92,14 +85,6 @@ public class ProviderModelSliceHelper { return builder; } - protected GridRowBuilder createMessageGridRow(int messageResId, String intentAction) { - final CharSequence title = mContext.getText(messageResId); - return new GridRowBuilder() - // Add cells to the grid row. - .addCell(new GridRowBuilder.CellBuilder().addTitleText(title)) - .setPrimaryAction(getPrimarySliceAction(intentAction)); - } - @Nullable protected WifiSliceItem getConnectedWifiItem(List wifiList) { if (wifiList == null) { @@ -111,7 +96,10 @@ public class ProviderModelSliceHelper { return item.isPresent() ? item.get() : null; } - protected boolean hasCarrier() { + /** + * @return whether there is the carrier item in the slice. + */ + public boolean hasCarrier() { if (isAirplaneModeEnabled() || mSubscriptionManager == null || mTelephonyManager == null || mSubscriptionManager.getDefaultDataSubscriptionId() @@ -175,7 +163,12 @@ public class ProviderModelSliceHelper { return mTelephonyManager.isDataEnabled(); } - protected boolean isDataSimActive() { + /** + * To check the carrier data status. + * + * @return whether the carrier data is active. + */ + public boolean isDataSimActive() { return isNoCarrierData() ? false : MobileNetworkUtils.activeNetworkIsCellular(mContext); } @@ -193,11 +186,6 @@ public class ProviderModelSliceHelper { return mobileDataOnAndNoData || mobileDataOffAndOutOfService; } - private boolean isAirplaneSafeNetworksModeEnabled() { - // TODO: isAirplaneSafeNetworksModeEnabled is not READY - return false; - } - @VisibleForTesting Drawable getMobileDrawable(Drawable drawable) throws Throwable { // set color and drawable diff --git a/src/com/android/settings/panel/InternetConnectivityPanel.java b/src/com/android/settings/panel/InternetConnectivityPanel.java index 4fda0a4f0c3..238cbb4ed97 100644 --- a/src/com/android/settings/panel/InternetConnectivityPanel.java +++ b/src/com/android/settings/panel/InternetConnectivityPanel.java @@ -22,10 +22,23 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; import static com.android.settings.network.NetworkProviderSettings.ACTION_NETWORK_PROVIDER_SETTINGS; import android.app.settings.SettingsEnums; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.net.Uri; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.HandlerExecutor; +import android.os.Looper; import android.provider.Settings; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; import androidx.annotation.VisibleForTesting; import androidx.lifecycle.LifecycleObserver; @@ -35,6 +48,9 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.network.AirplaneModePreferenceController; import com.android.settings.network.InternetUpdater; +import com.android.settings.network.ProviderModelSliceHelper; +import com.android.settings.network.SubscriptionsChangeListener; +import com.android.settings.network.telephony.DataConnectivityListener; import com.android.settings.slices.CustomSliceRegistry; import java.util.ArrayList; @@ -44,23 +60,69 @@ import java.util.List; * Represents the Internet Connectivity Panel. */ public class InternetConnectivityPanel implements PanelContent, LifecycleObserver, - InternetUpdater.InternetChangeListener { + InternetUpdater.InternetChangeListener, DataConnectivityListener.Client, + SubscriptionsChangeListener.SubscriptionsChangeListenerClient { + private static final String TAG = "InternetConnectivityPanel"; + private static final int SUBTITLE_TEXT_NONE = -1; + private static final int SUBTITLE_TEXT_WIFI_IS_TURNED_ON = R.string.wifi_is_turned_on_subtitle; + private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE = + R.string.non_carrier_network_unavailable; + private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE = + R.string.all_network_unavailable; private final Context mContext; + private final WifiManager mWifiManager; + private final IntentFilter mWifiStateFilter; + private final NetworkProviderTelephonyCallback mTelephonyCallback; + private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null) { + return; + } + if (TextUtils.equals(intent.getAction(), WifiManager.NETWORK_STATE_CHANGED_ACTION) + || TextUtils.equals(intent.getAction(), + WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { + updatePanelTitle(); + } + } + }; + @VisibleForTesting boolean mIsProviderModelEnabled; - private PanelContentCallback mCallback; @VisibleForTesting InternetUpdater mInternetUpdater; + @VisibleForTesting + ProviderModelSliceHelper mProviderModelSliceHelper; - public static InternetConnectivityPanel create(Context context) { - return new InternetConnectivityPanel(context); - } + private int mSubtitle = SUBTITLE_TEXT_NONE; + private PanelContentCallback mCallback; + private TelephonyManager mTelephonyManager; + private SubscriptionsChangeListener mSubscriptionsListener; + private DataConnectivityListener mConnectivityListener; + private int mDefaultDataSubid = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private InternetConnectivityPanel(Context context) { mContext = context.getApplicationContext(); mIsProviderModelEnabled = Utils.isProviderModelEnabled(mContext); mInternetUpdater = new InternetUpdater(context, null /* Lifecycle */, this); + + mSubscriptionsListener = new SubscriptionsChangeListener(context, this); + mConnectivityListener = new DataConnectivityListener(context, this); + mTelephonyCallback = new NetworkProviderTelephonyCallback(); + mDefaultDataSubid = getDefaultDataSubscriptionId(); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + + mWifiManager = mContext.getSystemService(WifiManager.class); + mWifiStateFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mWifiStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + + mProviderModelSliceHelper = new ProviderModelSliceHelper(mContext, null); + } + + /** create the panel */ + public static InternetConnectivityPanel create(Context context) { + return new InternetConnectivityPanel(context); } /** @OnLifecycleEvent(ON_RESUME) */ @@ -70,6 +132,12 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve return; } mInternetUpdater.onResume(); + mSubscriptionsListener.start(); + mConnectivityListener.start(); + mTelephonyManager.registerTelephonyCallback( + new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback); + mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter); + updatePanelTitle(); } /** @OnLifecycleEvent(ON_PAUSE) */ @@ -79,6 +147,10 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve return; } mInternetUpdater.onPause(); + mSubscriptionsListener.stop(); + mConnectivityListener.stop(); + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); + mContext.unregisterReceiver(mWifiStateReceiver); } /** @@ -98,9 +170,8 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve */ @Override public CharSequence getSubTitle() { - if (mIsProviderModelEnabled && mInternetUpdater.isAirplaneModeOn() - && mInternetUpdater.isWifiEnabled()) { - return mContext.getText(R.string.wifi_is_turned_on_subtitle); + if (mIsProviderModelEnabled && mSubtitle != SUBTITLE_TEXT_NONE) { + return mContext.getText(mSubtitle); } return null; } @@ -170,15 +241,36 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve updatePanelTitle(); } - private void updatePanelTitle() { + @Override + public void onSubscriptionsChanged() { + final int defaultDataSubId = getDefaultDataSubscriptionId(); + log("onSubscriptionsChanged: defaultDataSubId:" + defaultDataSubId); + if (mDefaultDataSubid == defaultDataSubId) { + return; + } + if (SubscriptionManager.isUsableSubscriptionId(defaultDataSubId)) { + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback); + mTelephonyManager.registerTelephonyCallback( + new HandlerExecutor(new Handler(Looper.getMainLooper())), mTelephonyCallback); + } + updatePanelTitle(); + } + + @Override + public void onDataConnectivityChange() { + log("onDataConnectivityChange"); + updatePanelTitle(); + } + + @VisibleForTesting + void updatePanelTitle() { if (mCallback == null) { return; } + updateSubtitleText(); - if (mInternetUpdater.isAirplaneModeOn() && mInternetUpdater.isWifiEnabled()) { - // When the airplane mode is on and Wi-Fi is enabled. - // Title: Airplane mode - // Sub-Title: Wi-Fi is turned on + log("Subtitle:" + mSubtitle); + if (mSubtitle != SUBTITLE_TEXT_NONE) { mCallback.onHeaderChanged(); } else { // Other situations. @@ -187,4 +279,63 @@ public class InternetConnectivityPanel implements PanelContent, LifecycleObserve } mCallback.onCustomizedButtonStateChanged(); } + + @VisibleForTesting + int getDefaultDataSubscriptionId() { + return SubscriptionManager.getDefaultDataSubscriptionId(); + } + + private void updateSubtitleText() { + mSubtitle = SUBTITLE_TEXT_NONE; + if (!mInternetUpdater.isWifiEnabled()) { + return; + } + + if (mInternetUpdater.isAirplaneModeOn()) { + // When the airplane mode is on and Wi-Fi is enabled. + // Title: Airplane mode + // Sub-Title: Wi-Fi is turned on + log("Airplane mode is on + Wi-Fi on."); + mSubtitle = SUBTITLE_TEXT_WIFI_IS_TURNED_ON; + return; + } + + final List wifiList = mWifiManager.getScanResults(); + if (wifiList != null && wifiList.size() == 0) { + // Sub-Title: + // show non_carrier_network_unavailable + // - while Wi-Fi on + no Wi-Fi item + // show all_network_unavailable: + // - while Wi-Fi on + no Wi-Fi item + no carrier + // - while Wi-Fi on + no Wi-Fi item + no data capability + log("No Wi-Fi item."); + mSubtitle = SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE; + if (!mProviderModelSliceHelper.hasCarrier() + || !mProviderModelSliceHelper.isDataSimActive()) { + log("No carrier item or no carrier data."); + mSubtitle = SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE; + } + } + } + + private class NetworkProviderTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.DataConnectionStateListener, + TelephonyCallback.ServiceStateListener { + @Override + public void onServiceStateChanged(ServiceState state) { + log("onServiceStateChanged voiceState=" + state.getState() + + " dataState=" + state.getDataRegistrationState()); + updatePanelTitle(); + } + + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + log("onDataConnectionStateChanged: networkType=" + networkType + " state=" + state); + updatePanelTitle(); + } + } + + private static void log(String s) { + Log.d(TAG, s); + } } diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java index d205607db23..ac2e24d8061 100644 --- a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java +++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java @@ -34,7 +34,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.Uri; import android.os.PersistableBundle; -import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.SubscriptionInfo; @@ -43,8 +42,6 @@ import android.telephony.TelephonyManager; import android.text.Html; import androidx.slice.Slice; -import androidx.slice.builders.GridRowBuilder; -import androidx.slice.builders.GridRowBuilder.CellBuilder; import androidx.slice.builders.ListBuilder; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -114,20 +111,6 @@ public class ProviderModelSliceHelperTest { mProviderModelSliceHelper = new MockProviderModelSliceHelper(mContext, testCustomSliceable); } - @Test - public void createMessageGridRow_inputTheResourceId_verifyTitle() { - int messageResId = ResourcesUtils.getResourcesId(mContext, "string", - "non_carrier_network_unavailable"); - CharSequence title = ResourcesUtils.getResourcesString(mContext, - "non_carrier_network_unavailable"); - - GridRowBuilder testGridRow = mProviderModelSliceHelper.createMessageGridRow(messageResId, - Settings.ACTION_AIRPLANE_MODE_SETTINGS); - List cellItem = testGridRow.getCells(); - - assertThat(cellItem.get(0).getTitle()).isEqualTo(title); - } - @Test public void getConnectedWifiItem_inputListInvolveOneConnectedWifiItem_verifyReturnItem() { when(mWifiSliceItem1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED); diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java index 705f60ec972..4760daacef8 100644 --- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java +++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java @@ -22,7 +22,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -42,7 +41,6 @@ import android.telephony.TelephonyManager; import androidx.slice.Slice; import androidx.slice.SliceProvider; -import androidx.slice.builders.GridRowBuilder; import androidx.slice.builders.ListBuilder; import androidx.slice.builders.SliceAction; import androidx.slice.widget.SliceLiveData; @@ -97,12 +95,6 @@ public class ProviderModelSliceTest { private WifiSliceItem mMockWifiSliceItem3; @Mock ListBuilder.RowBuilder mMockCarrierRowBuild; - @Mock - ListBuilder.HeaderBuilder mMockHeader; - @Mock - GridRowBuilder mMockGridRowBuilderNonCarrierNetworkUnavailable; - @Mock - GridRowBuilder mMockGridRowBuilderAllNetworkUnavailable; private FakeFeatureFactory mFeatureFactory; @Mock @@ -147,35 +139,7 @@ public class ProviderModelSliceTest { @Test @UiThreadTest - public void getSlice_noWorkerAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() { - mWifiList.clear(); - mMockProviderModelSlice = new MockProviderModelSlice(mContext, null); - mockHelperCondition(false, false, false, null); - - final Slice slice = mMockProviderModelSlice.getSlice(); - - assertThat(slice).isNotNull(); - verify(mListBuilder, times(1)).setHeader(mMockHeader); - verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable); - } - - @Test - @UiThreadTest - public void getSlice_noWifiAndNoCarrier_getOneHeaderOneGridRowWithAllNetworkUnavailable() { - mWifiList.clear(); - mMockNetworkProviderWorker.updateSelfResults(null); - mockHelperCondition(false, false, false, null); - - final Slice slice = mMockProviderModelSlice.getSlice(); - - assertThat(slice).isNotNull(); - verify(mListBuilder, times(1)).setHeader(mMockHeader); - verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable); - } - - @Test - @UiThreadTest - public void getSlice_noWifiAndHasCarrierNoData_oneCarrierOneGridRowWithAllNetworkUnavailable() { + public void getSlice_noWifiAndHasCarrierNoData_oneCarrier() { mWifiList.clear(); mMockNetworkProviderWorker.updateSelfResults(null); mockHelperCondition(false, true, false, null); @@ -184,12 +148,11 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); - verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderAllNetworkUnavailable); } @Test @UiThreadTest - public void getSlice_noWifiAndNoCarrier_oneCarrierOneGridRowWithNonCarrierNetworkUnavailable() { + public void getSlice_noWifiAndNoCarrier_oneCarrier() { mWifiList.clear(); mMockProviderModelSlice = new MockProviderModelSlice(mContext, null); mockHelperCondition(false, true, true, null); @@ -198,7 +161,6 @@ public class ProviderModelSliceTest { assertThat(slice).isNotNull(); verify(mListBuilder, times(1)).addRow(mMockCarrierRowBuild); - verify(mListBuilder, times(1)).addGridRow(mMockGridRowBuilderNonCarrierNetworkUnavailable); } @Test @@ -331,19 +293,6 @@ public class ProviderModelSliceTest { private void mockBuilder() { SliceAction mockSliceAction = getPrimarySliceAction(); - when(mMockHeader.getTitle()).thenReturn("mockHeader"); - when(mMockHeader.getPrimaryAction()).thenReturn(mockSliceAction); - when(mProviderModelSliceHelper.createHeader(anyString())).thenReturn(mMockHeader); - - int resId = ResourcesUtils.getResourcesId(mContext, "string", - "non_carrier_network_unavailable"); - when(mProviderModelSliceHelper.createMessageGridRow(eq(resId), anyString())).thenReturn( - mMockGridRowBuilderNonCarrierNetworkUnavailable); - resId = ResourcesUtils.getResourcesId(mContext, "string", - "all_network_unavailable"); - when(mProviderModelSliceHelper.createMessageGridRow(eq(resId), anyString())).thenReturn( - mMockGridRowBuilderAllNetworkUnavailable); - when(mMockCarrierRowBuild.getTitle()).thenReturn("mockRow"); when(mMockCarrierRowBuild.getPrimaryAction()).thenReturn(mockSliceAction); when(mProviderModelSliceHelper.createCarrierRow(anyString())).thenReturn( diff --git a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java index ba5ee8e3263..8f0cfb31538 100644 --- a/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java +++ b/tests/unit/src/com/android/settings/panel/InternetConnectivityPanelTest.java @@ -22,15 +22,19 @@ import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.Context; import android.net.Uri; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.settings.network.AirplaneModePreferenceController; import com.android.settings.network.InternetUpdater; +import com.android.settings.network.ProviderModelSliceHelper; import com.android.settings.slices.CustomSliceRegistry; import com.android.settings.testutils.ResourcesUtils; @@ -42,6 +46,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import java.util.ArrayList; import java.util.List; @RunWith(AndroidJUnit4.class) @@ -55,6 +60,12 @@ public class InternetConnectivityPanelTest { ApplicationProvider.getApplicationContext(), "wifi_is_turned_on_subtitle"); public static final String BUTTON_SETTINGS = ResourcesUtils.getResourcesString( ApplicationProvider.getApplicationContext(), "settings_button"); + public static final String SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE = + ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), + "non_carrier_network_unavailable"); + public static final String SUBTITLE_ALL_NETWORK_UNAVAILABLE = + ResourcesUtils.getResourcesString(ApplicationProvider.getApplicationContext(), + "all_network_unavailable"); @Rule public final MockitoRule mMocks = MockitoJUnit.rule(); @@ -62,6 +73,10 @@ public class InternetConnectivityPanelTest { PanelContentCallback mPanelContentCallback; @Mock InternetUpdater mInternetUpdater; + @Mock + private WifiManager mWifiManager; + @Mock + private ProviderModelSliceHelper mProviderModelSliceHelper; private Context mContext; private InternetConnectivityPanel mPanel; @@ -69,11 +84,14 @@ public class InternetConnectivityPanelTest { @Before public void setUp() { mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getApplicationContext()).thenReturn(mContext); + when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager); mPanel = InternetConnectivityPanel.create(mContext); mPanel.registerCallback(mPanelContentCallback); mPanel.mIsProviderModelEnabled = true; mPanel.mInternetUpdater = mInternetUpdater; + mPanel.mProviderModelSliceHelper = mProviderModelSliceHelper; } @Test @@ -90,13 +108,6 @@ public class InternetConnectivityPanelTest { assertThat(mPanel.getTitle()).isEqualTo(TITLE_APM); } - @Test - public void getSubTitle_apmOff_shouldBeNull() { - doReturn(false).when(mInternetUpdater).isAirplaneModeOn(); - - assertThat(mPanel.getSubTitle()).isNull(); - } - @Test public void getSubTitle_apmOnWifiOff_shouldBeNull() { doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); @@ -110,9 +121,43 @@ public class InternetConnectivityPanelTest { doReturn(true).when(mInternetUpdater).isAirplaneModeOn(); doReturn(true).when(mInternetUpdater).isWifiEnabled(); + mPanel.updatePanelTitle(); + assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_WIFI_IS_TURNED_ON); } + @Test + public void getSubTitle_apmOffWifiOnNoWifiListHasCarrierData_NonCarrierNetworkUnavailable() { + List wifiList = new ArrayList(); + mockCondition(false, true, true, true, wifiList); + + mPanel.updatePanelTitle(); + + assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_NON_CARRIER_NETWORK_UNAVAILABLE); + } + + @Test + public void getSubTitle_apmOffWifiOnNoWifiListNoCarrierData_AllNetworkUnavailable() { + List wifiList = new ArrayList(); + mockCondition(false, true, false, true, wifiList); + + mPanel.updatePanelTitle(); + + assertThat(mPanel.getSubTitle()).isEqualTo(SUBTITLE_ALL_NETWORK_UNAVAILABLE); + } + + @Test + public void getSubTitle_apmOffWifiOnTwoWifiItemsNoCarrierData_shouldBeNull() { + List wifiList = new ArrayList(); + wifiList.add(new ScanResult()); + wifiList.add(new ScanResult()); + mockCondition(false, true, false, true, wifiList); + + mPanel.updatePanelTitle(); + + assertThat(mPanel.getSubTitle()).isNull(); + } + @Test public void getCustomizedButtonTitle_apmOff_shouldBeSettings() { doReturn(false).when(mInternetUpdater).isAirplaneModeOn(); @@ -244,4 +289,13 @@ public class InternetConnectivityPanelTest { verify(mPanelContentCallback).onCustomizedButtonStateChanged(); } + + private void mockCondition(boolean airplaneMode, boolean hasCarrier, + boolean isDataSimActive, boolean isWifiEnabled, List wifiItems) { + doReturn(airplaneMode).when(mInternetUpdater).isAirplaneModeOn(); + when(mProviderModelSliceHelper.hasCarrier()).thenReturn(hasCarrier); + when(mProviderModelSliceHelper.isDataSimActive()).thenReturn(isDataSimActive); + doReturn(isWifiEnabled).when(mInternetUpdater).isWifiEnabled(); + doReturn(wifiItems).when(mWifiManager).getScanResults(); + } } From 03dbb40d2baa8797f600fdd8139e5e87a241a732 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Fri, 12 Feb 2021 00:49:51 +0800 Subject: [PATCH 07/28] Setup basic layout and resources for the accessibility button settings page cherry picked from commit 93ef33655c53ccefd782b51f9743eee3fc0abb62 Bug: 173940869 Test: atest AccessibilityButtonFragmentTest Change-Id: I3f1d8b161d1baadeead36f49f18f00a91fd40b4c Merged-In: I3f1d8b161d1baadeead36f49f18f00a91fd40b4c --- res/values/arrays.xml | 32 +++++++++++ res/values/strings.xml | 20 +++++++ res/xml/accessibility_button_settings.xml | 57 +++++++++++++++++++ res/xml/accessibility_shortcuts_settings.xml | 7 +++ .../AccessibilityButtonFragment.java | 55 ++++++++++++++++++ .../AccessibilityButtonFragmentTest.java | 50 ++++++++++++++++ 6 files changed, 221 insertions(+) create mode 100644 res/xml/accessibility_button_settings.xml create mode 100644 src/com/android/settings/accessibility/AccessibilityButtonFragment.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonFragmentTest.java diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 183dd1e579d..2d03c11227e 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -966,6 +966,38 @@ -1 + + + Floating over other apps + Navigation bar + + + + + + + 1 + + 0 + + + + + Small + Large + Half Circle + + + + + + 0 + + 1 + + 2 + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 91867dc9e3d..a9f860acbad 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5164,6 +5164,26 @@ Shortcut from lock screen Allow feature shortcut to turn on from the lock screen. Hold both volume keys for a few seconds. + + Accessibility button + + Quickly access accessibility features + + Quickly access accessibility features from any screen. \n\nTo get started, go to accessibility settings and select a feature. Tap on the shortcut and select the accessibility button. + + Location + + Size + + Fade when not in use + + Fades after a few seconds so it\u2019s easier to see your screen + + Transparency when not in use + + Transparent + + Non-transparent High contrast text diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml new file mode 100644 index 00000000000..7bb534f3fbb --- /dev/null +++ b/res/xml/accessibility_button_settings.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/xml/accessibility_shortcuts_settings.xml b/res/xml/accessibility_shortcuts_settings.xml index 35314e708bb..465f96d74df 100644 --- a/res/xml/accessibility_shortcuts_settings.xml +++ b/res/xml/accessibility_shortcuts_settings.xml @@ -21,6 +21,13 @@ android:persistent="false" android:title="@string/accessibility_shortcuts_settings_title"> + + niks = AccessibilityButtonFragment.SEARCH_INDEX_DATA_PROVIDER + .getNonIndexableKeys(mContext); + final List keys = + XmlTestUtils.getKeysFromPreferenceXml(mContext, + R.xml.accessibility_button_settings); + + assertThat(keys).containsAtLeastElementsIn(niks); + } +} From 2dc32f63f81fdffea0b7a7bf001b480c0eda1384 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Wed, 17 Feb 2021 17:07:43 +0800 Subject: [PATCH 08/28] Add the preference controller to control accessibility button location preference cherry picked from commit 123464429dbe0e677a4cb9118e436444bd575061 Bug: 173940869 Test: atest AccessibilityButtonLocationPreferenceControllerTest Change-Id: I49a23b2eb4e07e79afcefc5a148c23b06396ec1c Merged-In: I49a23b2eb4e07e79afcefc5a148c23b06396ec1c --- res/xml/accessibility_button_settings.xml | 3 +- ...ityButtonLocationPreferenceController.java | 89 +++++++++++++++ ...uttonLocationPreferenceControllerTest.java | 106 ++++++++++++++++++ 3 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml index 7bb534f3fbb..2fa2e0d0938 100644 --- a/res/xml/accessibility_button_settings.xml +++ b/res/xml/accessibility_button_settings.xml @@ -25,7 +25,8 @@ android:key="accessibility_button_location" android:title="@string/accessibility_button_location_title" android:summary="%s" - android:persistent="false"/> + android:persistent="false" + settings:controller="com.android.settings.accessibility.AccessibilityButtonLocationPreferenceController"/> mValueTitleMap = new ArrayMap<>(); + private int mDefaultLocation; + + public AccessibilityButtonLocationPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + initValueTitleMap(); + } + + @Override + public int getAvailabilityStatus() { + return AccessibilityUtil.isGestureNavigateEnabled(mContext) + ? DISABLED_DEPENDENT_SETTING : AVAILABLE; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final ListPreference listPreference = (ListPreference) preference; + final Integer value = Ints.tryParse((String) newValue); + if (value != null) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, value); + updateState(listPreference); + } + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + final ListPreference listPreference = (ListPreference) preference; + + listPreference.setValue(getCurrentAccessibilityButtonMode()); + } + + private String getCurrentAccessibilityButtonMode() { + final int mode = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BUTTON_MODE, mDefaultLocation); + return String.valueOf(mode); + } + + private void initValueTitleMap() { + if (mValueTitleMap.size() == 0) { + final String[] values = mContext.getResources().getStringArray( + R.array.accessibility_button_location_selector_values); + final String[] titles = mContext.getResources().getStringArray( + R.array.accessibility_button_location_selector_titles); + final int mapSize = values.length; + + mDefaultLocation = Integer.parseInt(values[0]); + for (int i = 0; i < mapSize; i++) { + mValueTitleMap.put(values[i], titles[i]); + } + } + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java new file mode 100644 index 00000000000..a67038a6b2d --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonLocationPreferenceControllerTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2021 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.accessibility; + +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.Resources; +import android.provider.Settings; + +import androidx.preference.ListPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link AccessibilityButtonLocationPreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class AccessibilityButtonLocationPreferenceControllerTest { + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Spy + private final Resources mResources = mContext.getResources(); + private final ContentResolver mContentResolver = mContext.getContentResolver(); + private final ListPreference mListPreference = new ListPreference(mContext); + private AccessibilityButtonLocationPreferenceController mController; + + + @Before + public void setUp() { + mController = new AccessibilityButtonLocationPreferenceController(mContext, + "test_key"); + when(mContext.getResources()).thenReturn(mResources); + } + + @Test + public void getAvailabilityStatus_navigationGestureEnabled_returnDisabledDependentSetting() { + when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode)) + .thenReturn(NAV_BAR_MODE_GESTURAL); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void getAvailabilityStatus_navigationGestureDisabled_returnAvailable() { + when(mResources.getInteger(com.android.internal.R.integer.config_navBarInteractionMode)) + .thenReturn(NAV_BAR_MODE_2BUTTON); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void updateState_a11yBtnModeNavigationBar_navigationBarValue() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + mController.updateState(mListPreference); + + final String navigationBarValue = String.valueOf(ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + assertThat(mListPreference.getValue()).isEqualTo(navigationBarValue); + } + + @Test + public void onPreferenceChange_a11yBtnModeFloatingMenu_floatingMenuValue() { + final String floatingMenuValue = String.valueOf(ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + + mController.onPreferenceChange(mListPreference, floatingMenuValue); + + assertThat(mListPreference.getValue()).isEqualTo(floatingMenuValue); + } +} From 0377025554e748c2b30cde923d38e1bc728ca565 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 18 Feb 2021 00:49:43 +0800 Subject: [PATCH 09/28] Add the preference controller to control accessibility button size preference cherry picked from commit 04955b96aea80194ae979912f87eac1e1ec6a9d3 Bug: 173940869 Test: atest FloatingMenuSizePreferenceControllerTest Change-Id: Ic206a940abde90641442df37a634c8cb3a345597 Merged-In: Ic206a940abde90641442df37a634c8cb3a345597 --- res/xml/accessibility_button_settings.xml | 3 +- .../accessibility/AccessibilityUtil.java | 8 + .../FloatingMenuSizePreferenceController.java | 199 ++++++++++++++++++ ...atingMenuSizePreferenceControllerTest.java | 145 +++++++++++++ 4 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml index 2fa2e0d0938..e348b77ffb0 100644 --- a/res/xml/accessibility_button_settings.xml +++ b/res/xml/accessibility_button_settings.xml @@ -34,7 +34,8 @@ android:key="accessibility_button_size" android:title="@string/accessibility_button_size_title" android:summary="%s" - android:persistent="false"/> + android:persistent="false" + settings:controller="com.android.settings.accessibility.FloatingMenuSizePreferenceController"/> mValueTitleMap = new ArrayMap<>(); + private int mDefaultSize; + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + Size.SMALL, + Size.LARGE, + Size.EDGE + }) + @VisibleForTesting + @interface Size { + int SMALL = 0; + int LARGE = 1; + int EDGE = 2; + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + EdgeMode.FULL_CIRCLE, + EdgeMode.HALF_CIRCLE, + }) + @VisibleForTesting + @interface EdgeMode { + int FULL_CIRCLE = 0; + int HALF_CIRCLE = 1; + } + + public FloatingMenuSizePreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mContentResolver = context.getContentResolver(); + mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + updateAvailabilityStatus(); + } + }; + + initValueTitleMap(); + } + + @Override + public int getAvailabilityStatus() { + return AccessibilityUtil.isFloatingMenuEnabled(mContext) + ? AVAILABLE : DISABLED_DEPENDENT_SETTING; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final ListPreference listPreference = (ListPreference) preference; + final Integer value = Ints.tryParse((String) newValue); + if (value != null) { + writeToFloatingMenuSettings(value); + updateState(listPreference); + } + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + final ListPreference listPreference = (ListPreference) preference; + + listPreference.setValue(getCurrentAccessibilityButtonSize()); + } + + @Override + public void onResume() { + mContentResolver.registerContentObserver( + Settings.Secure.getUriFor( + Settings.Secure.ACCESSIBILITY_BUTTON_MODE), /* notifyForDescendants= */ + false, mContentObserver); + + } + + @Override + public void onPause() { + mContentResolver.unregisterContentObserver(mContentObserver); + } + + private void updateAvailabilityStatus() { + mPreference.setEnabled(AccessibilityUtil.isFloatingMenuEnabled(mContext)); + } + + private void initValueTitleMap() { + if (mValueTitleMap.size() == 0) { + final String[] values = mContext.getResources().getStringArray( + R.array.accessibility_button_size_selector_values); + final String[] titles = mContext.getResources().getStringArray( + R.array.accessibility_button_size_selector_titles); + final int mapSize = values.length; + + mDefaultSize = Integer.parseInt(values[0]); + for (int i = 0; i < mapSize; i++) { + mValueTitleMap.put(values[i], titles[i]); + } + } + } + + private void writeToFloatingMenuSettings(@Size int sizeValue) { + if (sizeValue == Size.EDGE) { + putAccessibilityFloatingMenuSize(Size.SMALL); + putAccessibilityFloatingMenuIconType(EdgeMode.HALF_CIRCLE); + } else { + putAccessibilityFloatingMenuSize(sizeValue); + putAccessibilityFloatingMenuIconType(EdgeMode.FULL_CIRCLE); + } + } + + private String getCurrentAccessibilityButtonSize() { + final @EdgeMode int iconType = getAccessibilityFloatingMenuIconType(EdgeMode.FULL_CIRCLE); + final @Size int btnSize = getAccessibilityFloatingMenuSize(mDefaultSize); + + return (iconType == EdgeMode.HALF_CIRCLE) + ? String.valueOf(Size.EDGE) : String.valueOf(btnSize); + } + + @Size + private int getAccessibilityFloatingMenuSize(@Size int defaultValue) { + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, defaultValue); + } + + private void putAccessibilityFloatingMenuSize(@Size int value) { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, value); + } + + @EdgeMode + private int getAccessibilityFloatingMenuIconType(@EdgeMode int defaultValue) { + return Settings.Secure.getInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, defaultValue); + } + + private void putAccessibilityFloatingMenuIconType(@EdgeMode int value) { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, value); + } +} diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java new file mode 100644 index 00000000000..70257ca6931 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2021 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.accessibility; + +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import androidx.preference.ListPreference; +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link FloatingMenuSizePreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class FloatingMenuSizePreferenceControllerTest { + + @Rule + public MockitoRule mocks = MockitoJUnit.rule(); + + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private ContentResolver mContentResolver; + private final ListPreference mListPreference = new ListPreference(mContext); + private FloatingMenuSizePreferenceController mController; + + @Before + public void setUp() { + when(mContext.getContentResolver()).thenReturn(mContentResolver); + mController = new FloatingMenuSizePreferenceController(mContext, "test_key"); + } + + @Test + public void getAvailabilityStatus_a11yBtnModeFloatingMenu_returnAvailable() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_a11yBtnModeNavigationBar_returnDisabledDependentSetting() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void updateState_floatingMenuLargeSizeAndFullCircle_largeSizeValue() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, + FloatingMenuSizePreferenceController.Size.LARGE); + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, + FloatingMenuSizePreferenceController.EdgeMode.FULL_CIRCLE); + + mController.updateState(mListPreference); + + final String largeSize = String.valueOf(FloatingMenuSizePreferenceController.Size.LARGE); + assertThat(mListPreference.getValue()).isEqualTo(largeSize); + } + + @Test + public void updateState_floatingMenuHalfCircle_edgeSizeValue() { + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, + FloatingMenuSizePreferenceController.EdgeMode.HALF_CIRCLE); + + mController.updateState(mListPreference); + + final String edgeSize = String.valueOf(FloatingMenuSizePreferenceController.Size.EDGE); + assertThat(mListPreference.getValue()).isEqualTo(edgeSize); + } + + @Test + public void onPreferenceChange_floatingMenuEdgeSize_edgeSizeValue() { + final String edgeSize = String.valueOf( + FloatingMenuSizePreferenceController.Size.EDGE); + + mController.onPreferenceChange(mListPreference, edgeSize); + + assertThat(mListPreference.getValue()).isEqualTo(edgeSize); + } + + @Test + public void onChange_a11yBtnModeChangeToNavigationBar_preferenceDisabled() { + mController.mPreference = mListPreference; + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + mController.mContentObserver.onChange(false); + + assertThat(mController.mPreference.isEnabled()).isFalse(); + } + + @Test + public void onResume_registerSpecificContentObserver() { + mController.onResume(); + + verify(mContentResolver).registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false, + mController.mContentObserver); + } + + @Test + public void onPause_unregisterContentObserver() { + mController.onPause(); + + verify(mContentResolver).unregisterContentObserver(mController.mContentObserver); + } +} From c72fe39597381b6d1969096a98e4078ec8f982b3 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 18 Feb 2021 03:29:26 +0800 Subject: [PATCH 10/28] Add the preference controller to control accessibility button opacity preference cherry picked from commit c497c7aabeb004b5d1ace57a9cfe164f9ecfa597 Bug: 173940869 Test: atest FloatingMenuOpacityPreferenceControllerTest Change-Id: I1fbe3157c93fef4611c3b9b13569c9b339e2898a Merged-In: I1fbe3157c93fef4611c3b9b13569c9b339e2898a --- res/xml/accessibility_button_settings.xml | 3 +- ...oatingMenuOpacityPreferenceController.java | 142 ++++++++++++++++++ ...ngMenuOpacityPreferenceControllerTest.java | 137 +++++++++++++++++ 3 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml index e348b77ffb0..8d4631afbba 100644 --- a/res/xml/accessibility_button_settings.xml +++ b/res/xml/accessibility_button_settings.xml @@ -47,7 +47,8 @@ android:key="accessibility_button_opacity" android:title="@string/accessibility_button_opacity_title" android:selectable="true" - android:persistent="false"/> + android:persistent="false" + settings:controller="com.android.settings.accessibility.FloatingMenuOpacityPreferenceController"/> maxValue) ? DEFAULT_OPACITY : value; + } +} + diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java new file mode 100644 index 00000000000..98ad00a8fda --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuOpacityPreferenceControllerTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2021 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.accessibility; + +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; +import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; + +import static com.android.settings.accessibility.FloatingMenuOpacityPreferenceController.DEFAULT_OPACITY; +import static com.android.settings.accessibility.FloatingMenuOpacityPreferenceController.PRECISION; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.widget.SeekBarPreference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** Tests for {@link FloatingMenuOpacityPreferenceController}. */ +@RunWith(RobolectricTestRunner.class) +public class FloatingMenuOpacityPreferenceControllerTest { + + @Rule + public MockitoRule mocks = MockitoJUnit.rule(); + + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private ContentResolver mContentResolver; + private FloatingMenuOpacityPreferenceController mController; + + @Before + public void setUp() { + when(mContext.getContentResolver()).thenReturn(mContentResolver); + mController = new FloatingMenuOpacityPreferenceController(mContext, "test_key"); + } + + @Test + public void getAvailabilityStatus_a11yBtnModeFloatingMenu_returnAvailable() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_a11yBtnModeNavigationBar_returnDisabledDependentSetting() { + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + } + + @Test + public void onChange_a11yBtnModeChangeToNavigationBar_preferenceDisabled() { + mController.mPreference = new SeekBarPreference(mContext); + Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_BUTTON_MODE, + ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR); + + mController.mContentObserver.onChange(false); + + assertThat(mController.mPreference.isEnabled()).isFalse(); + } + + @Test + public void getSliderPosition_putNormalOpacityValue_expectedValue() { + Settings.Secure.putFloat(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, 0.35f); + + assertThat(mController.getSliderPosition()).isEqualTo(35); + } + + @Test + public void getSliderPosition_putOutOfBoundOpacityValue_defaultValue() { + Settings.Secure.putFloat(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, 0.01f); + + final int defaultValue = Math.round(DEFAULT_OPACITY * PRECISION); + assertThat(mController.getSliderPosition()).isEqualTo(defaultValue); + } + + @Test + public void setSliderPosition_expectedValue() { + mController.setSliderPosition(27); + + final float value = Settings.Secure.getFloat(mContext.getContentResolver(), + Settings.Secure.ACCESSIBILITY_FLOATING_MENU_OPACITY, -1); + assertThat(value).isEqualTo(0.27f); + } + + @Test + public void onResume_registerSpecificContentObserver() { + mController.onResume(); + + verify(mContentResolver).registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_BUTTON_MODE), false, + mController.mContentObserver); + } + + @Test + public void onPause_unregisterContentObserver() { + mController.onPause(); + + verify(mContentResolver).unregisterContentObserver(mController.mContentObserver); + } +} From eb2411db9d396e8c502787b6984cee69df45108f Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 18 Feb 2021 04:01:01 +0800 Subject: [PATCH 11/28] Add the preference controller to control accessibility button preview preference * Create FloatingMenuLayerDrawable class to handle the preview layer drawable cherry picked from commit 603014760fb6ceb4a66c805ebeef07918fba6652 Bug: 173940869 Test: atest AccessibilityButtonPreviewPreferenceControllerTest FloatingMenuLayerDrawableTest Change-Id: Ia3d030547b377e87c505b2310f559f7f3876ecd5 Merged-In: Ia3d030547b377e87c505b2310f559f7f3876ecd5 --- .../accessibility_button_navigation.xml | 70 +++++++++ .../accessibility_button_preview_base.xml | 45 ++++++ ...ity_button_preview_large_floating_menu.xml | 41 ++++++ ...ity_button_preview_small_floating_menu.xml | 41 ++++++ res/layout/accessibility_button_preview.xml | 33 +++++ res/values/dimens.xml | 2 + res/xml/accessibility_button_settings.xml | 9 ++ ...lityButtonPreviewPreferenceController.java | 126 +++++++++++++++++ .../FloatingMenuLayerDrawable.java | 133 ++++++++++++++++++ ...ButtonPreviewPreferenceControllerTest.java | 120 ++++++++++++++++ .../FloatingMenuLayerDrawableTest.java | 73 ++++++++++ 11 files changed, 693 insertions(+) create mode 100644 res/drawable/accessibility_button_navigation.xml create mode 100644 res/drawable/accessibility_button_preview_base.xml create mode 100644 res/drawable/accessibility_button_preview_large_floating_menu.xml create mode 100644 res/drawable/accessibility_button_preview_small_floating_menu.xml create mode 100644 res/layout/accessibility_button_preview.xml create mode 100644 src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceController.java create mode 100644 src/com/android/settings/accessibility/FloatingMenuLayerDrawable.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/AccessibilityButtonPreviewPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/FloatingMenuLayerDrawableTest.java diff --git a/res/drawable/accessibility_button_navigation.xml b/res/drawable/accessibility_button_navigation.xml new file mode 100644 index 00000000000..30273fb4e1f --- /dev/null +++ b/res/drawable/accessibility_button_navigation.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/accessibility_button_preview_base.xml b/res/drawable/accessibility_button_preview_base.xml new file mode 100644 index 00000000000..0712b9508b1 --- /dev/null +++ b/res/drawable/accessibility_button_preview_base.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/accessibility_button_preview_large_floating_menu.xml b/res/drawable/accessibility_button_preview_large_floating_menu.xml new file mode 100644 index 00000000000..e003dc7322c --- /dev/null +++ b/res/drawable/accessibility_button_preview_large_floating_menu.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/accessibility_button_preview_small_floating_menu.xml b/res/drawable/accessibility_button_preview_small_floating_menu.xml new file mode 100644 index 00000000000..3ff8e4b25f4 --- /dev/null +++ b/res/drawable/accessibility_button_preview_small_floating_menu.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/accessibility_button_preview.xml b/res/layout/accessibility_button_preview.xml new file mode 100644 index 00000000000..07cb0ffb8ab --- /dev/null +++ b/res/layout/accessibility_button_preview.xml @@ -0,0 +1,33 @@ + + + + + + + \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 4fef726d599..dbf21fc8626 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -57,6 +57,8 @@ 320dp + 200dp + 4dp diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml index 8d4631afbba..fc91dcaeef6 100644 --- a/res/xml/accessibility_button_settings.xml +++ b/res/xml/accessibility_button_settings.xml @@ -19,6 +19,15 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/accessibility_button_title"> + + Date: Fri, 19 Feb 2021 16:44:57 +0800 Subject: [PATCH 12/28] Add the preference controller to control accessibility button fade preference * Opacity preference will be disabled when fade is disabled cherry picked from commit f9fdedaafe90ecaa9bcfbef7a0d7054eecd23803 Bug: 173940869 Test: atest AccessibilityButtonFadePreferenceControllerTest AccessibilityButtonOactiyPreferenceControllerTest Change-Id: I1efd9760aa0287899cddd10ddd9a88a81ccc39ba Merged-In: I1efd9760aa0287899cddd10ddd9a88a81ccc39ba --- res/xml/accessibility_button_settings.xml | 3 +- .../FloatingMenuFadePreferenceController.java | 116 ++++++++++++++++ ...oatingMenuOpacityPreferenceController.java | 12 +- ...atingMenuFadePreferenceControllerTest.java | 131 ++++++++++++++++++ ...ngMenuOpacityPreferenceControllerTest.java | 4 + 5 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/accessibility/FloatingMenuFadePreferenceControllerTest.java diff --git a/res/xml/accessibility_button_settings.xml b/res/xml/accessibility_button_settings.xml index fc91dcaeef6..5e81616bffc 100644 --- a/res/xml/accessibility_button_settings.xml +++ b/res/xml/accessibility_button_settings.xml @@ -50,7 +50,8 @@ android:key="accessibility_button_fade" android:title="@string/accessibility_button_fade_title" android:summary="@string/accessibility_button_fade_summary" - android:persistent="false"/> + android:persistent="false" + settings:controller="com.android.settings.accessibility.FloatingMenuFadePreferenceController"/> Date: Thu, 11 Mar 2021 21:44:56 +0800 Subject: [PATCH 13/28] Update the dialog content for accessibility floating menu Accessibility gesture is replaced by accessibility floating menu, related content in edit shortcut dialog and tutorial dialog are updated in this changelist. cherry picked from commit 5fe2cdcf8751f50ea21d23a17abd619d7a16cf25 Bug: 173990914 Test: manual test Change-Id: Ie529fa8a1f8ee87ca1ec5611b35675cdfd762165 Merged-In: Ie529fa8a1f8ee87ca1ec5611b35675cdfd762165 --- ...bility_shortcut_type_software_floating.xml | 68 +++++++++++++++++++ res/values/strings.xml | 4 ++ .../AccessibilityEditDialogUtils.java | 56 +++++++-------- ...ccessibilityGestureNavigationTutorial.java | 42 +++--------- .../ToggleFeaturePreferenceFragment.java | 16 ++--- ...ScreenMagnificationPreferenceFragment.java | 20 +++--- 6 files changed, 124 insertions(+), 82 deletions(-) create mode 100644 res/drawable/accessibility_shortcut_type_software_floating.xml diff --git a/res/drawable/accessibility_shortcut_type_software_floating.xml b/res/drawable/accessibility_shortcut_type_software_floating.xml new file mode 100644 index 00000000000..958201515f1 --- /dev/null +++ b/res/drawable/accessibility_shortcut_type_software_floating.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index a9f860acbad..e9fe090b2f6 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5106,6 +5106,8 @@ Use new accessibility gesture To use this feature, tap the accessibility button %s on the bottom of your screen.\n\nTo switch between features, touch & hold the accessibility button. + + To use this feature, tap the accessibility button on your screen. To use this feature, press & hold both volume keys. @@ -5136,6 +5138,8 @@ Swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold. Swipe up from the bottom of the screen with 3 fingers.\n\nTo switch between features, swipe up with 3 fingers and hold. + + Customize accessibility button Hold volume keys diff --git a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java index f349a125085..6b31988ecff 100644 --- a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java +++ b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java @@ -17,6 +17,7 @@ package com.android.settings.accessibility; import android.app.Dialog; +import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.content.res.TypedArray; @@ -24,6 +25,7 @@ import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; +import android.text.method.LinkMovementMethod; import android.text.style.ImageSpan; import android.view.LayoutInflater; import android.view.View; @@ -40,6 +42,8 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import com.android.settings.R; +import com.android.settings.core.SubSettingLauncher; +import com.android.settings.utils.AnnotationSpan; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -253,6 +257,8 @@ public class AccessibilityEditDialogUtils { summary.setVisibility(View.GONE); } else { summary.setText(summaryText); + summary.setMovementMethod(LinkMovementMethod.getInstance()); + summary.setFocusable(false); } final ImageView image = view.findViewById(R.id.image); image.setImageResource(imageResId); @@ -260,10 +266,13 @@ public class AccessibilityEditDialogUtils { private static void initSoftwareShortcut(Context context, View view) { final View dialogView = view.findViewById(R.id.software_shortcut); + final CharSequence title = context.getText( + R.string.accessibility_shortcut_edit_dialog_title_software); final TextView summary = dialogView.findViewById(R.id.summary); final int lineHeight = summary.getLineHeight(); - setupShortcutWidget(dialogView, retrieveTitle(context), - retrieveSummary(context, lineHeight), retrieveImageResId(context)); + + setupShortcutWidget(dialogView, title, retrieveSummary(context, lineHeight), + retrieveImageResId(context)); } private static void initHardwareShortcut(Context context, View view) { @@ -297,35 +306,28 @@ public class AccessibilityEditDialogUtils { }); } - private static CharSequence retrieveTitle(Context context) { - int resId = R.string.accessibility_shortcut_edit_dialog_title_software; - if (AccessibilityUtil.isGestureNavigateEnabled(context)) { - resId = AccessibilityUtil.isTouchExploreEnabled(context) - ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback - : R.string.accessibility_shortcut_edit_dialog_title_software_gesture; - } - return context.getText(resId); - } - private static CharSequence retrieveSummary(Context context, int lineHeight) { - if (AccessibilityUtil.isGestureNavigateEnabled(context)) { - final int resId = AccessibilityUtil.isTouchExploreEnabled(context) - ? R.string.accessibility_shortcut_edit_dialog_summary_software_gesture_talkback - : R.string.accessibility_shortcut_edit_dialog_summary_software_gesture; - return context.getText(resId); - } - return getSummaryStringWithIcon(context, lineHeight); + return AccessibilityUtil.isFloatingMenuEnabled(context) + ? getSummaryStringWithLink(context) : getSummaryStringWithIcon(context, lineHeight); } private static int retrieveImageResId(Context context) { - // TODO(b/142531156): Use vector drawable instead of temporal png file to avoid distorted. - int resId = R.drawable.accessibility_shortcut_type_software; - if (AccessibilityUtil.isGestureNavigateEnabled(context)) { - resId = AccessibilityUtil.isTouchExploreEnabled(context) - ? R.drawable.accessibility_shortcut_type_software_gesture_talkback - : R.drawable.accessibility_shortcut_type_software_gesture; - } - return resId; + return AccessibilityUtil.isFloatingMenuEnabled(context) + ? R.drawable.accessibility_shortcut_type_software_floating + : R.drawable.accessibility_shortcut_type_software; + } + + private static CharSequence getSummaryStringWithLink(Context context) { + final View.OnClickListener linkListener = v -> new SubSettingLauncher(context) + .setDestination(AccessibilityButtonFragment.class.getName()) + .setSourceMetricsCategory( + SettingsEnums.SWITCH_SHORTCUT_DIALOG_ACCESSIBILITY_BUTTON_SETTINGS) + .launch(); + final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo( + AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION, linkListener); + + return AnnotationSpan.linkify(context.getText( + R.string.accessibility_shortcut_edit_dialog_summary_software_floating), linkInfo); } private static SpannableString getSummaryStringWithIcon(Context context, int lineHeight) { diff --git a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java index 482822e4f66..5ea5462c0c8 100644 --- a/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java +++ b/src/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.java @@ -333,7 +333,8 @@ public final class AccessibilityGestureNavigationTutorial { } private static TutorialPage createSoftwareTutorialPage(@NonNull Context context) { - final CharSequence title = getSoftwareTitle(context); + final CharSequence title = context.getText( + R.string.accessibility_tutorial_dialog_title_button); final ImageView image = createSoftwareImage(context); final CharSequence instruction = getSoftwareInstruction(context); final ImageView indicatorIcon = @@ -390,44 +391,19 @@ public final class AccessibilityGestureNavigationTutorial { return tutorialPages; } - private static CharSequence getSoftwareTitle(Context context) { - final boolean isGestureNavigationEnabled = - AccessibilityUtil.isGestureNavigateEnabled(context); - final int resId = isGestureNavigationEnabled - ? R.string.accessibility_tutorial_dialog_title_gesture - : R.string.accessibility_tutorial_dialog_title_button; - - return context.getText(resId); - } - private static ImageView createSoftwareImage(Context context) { - int resId = R.drawable.accessibility_shortcut_type_software; - if (AccessibilityUtil.isGestureNavigateEnabled(context)) { - resId = AccessibilityUtil.isTouchExploreEnabled(context) - ? R.drawable.accessibility_shortcut_type_software_gesture_talkback - : R.drawable.accessibility_shortcut_type_software_gesture; - } + final int resId = AccessibilityUtil.isFloatingMenuEnabled(context) + ? R.drawable.accessibility_shortcut_type_software_floating + : R.drawable.accessibility_shortcut_type_software; return createImageView(context, resId); } private static CharSequence getSoftwareInstruction(Context context) { - final boolean isGestureNavigateEnabled = - AccessibilityUtil.isGestureNavigateEnabled(context); - final boolean isTouchExploreEnabled = AccessibilityUtil.isTouchExploreEnabled(context); - int resId = R.string.accessibility_tutorial_dialog_message_button; - if (isGestureNavigateEnabled) { - resId = isTouchExploreEnabled - ? R.string.accessibility_tutorial_dialog_message_gesture_talkback - : R.string.accessibility_tutorial_dialog_message_gesture; - } - - CharSequence text = context.getText(resId); - if (resId == R.string.accessibility_tutorial_dialog_message_button) { - text = getSoftwareInstructionWithIcon(context, text); - } - - return text; + return AccessibilityUtil.isFloatingMenuEnabled(context) + ? context.getText(R.string.accessibility_tutorial_dialog_message_floating_button) + : getSoftwareInstructionWithIcon(context, + context.getText(R.string.accessibility_tutorial_dialog_message_button)); } private static CharSequence getSoftwareInstructionWithIcon(Context context, CharSequence text) { diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index ec22a28aeef..cf9c08b73fd 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -608,19 +608,15 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context, mComponentName.flattenToString(), UserShortcutType.SOFTWARE); - int resId = R.string.accessibility_shortcut_edit_summary_software; - if (AccessibilityUtil.isGestureNavigateEnabled(context)) { - resId = AccessibilityUtil.isTouchExploreEnabled(context) - ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback - : R.string.accessibility_shortcut_edit_dialog_title_software_gesture; - } - final CharSequence softwareTitle = context.getText(resId); - List list = new ArrayList<>(); - if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { + final List list = new ArrayList<>(); + final CharSequence softwareTitle = context.getText( + R.string.accessibility_shortcut_edit_summary_software); + + if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) { list.add(softwareTitle); } - if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { + if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) { final CharSequence hardwareTitle = context.getText( R.string.accessibility_shortcut_hardware_keyword); list.add(hardwareTitle); diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index dde5be17d74..738d284bda0 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -226,27 +226,23 @@ public class ToggleScreenMagnificationPreferenceFragment extends return context.getText(R.string.switch_off_text); } - final int shortcutType = PreferredShortcuts.retrieveUserShortcutType(context, + final int shortcutTypes = PreferredShortcuts.retrieveUserShortcutType(context, MAGNIFICATION_CONTROLLER_NAME, UserShortcutType.SOFTWARE); - int resId = R.string.accessibility_shortcut_edit_summary_software; - if (AccessibilityUtil.isGestureNavigateEnabled(context)) { - resId = AccessibilityUtil.isTouchExploreEnabled(context) - ? R.string.accessibility_shortcut_edit_dialog_title_software_gesture_talkback - : R.string.accessibility_shortcut_edit_dialog_title_software_gesture; - } - final CharSequence softwareTitle = context.getText(resId); - List list = new ArrayList<>(); - if ((shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { + final List list = new ArrayList<>(); + final CharSequence softwareTitle = context.getText( + R.string.accessibility_shortcut_edit_summary_software); + + if (hasShortcutType(shortcutTypes, UserShortcutType.SOFTWARE)) { list.add(softwareTitle); } - if ((shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { + if (hasShortcutType(shortcutTypes, UserShortcutType.HARDWARE)) { final CharSequence hardwareTitle = context.getText( R.string.accessibility_shortcut_hardware_keyword); list.add(hardwareTitle); } - if ((shortcutType & UserShortcutType.TRIPLETAP) == UserShortcutType.TRIPLETAP) { + if (hasShortcutType(shortcutTypes, UserShortcutType.TRIPLETAP)) { final CharSequence tripleTapTitle = context.getText( R.string.accessibility_shortcut_triple_tap_keyword); list.add(tripleTapTitle); From e2c69bcd7b90a77c13e8938932117fd53793a386 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 11 Mar 2021 22:27:26 +0800 Subject: [PATCH 14/28] Remove the accessibility gesture tutorial dialog in system navigation Accessibility gesture is replaced by the accessibility floating menu, remove the accessibility gesture tutorial dialog when choosing to use gesture navigation mode. cherry picked from commit 1a0e2b1be52849a0c91dcc1a907910592ddc3f0d Bug: 173990914 Test: manual test Change-Id: Iae5297747594fcc73fc9bc14537c8fdecb86b660 Merged-In: Iae5297747594fcc73fc9bc14537c8fdecb86b660 --- .../SystemNavigationGestureSettings.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java index 14fe6a664be..388d87ae9a9 100644 --- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java +++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java @@ -30,15 +30,12 @@ import android.content.om.OverlayInfo; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; -import android.text.TextUtils; import android.util.FeatureFlagUtils; -import android.view.accessibility.AccessibilityManager; import androidx.annotation.VisibleForTesting; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.SettingsTutorialDialogWrapperActivity; import com.android.settings.core.FeatureFlags; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.overlay.FeatureFactory; @@ -188,12 +185,7 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i protected boolean setDefaultKey(String key) { setCurrentSystemNavigationMode(mOverlayManager, key); setIllustrationVideo(mVideoPreference, key); - if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, key) && ( - isAnyServiceSupportAccessibilityButton() || isNavBarMagnificationEnabled())) { - Intent intent = new Intent(getActivity(), SettingsTutorialDialogWrapperActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } + return true; } @@ -267,18 +259,6 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i } } - private boolean isAnyServiceSupportAccessibilityButton() { - final AccessibilityManager ams = getContext().getSystemService(AccessibilityManager.class); - final List targets = ams.getAccessibilityShortcutTargets( - AccessibilityManager.ACCESSIBILITY_BUTTON); - return !targets.isEmpty(); - } - - private boolean isNavBarMagnificationEnabled() { - return Settings.Secure.getInt(getContext().getContentResolver(), - Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED, 0) == 1; - } - public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.system_navigation_gesture_settings) { From 799ead4d4146ae8651e22c1a6cc1261f9cac82f1 Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 11 Mar 2021 22:37:34 +0800 Subject: [PATCH 15/28] Update the vector drawable for accessibility button preview preference cherry picked from commit 96121b3f0d7e48f08f9373f56d158300d03dd4cd Bug: 173940869 Test: manual test Change-Id: Id24d1550e7c640a7fdbd752e3571296a7e6567d6 Merged-In: Id24d1550e7c640a7fdbd752e3571296a7e6567d6 --- .../accessibility_button_navigation.xml | 89 +++++++++---------- .../accessibility_button_preview_base.xml | 39 ++++---- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/res/drawable/accessibility_button_navigation.xml b/res/drawable/accessibility_button_navigation.xml index 30273fb4e1f..82e3c70174f 100644 --- a/res/drawable/accessibility_button_navigation.xml +++ b/res/drawable/accessibility_button_navigation.xml @@ -19,52 +19,49 @@ android:height="153dp" android:viewportWidth="125" android:viewportHeight="153"> + + + + + + - - - - - - - - - - - - - - + android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"/> + - \ No newline at end of file + + + + + + + diff --git a/res/drawable/accessibility_button_preview_base.xml b/res/drawable/accessibility_button_preview_base.xml index 0712b9508b1..9e3ec598586 100644 --- a/res/drawable/accessibility_button_preview_base.xml +++ b/res/drawable/accessibility_button_preview_base.xml @@ -19,27 +19,24 @@ android:height="153dp" android:viewportWidth="125" android:viewportHeight="153"> + + + + + + - - - - - - - - - + android:pathData="M12.4,-61L112.6,-61A5.4,5.4 0,0 1,118 -55.6L118,140.6A5.4,5.4 0,0 1,112.6 146L12.4,146A5.4,5.4 0,0 1,7 140.6L7,-55.6A5.4,5.4 0,0 1,12.4 -61z"/> + - \ No newline at end of file + + From 9a5925c471ffb801923d4bd0e20daa9311fdc09b Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 11 Mar 2021 23:08:02 +0800 Subject: [PATCH 16/28] Remove half circle option in size selector Half circle accessibility floating menu mode changed to be triggered from gesture. cherry picked from commit c2057ae257514987270fbf7f1f69fc958ea88881 Bug: 173940869 Test: atest FloatingMenuSizePreferenceControllerTest Change-Id: I123baaf3684d5cbb0a33fc2383da72aa022876c0 Merged-In: I123baaf3684d5cbb0a33fc2383da72aa022876c0 --- res/values/arrays.xml | 3 -- .../FloatingMenuSizePreferenceController.java | 46 +------------------ ...atingMenuSizePreferenceControllerTest.java | 25 ---------- 3 files changed, 2 insertions(+), 72 deletions(-) diff --git a/res/values/arrays.xml b/res/values/arrays.xml index 2d03c11227e..2057c50626f 100644 --- a/res/values/arrays.xml +++ b/res/values/arrays.xml @@ -985,7 +985,6 @@ Small Large - Half Circle @@ -994,8 +993,6 @@ 0 1 - - 2 diff --git a/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java b/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java index b4fa495f071..2f0f833772e 100644 --- a/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java +++ b/src/com/android/settings/accessibility/FloatingMenuSizePreferenceController.java @@ -59,24 +59,11 @@ public class FloatingMenuSizePreferenceController extends BasePreferenceControll @IntDef({ Size.SMALL, Size.LARGE, - Size.EDGE }) @VisibleForTesting @interface Size { int SMALL = 0; int LARGE = 1; - int EDGE = 2; - } - - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - EdgeMode.FULL_CIRCLE, - EdgeMode.HALF_CIRCLE, - }) - @VisibleForTesting - @interface EdgeMode { - int FULL_CIRCLE = 0; - int HALF_CIRCLE = 1; } public FloatingMenuSizePreferenceController(Context context, String preferenceKey) { @@ -110,7 +97,7 @@ public class FloatingMenuSizePreferenceController extends BasePreferenceControll final ListPreference listPreference = (ListPreference) preference; final Integer value = Ints.tryParse((String) newValue); if (value != null) { - writeToFloatingMenuSettings(value); + putAccessibilityFloatingMenuSize(value); updateState(listPreference); } return true; @@ -121,7 +108,7 @@ public class FloatingMenuSizePreferenceController extends BasePreferenceControll super.updateState(preference); final ListPreference listPreference = (ListPreference) preference; - listPreference.setValue(getCurrentAccessibilityButtonSize()); + listPreference.setValue(String.valueOf(getAccessibilityFloatingMenuSize(mDefaultSize))); } @Override @@ -157,24 +144,6 @@ public class FloatingMenuSizePreferenceController extends BasePreferenceControll } } - private void writeToFloatingMenuSettings(@Size int sizeValue) { - if (sizeValue == Size.EDGE) { - putAccessibilityFloatingMenuSize(Size.SMALL); - putAccessibilityFloatingMenuIconType(EdgeMode.HALF_CIRCLE); - } else { - putAccessibilityFloatingMenuSize(sizeValue); - putAccessibilityFloatingMenuIconType(EdgeMode.FULL_CIRCLE); - } - } - - private String getCurrentAccessibilityButtonSize() { - final @EdgeMode int iconType = getAccessibilityFloatingMenuIconType(EdgeMode.FULL_CIRCLE); - final @Size int btnSize = getAccessibilityFloatingMenuSize(mDefaultSize); - - return (iconType == EdgeMode.HALF_CIRCLE) - ? String.valueOf(Size.EDGE) : String.valueOf(btnSize); - } - @Size private int getAccessibilityFloatingMenuSize(@Size int defaultValue) { return Settings.Secure.getInt(mContentResolver, @@ -185,15 +154,4 @@ public class FloatingMenuSizePreferenceController extends BasePreferenceControll Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, value); } - - @EdgeMode - private int getAccessibilityFloatingMenuIconType(@EdgeMode int defaultValue) { - return Settings.Secure.getInt(mContentResolver, - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, defaultValue); - } - - private void putAccessibilityFloatingMenuIconType(@EdgeMode int value) { - Settings.Secure.putInt(mContentResolver, - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, value); - } } diff --git a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java index 70257ca6931..4d7d98d7aff 100644 --- a/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/FloatingMenuSizePreferenceControllerTest.java @@ -84,9 +84,6 @@ public class FloatingMenuSizePreferenceControllerTest { public void updateState_floatingMenuLargeSizeAndFullCircle_largeSizeValue() { Settings.Secure.putInt(mContentResolver, Settings.Secure.ACCESSIBILITY_FLOATING_MENU_SIZE, FloatingMenuSizePreferenceController.Size.LARGE); - Settings.Secure.putInt(mContentResolver, - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, - FloatingMenuSizePreferenceController.EdgeMode.FULL_CIRCLE); mController.updateState(mListPreference); @@ -94,28 +91,6 @@ public class FloatingMenuSizePreferenceControllerTest { assertThat(mListPreference.getValue()).isEqualTo(largeSize); } - @Test - public void updateState_floatingMenuHalfCircle_edgeSizeValue() { - Settings.Secure.putInt(mContentResolver, - Settings.Secure.ACCESSIBILITY_FLOATING_MENU_ICON_TYPE, - FloatingMenuSizePreferenceController.EdgeMode.HALF_CIRCLE); - - mController.updateState(mListPreference); - - final String edgeSize = String.valueOf(FloatingMenuSizePreferenceController.Size.EDGE); - assertThat(mListPreference.getValue()).isEqualTo(edgeSize); - } - - @Test - public void onPreferenceChange_floatingMenuEdgeSize_edgeSizeValue() { - final String edgeSize = String.valueOf( - FloatingMenuSizePreferenceController.Size.EDGE); - - mController.onPreferenceChange(mListPreference, edgeSize); - - assertThat(mListPreference.getValue()).isEqualTo(edgeSize); - } - @Test public void onChange_a11yBtnModeChangeToNavigationBar_preferenceDisabled() { mController.mPreference = mListPreference; From d507dc19b1b9f0362c54ee8667eb0a51169bb794 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 16 Mar 2021 17:03:31 +0800 Subject: [PATCH 17/28] Replace hidden CM#isNetworkSupported() usage It's a refactor work for connectivity mainline module. The hidden methods access is no longer allowed, so the usage for isNetworkSupported() should be replaced. Settings use it to check if device support telephony, wifi or ethernet service. There are alternative methods to check if device supports such features. Replace as it is. Bug: 172183305 Test: m ; make RunSettingsRoboTests Change-Id: I8f1d11558b1be575a0777ed195abe027e838cb74 Merged-In: I8f1d11558b1be575a0777ed195abe027e838cb74 --- .../android/settings/SettingsDumpService.java | 13 +++++---- .../settings/datausage/DataUsageUtils.java | 28 +++++++++---------- .../CellularDataConditionController.java | 6 +--- .../datausage/BillingCycleSettingsTest.java | 11 ++++---- ...aUsageSummaryPreferenceControllerTest.java | 14 +++++----- .../datausage/DataUsageUtilsTest.java | 14 +++++----- ...MobileNetworkPreferenceControllerTest.java | 10 ++----- .../MobileNetworkSummaryControllerTest.java | 10 ++----- 8 files changed, 45 insertions(+), 61 deletions(-) diff --git a/src/com/android/settings/SettingsDumpService.java b/src/com/android/settings/SettingsDumpService.java index 2b6c7d87f89..5e6ee9307a7 100644 --- a/src/com/android/settings/SettingsDumpService.java +++ b/src/com/android/settings/SettingsDumpService.java @@ -14,13 +14,15 @@ package com.android.settings; +import static android.content.pm.PackageManager.FEATURE_ETHERNET; +import static android.content.pm.PackageManager.FEATURE_WIFI; + import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.net.ConnectivityManager; import android.net.NetworkTemplate; import android.net.Uri; import android.os.IBinder; @@ -101,10 +103,10 @@ public class SettingsDumpService extends Service { private JSONObject dumpDataUsage() throws JSONException { JSONObject obj = new JSONObject(); DataUsageController controller = new DataUsageController(this); - ConnectivityManager connectivityManager = getSystemService(ConnectivityManager.class); SubscriptionManager manager = this.getSystemService(SubscriptionManager.class); TelephonyManager telephonyManager = this.getSystemService(TelephonyManager.class); - if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)) { + final PackageManager packageManager = this.getPackageManager(); + if (telephonyManager.isDataCapable()) { JSONArray array = new JSONArray(); for (SubscriptionInfo info : manager.getAvailableSubscriptionInfoList()) { telephonyManager = telephonyManager @@ -117,10 +119,11 @@ public class SettingsDumpService extends Service { } obj.put("cell", array); } - if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_WIFI)) { + if (packageManager.hasSystemFeature(FEATURE_WIFI)) { obj.put("wifi", dumpDataUsage(NetworkTemplate.buildTemplateWifiWildcard(), controller)); } - if (connectivityManager.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) { + + if (packageManager.hasSystemFeature(FEATURE_ETHERNET)) { obj.put("ethernet", dumpDataUsage(NetworkTemplate.buildTemplateEthernet(), controller)); } return obj; diff --git a/src/com/android/settings/datausage/DataUsageUtils.java b/src/com/android/settings/datausage/DataUsageUtils.java index da0ca63b22b..7da69cb9352 100644 --- a/src/com/android/settings/datausage/DataUsageUtils.java +++ b/src/com/android/settings/datausage/DataUsageUtils.java @@ -14,13 +14,14 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.content.pm.PackageManager.FEATURE_ETHERNET; +import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.telephony.TelephonyManager.SIM_STATE_READY; import android.app.usage.NetworkStats.Bucket; import android.app.usage.NetworkStatsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.NetworkTemplate; import android.os.RemoteException; @@ -69,8 +70,7 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU return SystemProperties.get(DataUsageUtils.TEST_RADIOS_PROP).contains(ETHERNET); } - final ConnectivityManager conn = context.getSystemService(ConnectivityManager.class); - if (!conn.isNetworkSupported(ConnectivityManager.TYPE_ETHERNET)) { + if (!context.getPackageManager().hasSystemFeature(FEATURE_ETHERNET)) { return false; } @@ -96,10 +96,8 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU * TODO: This is the opposite to Utils.isWifiOnly(), it should be refactored into 1 method. */ public static boolean hasMobileData(Context context) { - final ConnectivityManager connectivityManager = - context.getSystemService(ConnectivityManager.class); - return connectivityManager != null && connectivityManager - .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + final TelephonyManager tele = context.getSystemService(TelephonyManager.class); + return tele.isDataCapable(); } /** @@ -128,12 +126,13 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU Log.d(TAG, "hasReadyMobileRadio: subInfo=" + subInfo); } } - final ConnectivityManager conn = context.getSystemService(ConnectivityManager.class); - final boolean retVal = conn.isNetworkSupported(TYPE_MOBILE) && isReady; + + final boolean isDataCapable = tele.isDataCapable(); + final boolean retVal = isDataCapable && isReady; if (LOGD) { Log.d(TAG, "hasReadyMobileRadio:" - + " conn.isNetworkSupported(TYPE_MOBILE)=" - + conn.isNetworkSupported(TYPE_MOBILE) + + " telephonManager.isDataCapable()=" + + isDataCapable + " isReady=" + isReady); } return retVal; @@ -147,9 +146,8 @@ public final class DataUsageUtils extends com.android.settingslib.net.DataUsageU return SystemProperties.get(TEST_RADIOS_PROP).contains("wifi"); } - final ConnectivityManager connectivityManager = - context.getSystemService(ConnectivityManager.class); - return connectivityManager != null && connectivityManager.isNetworkSupported(TYPE_WIFI); + final PackageManager packageManager = context.getPackageManager(); + return packageManager != null && packageManager.hasSystemFeature(FEATURE_WIFI); } /** diff --git a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java index 4c0ddc9aa91..9c936b9c08e 100644 --- a/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java +++ b/src/com/android/settings/homepage/contextualcards/conditional/CellularDataConditionController.java @@ -19,7 +19,6 @@ package com.android.settings.homepage.contextualcards.conditional; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; import android.telephony.PhoneStateListener; import android.telephony.PreciseDataConnectionState; import android.telephony.SubscriptionManager; @@ -39,7 +38,6 @@ public class CellularDataConditionController implements ConditionalCardControlle private final Context mAppContext; private final ConditionManager mConditionManager; private final GlobalSettingsChangeListener mDefaultDataSubscriptionIdListener; - private final ConnectivityManager mConnectivityManager; private int mSubId; private TelephonyManager mTelephonyManager; @@ -63,8 +61,6 @@ public class CellularDataConditionController implements ConditionalCardControlle } } }; - mConnectivityManager = appContext.getSystemService( - ConnectivityManager.class); } @Override @@ -74,7 +70,7 @@ public class CellularDataConditionController implements ConditionalCardControlle @Override public boolean isDisplayable() { - if (!mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + if (!mTelephonyManager.isDataCapable() || mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_READY) { return false; } diff --git a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java index 3fdb7b4d256..861b4e395fa 100644 --- a/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/BillingCycleSettingsTest.java @@ -36,8 +36,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; +import android.content.pm.PackageManager; import android.content.res.Resources; -import android.net.ConnectivityManager; import android.net.NetworkPolicyManager; import android.os.Bundle; @@ -72,9 +72,9 @@ public class BillingCycleSettingsTest { @Mock private NetworkPolicyEditor mNetworkPolicyEditor; @Mock - private ConnectivityManager mConnectivityManager; - @Mock private NetworkPolicyManager mNetworkPolicyManager; + @Mock + private PackageManager mMockPackageManager; private Context mContext; @Mock @@ -157,9 +157,8 @@ public class BillingCycleSettingsTest { .onCreatePreferences(any(Bundle.class), nullable(String.class)); when(mContext.getSystemService(Context.NETWORK_POLICY_SERVICE)) .thenReturn(mNetworkPolicyManager); - when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) - .thenReturn(mConnectivityManager); - when(mConnectivityManager.isNetworkSupported(anyInt())).thenReturn(true); + when(mContext.getPackageManager()).thenReturn(mMockPackageManager); + when(mMockPackageManager.hasSystemFeature(any())).thenReturn(true); final SwitchPreference preference = mock(SwitchPreference.class); when(billingCycleSettings.findPreference(anyString())).thenReturn(preference); diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java index 4a5bc700b1d..6a7f2374380 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java @@ -16,13 +16,14 @@ package com.android.settings.datausage; -import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.content.pm.PackageManager.FEATURE_WIFI; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -31,7 +32,7 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; +import android.content.pm.PackageManager; import android.net.NetworkTemplate; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -104,7 +105,7 @@ public class DataUsageSummaryPreferenceControllerTest { @Mock private TelephonyManager mTelephonyManager; @Mock - private ConnectivityManager mConnectivityManager; + private PackageManager mPm; private DataUsageInfoController mDataInfoController; @@ -138,10 +139,9 @@ public class DataUsageSummaryPreferenceControllerTest { doReturn(mTelephonyManager).when(mActivity).getSystemService(TelephonyManager.class); doReturn(mTelephonyManager).when(mTelephonyManager) .createForSubscriptionId(mDefaultSubscriptionId); - when(mActivity.getSystemService(Context.CONNECTIVITY_SERVICE)) - .thenReturn(mConnectivityManager); + doReturn(mPm).when(mActivity).getPackageManager(); + doReturn(false).when(mPm).hasSystemFeature(eq(FEATURE_WIFI)); doReturn(TelephonyManager.SIM_STATE_READY).when(mTelephonyManager).getSimState(); - when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(false); mController = spy(new DataUsageSummaryPreferenceController( mDataUsageController, @@ -363,7 +363,7 @@ public class DataUsageSummaryPreferenceControllerTest { final int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; mController.init(subscriptionId); mController.mDataUsageController = mDataUsageController; - when(mConnectivityManager.isNetworkSupported(TYPE_WIFI)).thenReturn(true); + doReturn(true).when(mPm).hasSystemFeature(eq(FEATURE_WIFI)); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java index 21f9d1a3ab3..a465d742356 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageUtilsTest.java @@ -18,14 +18,15 @@ package com.android.settings.datausage; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; import android.app.usage.NetworkStatsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.telephony.TelephonyManager; import android.util.DataUnit; @@ -38,12 +39,11 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowPackageManager; @RunWith(RobolectricTestRunner.class) public final class DataUsageUtilsTest { - @Mock - private ConnectivityManager mManager; @Mock private TelephonyManager mTelephonyManager; @Mock @@ -56,21 +56,20 @@ public final class DataUsageUtilsTest { MockitoAnnotations.initMocks(this); final ShadowApplication shadowContext = ShadowApplication.getInstance(); mContext = RuntimeEnvironment.application; - shadowContext.setSystemService(Context.CONNECTIVITY_SERVICE, mManager); shadowContext.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager); shadowContext.setSystemService(Context.NETWORK_STATS_SERVICE, mNetworkStatsManager); } @Test public void mobileDataStatus_whenNetworkIsSupported() { - when(mManager.isNetworkSupported(anyInt())).thenReturn(true); + when(mTelephonyManager.isDataCapable()).thenReturn(true); final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); assertThat(hasMobileData).isTrue(); } @Test public void mobileDataStatus_whenNetworkIsNotSupported() { - when(mManager.isNetworkSupported(anyInt())).thenReturn(false); + when(mTelephonyManager.isDataCapable()).thenReturn(false); final boolean hasMobileData = DataUsageUtils.hasMobileData(mContext); assertThat(hasMobileData).isFalse(); } @@ -85,7 +84,8 @@ public final class DataUsageUtilsTest { @Test public void hasEthernet_shouldQueryEthernetSummaryForUser() throws Exception { - when(mManager.isNetworkSupported(anyInt())).thenReturn(true); + ShadowPackageManager pm = shadowOf(RuntimeEnvironment.application.getPackageManager()); + pm.setSystemFeature(PackageManager.FEATURE_ETHERNET, true); final String subscriber = "TestSub"; when(mTelephonyManager.getSubscriberId()).thenReturn(subscriber); diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java index 6d46f9c6074..8256f3519cd 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkPreferenceControllerTest.java @@ -28,7 +28,6 @@ import static org.mockito.Mockito.when; import static org.robolectric.shadow.api.Shadow.extract; import android.content.Context; -import android.net.ConnectivityManager; import android.os.UserManager; import android.provider.Settings; import android.provider.Settings.Global; @@ -88,9 +87,7 @@ public class MobileNetworkPreferenceControllerTest { public void secondaryUser_prefIsNotAvailable() { ShadowUserManager userManager = extract(mContext.getSystemService(UserManager.class)); userManager.setIsAdminUser(false); - ShadowConnectivityManager connectivityManager = - extract(mContext.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true); + when(mTelephonyManager.isDataCapable()).thenReturn(true); mController = new MobileNetworkPreferenceController(mContext); assertThat(mController.isAvailable()).isFalse(); @@ -100,10 +97,7 @@ public class MobileNetworkPreferenceControllerTest { public void wifiOnly_prefIsNotAvailable() { ShadowUserManager userManager = extract(mContext.getSystemService(UserManager.class)); userManager.setIsAdminUser(true); - ShadowConnectivityManager connectivityManager = - extract(mContext.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false); - + when(mTelephonyManager.isDataCapable()).thenReturn(false); mController = new MobileNetworkPreferenceController(mContext); assertThat(mController.isAvailable()).isFalse(); } diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java index f6bc05a418c..bf8dcda3dd9 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java @@ -31,7 +31,6 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; import android.os.UserManager; import android.provider.Settings; import android.telephony.SubscriptionInfo; @@ -107,9 +106,7 @@ public class MobileNetworkSummaryControllerTest { @Test public void isAvailable_wifiOnlyMode_notAvailable() { - final ConnectivityManager cm = mock(ConnectivityManager.class); - when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(false); - when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm); + when(mTelephonyManager.isDataCapable()).thenReturn(false); when(mUserManager.isAdminUser()).thenReturn(true); assertThat(mController.isAvailable()).isFalse(); @@ -117,11 +114,8 @@ public class MobileNetworkSummaryControllerTest { @Test public void isAvailable_secondaryUser_notAvailable() { - final ConnectivityManager cm = mock(ConnectivityManager.class); - when(cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE)).thenReturn(true); - when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(cm); + when(mTelephonyManager.isDataCapable()).thenReturn(true); when(mUserManager.isAdminUser()).thenReturn(false); - assertThat(mController.isAvailable()).isFalse(); } From d5029fc823dc056aebd2d4191a88effe42b6e7bc Mon Sep 17 00:00:00 2001 From: sallyyuen Date: Tue, 16 Mar 2021 11:56:35 -0700 Subject: [PATCH 18/28] Update RBC UI with latest strings Get rid of the slider (no longer need labels) Test: Manual Bug: 182922255 Change-Id: Ib3d0c8ad823af55848f2526f3377ff11b4196f54 --- .../preference_labeled_continuous_slider.xml | 68 ------------------- res/values/strings.xml | 16 ++--- res/xml/reduce_bright_colors_settings.xml | 7 +- ...eReduceBrightColorsPreferenceFragment.java | 2 + .../LabeledContinuousSeekBarPreference.java | 44 ------------ 5 files changed, 11 insertions(+), 126 deletions(-) delete mode 100644 res/layout/preference_labeled_continuous_slider.xml delete mode 100644 src/com/android/settings/widget/LabeledContinuousSeekBarPreference.java diff --git a/res/layout/preference_labeled_continuous_slider.xml b/res/layout/preference_labeled_continuous_slider.xml deleted file mode 100644 index 00e87964e0d..00000000000 --- a/res/layout/preference_labeled_continuous_slider.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index 7e10006638d..c3fdfa07884 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5334,15 +5334,17 @@ Blue-yellow - - Reduce brightness + + Extra dim + + Make screen extra dim - Make screen darker than your phone\u2019s minimum brightness + Dim screen beyond your phone\u2019s minimum brightness - Make screen darker than your tablet\u2019s minimum brightness + Dim screen beyond your tablet\u2019s minimum brightness -
+
This can be helpful when:
  1. \u00a0Your phone\u2019s default minimum brightness is still too bright
  2. @@ -5362,10 +5364,6 @@ Intensity - - Slightly darker - - Darkest Keep on after device restarts diff --git a/res/xml/reduce_bright_colors_settings.xml b/res/xml/reduce_bright_colors_settings.xml index 17e8b021fbd..b9ca8549204 100644 --- a/res/xml/reduce_bright_colors_settings.xml +++ b/res/xml/reduce_bright_colors_settings.xml @@ -17,16 +17,13 @@ - + android:title="@string/reduce_bright_colors_intensity_preference_title"/> Date: Wed, 17 Mar 2021 10:38:56 -0700 Subject: [PATCH 19/28] Hide non-system overlay windows in RequestIgnoreBatteryOptimizations. Add SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS to SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS. Bug: 182165099 Test: manual (test PoC) Change-Id: Iddf697c1e8945f49c6222605c67f8f98e9c418a9 --- .../fuelgauge/RequestIgnoreBatteryOptimizations.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java b/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java index c06a4ffba1f..f75fccc0efb 100644 --- a/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java +++ b/src/com/android/settings/fuelgauge/RequestIgnoreBatteryOptimizations.java @@ -93,6 +93,13 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity implements setupAlert(); } + @Override + protected void onStart() { + super.onStart(); + getWindow().addSystemFlags(android.view.WindowManager.LayoutParams + .SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); + } + @Override public void onClick(DialogInterface dialog, int which) { switch (which) { From 887273b2c6eef01bd0b797525cb4b05ce734f77d Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 17 Mar 2021 14:07:51 -0400 Subject: [PATCH 20/28] Refinements for DND settings - Adding headers - Remove collapsed 'advanced - correcting label for main toggle - fix underline Test: manual Fixes: 179210702 Fixes: 173910494 Change-Id: Iec67639a12c7e93dcf19d415108e7d2c1fcb93d4 --- res/values/strings.xml | 9 +++++++-- res/xml/zen_mode_settings.xml | 18 ++++++++++-------- .../zen/ZenModeButtonPreferenceController.java | 3 +++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 7e10006638d..b26982986da 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8189,7 +8189,7 @@ Do Not Disturb is on for %s with custom settings. - View custom settings + View custom settings Priority only @@ -8247,6 +8247,9 @@ Duration for Quick Settings + + General When Do Not Disturb is on, sound and vibration will be muted, except for the items you allow above. @@ -12808,7 +12811,9 @@ Use battery saver - Use Do Not Disturb + Turn off now + + Turn on now Use Night Light diff --git a/res/xml/zen_mode_settings.xml b/res/xml/zen_mode_settings.xml index 78dee028666..10b3e415b4d 100644 --- a/res/xml/zen_mode_settings.xml +++ b/res/xml/zen_mode_settings.xml @@ -23,7 +23,6 @@ - + + + + android:title="@string/zen_settings_general" + android:key="zen_mode_settings_advanced"> Date: Sat, 13 Mar 2021 20:17:58 -0800 Subject: [PATCH 21/28] Remove references to BatteryStatsHelper from AppBatteryPreferenceController Bug: 173745486 Bug: 180630447 Test: make RunSettingsRoboTests Test: male RunSettingsGoogleRoboTests Change-Id: Ic836d9f5e791d1e3ddc2237ff108190e53dcac19 --- .../AppBatteryPreferenceController.java | 55 +------------------ .../AppBatteryPreferenceControllerTest.java | 45 +++++---------- 2 files changed, 15 insertions(+), 85 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java index 5f1d9d2a52d..6d515a31363 100644 --- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java @@ -30,14 +30,11 @@ import androidx.loader.content.Loader; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.fuelgauge.AdvancedPowerUsageDetail; import com.android.settings.fuelgauge.BatteryEntry; -import com.android.settings.fuelgauge.BatteryStatsHelperLoader; import com.android.settings.fuelgauge.BatteryUsageStatsLoader; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -52,22 +49,11 @@ public class AppBatteryPreferenceController extends BasePreferenceController private static final String KEY_BATTERY = "battery"; - // TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to - // BatteryStatsHelper and BatterySipper - @VisibleForTesting - final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks = - new BatteryStatsHelperLoaderCallbacks(); @VisibleForTesting final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks = new BatteryUsageStatsLoaderCallbacks(); - - @VisibleForTesting - BatterySipper mSipper; - @VisibleForTesting - BatteryStatsHelper mBatteryHelper; @VisibleForTesting BatteryUtils mBatteryUtils; - @VisibleForTesting BatteryUsageStats mBatteryUsageStats; @VisibleForTesting @@ -124,9 +110,6 @@ public class AppBatteryPreferenceController extends BasePreferenceController @Override public void onResume() { - mParent.getLoaderManager().restartLoader( - AppInfoDashboardFragment.LOADER_BATTERY, Bundle.EMPTY, - mBatteryStatsHelperLoaderCallbacks); mParent.getLoaderManager().restartLoader( AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS, Bundle.EMPTY, mBatteryUsageStatsLoaderCallbacks); @@ -134,20 +117,17 @@ public class AppBatteryPreferenceController extends BasePreferenceController @Override public void onPause() { - mParent.getLoaderManager().destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY); mParent.getLoaderManager().destroyLoader( AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS); } private void onLoadFinished() { - // Wait for both loaders to finish before proceeding. - if (mBatteryHelper == null || mBatteryUsageStats == null) { + if (mBatteryUsageStats == null) { return; } final PackageInfo packageInfo = mParent.getPackageInfo(); if (packageInfo != null) { - mSipper = findTargetSipper(mBatteryHelper, packageInfo.applicationInfo.uid); mUidBatteryConsumer = findTargetUidBatteryConsumer(mBatteryUsageStats, packageInfo.applicationInfo.uid); if (mParent.getActivity() != null) { @@ -172,19 +152,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController @VisibleForTesting boolean isBatteryStatsAvailable() { - return mBatteryHelper != null && mSipper != null && mUidBatteryConsumer != null; - } - - @VisibleForTesting - BatterySipper findTargetSipper(BatteryStatsHelper batteryHelper, int uid) { - final List usageList = batteryHelper.getUsageList(); - for (int i = 0, size = usageList.size(); i < size; i++) { - final BatterySipper sipper = usageList.get(i); - if (sipper.getUid() == uid) { - return sipper; - } - } - return null; + return mUidBatteryConsumer != null; } @VisibleForTesting @@ -199,25 +167,6 @@ public class AppBatteryPreferenceController extends BasePreferenceController return null; } - private class BatteryStatsHelperLoaderCallbacks - implements LoaderManager.LoaderCallbacks { - @Override - public Loader onCreateLoader(int id, Bundle args) { - return new BatteryStatsHelperLoader(mContext); - } - - @Override - public void onLoadFinished(Loader loader, - BatteryStatsHelper batteryHelper) { - mBatteryHelper = batteryHelper; - AppBatteryPreferenceController.this.onLoadFinished(); - } - - @Override - public void onLoaderReset(Loader loader) { - } - } - private class BatteryUsageStatsLoaderCallbacks implements LoaderManager.LoaderCallbacks { @Override diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java index 440ad044087..71ab3344b29 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java @@ -30,7 +30,6 @@ import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; -import android.os.BatteryStats; import android.os.BatteryUsageStats; import android.os.Bundle; import android.os.UidBatteryConsumer; @@ -39,15 +38,12 @@ import androidx.loader.app.LoaderManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.SettingsActivity; import com.android.settings.fuelgauge.BatteryUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -73,13 +69,7 @@ public class AppBatteryPreferenceControllerTest { @Mock private UidBatteryConsumer mUidBatteryConsumer; @Mock - private BatterySipper mBatterySipper; - @Mock - private BatterySipper mOtherBatterySipper; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStatsHelper mBatteryStatsHelper; - @Mock - private BatteryStats.Uid mUid; + private UidBatteryConsumer mOtherUidBatteryConsumer; @Mock private PreferenceScreen mScreen; @Mock @@ -102,10 +92,8 @@ public class AppBatteryPreferenceControllerTest { mBatteryPreference = spy(new Preference(RuntimeEnvironment.application)); - mBatterySipper.drainType = BatterySipper.DrainType.IDLE; - mBatterySipper.uidObj = mUid; - doReturn(TARGET_UID).when(mBatterySipper).getUid(); - doReturn(OTHER_UID).when(mOtherBatterySipper).getUid(); + when(mUidBatteryConsumer.getUid()).thenReturn(TARGET_UID); + when(mOtherUidBatteryConsumer.getUid()).thenReturn(OTHER_UID); mController = spy(new AppBatteryPreferenceController( RuntimeEnvironment.application, mFragment, "package1", null /* lifecycle */)); @@ -125,14 +113,14 @@ public class AppBatteryPreferenceControllerTest { } @Test - public void findTargetSipper_findCorrectSipper() { - final List usageList = new ArrayList<>(); - usageList.add(mBatterySipper); - usageList.add(mOtherBatterySipper); - when(mBatteryStatsHelper.getUsageList()).thenReturn(usageList); + public void findTargetBatteryConsumer_findCorrectBatteryConsumer() { + final List uidBatteryConsumers = new ArrayList<>(); + uidBatteryConsumers.add(mUidBatteryConsumer); + uidBatteryConsumers.add(mOtherUidBatteryConsumer); + when(mBatteryUsageStats.getUidBatteryConsumers()).thenReturn(uidBatteryConsumers); - assertThat(mController.findTargetSipper(mBatteryStatsHelper, TARGET_UID)) - .isEqualTo(mBatterySipper); + assertThat(mController.findTargetUidBatteryConsumer(mBatteryUsageStats, TARGET_UID)) + .isEqualTo(mUidBatteryConsumer); } @Test @@ -147,13 +135,10 @@ public class AppBatteryPreferenceControllerTest { @Test public void updateBattery_hasBatteryStats_summaryPercent() { - mController.mBatteryHelper = mBatteryStatsHelper; - mController.mSipper = mBatterySipper; mController.mBatteryUsageStats = mBatteryUsageStats; mController.mUidBatteryConsumer = mUidBatteryConsumer; doReturn(BATTERY_LEVEL).when(mBatteryUtils).calculateBatteryPercent(anyDouble(), anyDouble(), anyInt()); - doReturn(new ArrayList<>()).when(mBatteryStatsHelper).getUsageList(); mController.displayPreference(mScreen); mController.updateBattery(); @@ -163,8 +148,6 @@ public class AppBatteryPreferenceControllerTest { @Test public void isBatteryStatsAvailable_hasBatteryStatsHelperAndSipper_returnTrue() { - mController.mBatteryHelper = mBatteryStatsHelper; - mController.mSipper = mBatterySipper; mController.mBatteryUsageStats = mBatteryUsageStats; mController.mUidBatteryConsumer = mUidBatteryConsumer; @@ -183,8 +166,6 @@ public class AppBatteryPreferenceControllerTest { when(mFragment.getActivity()).thenReturn(mActivity); final String key = mController.getPreferenceKey(); when(mBatteryPreference.getKey()).thenReturn(key); - mController.mSipper = mBatterySipper; - mController.mBatteryHelper = mBatteryStatsHelper; mController.mBatteryUsageStats = mBatteryUsageStats; mController.mUidBatteryConsumer = mUidBatteryConsumer; @@ -199,8 +180,8 @@ public class AppBatteryPreferenceControllerTest { mController.onResume(); verify(mLoaderManager) - .restartLoader(AppInfoDashboardFragment.LOADER_BATTERY, Bundle.EMPTY, - mController.mBatteryStatsHelperLoaderCallbacks); + .restartLoader(AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS, Bundle.EMPTY, + mController.mBatteryUsageStatsLoaderCallbacks); } @Test @@ -209,6 +190,6 @@ public class AppBatteryPreferenceControllerTest { mController.onPause(); - verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY); + verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_BATTERY_USAGE_STATS); } } From 8f6c946c821011df0d80d7e5bad2f42526423a34 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Sat, 13 Mar 2021 20:31:17 -0800 Subject: [PATCH 22/28] Transition HighUsageDetector to BatteryUsageStats API Bug: 173745486 Test: make RunSettingsRoboTests Test: male RunSettingsGoogleRoboTests Change-Id: Ie8f90a67e4dd16fa67cf4f44a3678a789b3da18a --- .../settings/fuelgauge/BatteryUtils.java | 56 ++---------- .../settings/fuelgauge/PowerUsageSummary.java | 2 +- .../batterytip/BatteryTipLoader.java | 10 +-- .../detectors/HighUsageDetector.java | 46 +++++----- .../slices/BatteryFixSlice.java | 11 +-- .../settings/fuelgauge/BatteryUtilsTest.java | 90 ++----------------- .../batterytip/BatteryTipLoaderTest.java | 6 +- .../detectors/HighUsageDetectorTest.java | 55 +++++------- .../slices/BatteryFixSliceTest.java | 13 ++- 9 files changed, 84 insertions(+), 205 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java index d3633b1b92e..661c1ea3c34 100644 --- a/src/com/android/settings/fuelgauge/BatteryUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryUtils.java @@ -42,7 +42,6 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; -import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.util.ArrayUtils; import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; @@ -173,22 +172,12 @@ public class BatteryUtils { } /** - * Check whether we should hide the battery sipper. + * Returns true if the specified battery consumer should be excluded from the summary + * battery consumption list. */ - public boolean shouldHideSipper(BatterySipper sipper) { - final BatterySipper.DrainType drainType = sipper.drainType; - - return drainType == BatterySipper.DrainType.IDLE - || drainType == BatterySipper.DrainType.CELL - || drainType == BatterySipper.DrainType.SCREEN - || drainType == BatterySipper.DrainType.UNACCOUNTED - || drainType == BatterySipper.DrainType.OVERCOUNTED - || drainType == BatterySipper.DrainType.BLUETOOTH - || drainType == BatterySipper.DrainType.WIFI - || (sipper.totalPowerMah * SECONDS_IN_HOUR) < MIN_POWER_THRESHOLD_MILLI_AMP - || mPowerUsageFeatureProvider.isTypeService(sipper) - || mPowerUsageFeatureProvider.isTypeSystem(sipper) - || isHiddenSystemModule(sipper); + public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer) { + return shouldHideUidBatteryConsumer(consumer, + mPackageManager.getPackagesForUid(consumer.getUid())); } /** @@ -227,17 +216,6 @@ public class BatteryUtils { } } - /** - * Return {@code true} if one of packages in {@code sipper} is hidden system modules - */ - public boolean isHiddenSystemModule(BatterySipper sipper) { - if (sipper.uidObj == null) { - return false; - } - sipper.mPackages = mPackageManager.getPackagesForUid(sipper.getUid()); - return isHiddenSystemModule(sipper.mPackages); - } - /** * Returns true if one the specified packages belongs to a hidden system module. */ @@ -270,23 +248,6 @@ public class BatteryUtils { return (powerUsageMah / totalPowerMah) * dischargeAmount; } - /** - * Calculate the whole running time in the state {@code statsType} - * - * @param batteryStatsHelper utility class that contains the data - * @param statsType state that we want to calculate the time for - * @return the running time in millis - */ - public long calculateRunningTimeBasedOnStatsType(BatteryStatsHelper batteryStatsHelper, - int statsType) { - final long elapsedRealtimeUs = PowerUtil.convertMsToUs( - SystemClock.elapsedRealtime()); - // Return the battery time (millisecond) on status mStatsType - return PowerUtil.convertUsToMs( - batteryStatsHelper.getStats().computeBatteryRealtime(elapsedRealtimeUs, statsType)); - - } - /** * Find the package name for a {@link android.os.BatteryStats.Uid} * @@ -336,14 +297,13 @@ public class BatteryUtils { /** * Calculate the time since last full charge, including the device off time * - * @param batteryStatsHelper utility class that contains the data + * @param batteryUsageStats class that contains the data * @param currentTimeMs current wall time * @return time in millis */ - public long calculateLastFullChargeTime(BatteryStatsHelper batteryStatsHelper, + public long calculateLastFullChargeTime(BatteryUsageStats batteryUsageStats, long currentTimeMs) { - return currentTimeMs - batteryStatsHelper.getStats().getStartClockTime(); - + return currentTimeMs - batteryUsageStats.getStatsStartRealtime(); } public static void logRuntime(String tag, String message, long startTime) { diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index 4f8ac628092..9e619973122 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -108,7 +108,7 @@ public class PowerUsageSummary extends PowerUsageBase implements @Override public Loader> onCreateLoader(int id, Bundle args) { - return new BatteryTipLoader(getContext(), mStatsHelper); + return new BatteryTipLoader(getContext(), mBatteryUsageStats); } @Override diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index 9b80a1f4029..433c06d0220 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -17,10 +17,10 @@ package com.android.settings.fuelgauge.batterytip; import android.content.Context; +import android.os.BatteryUsageStats; import androidx.annotation.VisibleForTesting; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.fuelgauge.BatteryInfo; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector; @@ -48,13 +48,13 @@ public class BatteryTipLoader extends AsyncLoaderCompat> { private static final boolean USE_FAKE_DATA = false; - private BatteryStatsHelper mBatteryStatsHelper; + private BatteryUsageStats mBatteryUsageStats; @VisibleForTesting BatteryUtils mBatteryUtils; - public BatteryTipLoader(Context context, BatteryStatsHelper batteryStatsHelper) { + public BatteryTipLoader(Context context, BatteryUsageStats batteryUsageStats) { super(context); - mBatteryStatsHelper = batteryStatsHelper; + mBatteryUsageStats = batteryUsageStats; mBatteryUtils = BatteryUtils.getInstance(context); } @@ -69,7 +69,7 @@ public class BatteryTipLoader extends AsyncLoaderCompat> { final Context context = getContext(); tips.add(new LowBatteryDetector(context, policy, batteryInfo).detect()); - tips.add(new HighUsageDetector(context, policy, mBatteryStatsHelper, batteryInfo).detect()); + tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect()); tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect()); tips.add(new EarlyWarningDetector(policy, context).detect()); tips.add(new BatteryDefenderDetector(batteryInfo).detect()); diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java index 6c102fb5d4d..4b3f2df3a7f 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetector.java @@ -19,12 +19,11 @@ package com.android.settings.fuelgauge.batterytip.detectors; import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; import android.content.Context; -import android.os.BatteryStats; +import android.os.BatteryUsageStats; +import android.os.UidBatteryConsumer; import androidx.annotation.VisibleForTesting; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.fuelgauge.BatteryInfo; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batterytip.AppInfo; @@ -34,7 +33,6 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -44,7 +42,7 @@ import java.util.concurrent.TimeUnit; */ public class HighUsageDetector implements BatteryTipDetector { private BatteryTipPolicy mPolicy; - private BatteryStatsHelper mBatteryStatsHelper; + private BatteryUsageStats mBatteryUsageStats; private final BatteryInfo mBatteryInfo; private List mHighUsageAppList; @VisibleForTesting @@ -55,9 +53,9 @@ public class HighUsageDetector implements BatteryTipDetector { boolean mDischarging; public HighUsageDetector(Context context, BatteryTipPolicy policy, - BatteryStatsHelper batteryStatsHelper, BatteryInfo batteryInfo) { + BatteryUsageStats batteryUsageStats, BatteryInfo batteryInfo) { mPolicy = policy; - mBatteryStatsHelper = batteryStatsHelper; + mBatteryUsageStats = batteryUsageStats; mBatteryInfo = batteryInfo; mHighUsageAppList = new ArrayList<>(); mBatteryUtils = BatteryUtils.getInstance(context); @@ -69,37 +67,35 @@ public class HighUsageDetector implements BatteryTipDetector { @Override public BatteryTip detect() { final long lastFullChargeTimeMs = mBatteryUtils.calculateLastFullChargeTime( - mBatteryStatsHelper, System.currentTimeMillis()); + mBatteryUsageStats, System.currentTimeMillis()); if (mPolicy.highUsageEnabled && mDischarging) { parseBatteryData(); if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) { - final BatteryStats batteryStats = mBatteryStatsHelper.getStats(); - final List batterySippers - = new ArrayList<>(mBatteryStatsHelper.getUsageList()); - final double totalPower = mBatteryStatsHelper.getTotalPower(); - final int dischargeAmount = batteryStats != null - ? batteryStats.getDischargeAmount(BatteryStats.STATS_SINCE_CHARGED) - : 0; - - Collections.sort(batterySippers, - (sipper1, sipper2) -> Double.compare(sipper2.totalSmearedPowerMah, - sipper1.totalSmearedPowerMah)); - for (BatterySipper batterySipper : batterySippers) { + final double totalPower = mBatteryUsageStats.getConsumedPower(); + final int dischargeAmount = mBatteryUsageStats.getDischargePercentage(); + final List uidBatteryConsumers = + mBatteryUsageStats.getUidBatteryConsumers(); + // Sort by descending power + uidBatteryConsumers.sort( + (consumer1, consumer2) -> Double.compare(consumer2.getConsumedPower(), + consumer1.getConsumedPower())); + for (UidBatteryConsumer consumer : uidBatteryConsumers) { final double percent = mBatteryUtils.calculateBatteryPercent( - batterySipper.totalSmearedPowerMah, totalPower, dischargeAmount); - if ((percent + 0.5f < 1f) || mBatteryUtils.shouldHideSipper(batterySipper)) { + consumer.getConsumedPower(), totalPower, dischargeAmount); + if ((percent + 0.5f < 1f) + || mBatteryUtils.shouldHideUidBatteryConsumer(consumer)) { // Don't show it if we should hide or usage percentage is lower than 1% continue; } + mHighUsageAppList.add(new AppInfo.Builder() - .setUid(batterySipper.getUid()) + .setUid(consumer.getUid()) .setPackageName( - mBatteryUtils.getPackageName(batterySipper.getUid())) + mBatteryUtils.getPackageName(consumer.getUid())) .build()); if (mHighUsageAppList.size() >= mPolicy.highUsageAppCount) { break; } - } // When in test mode, add an app if necessary diff --git a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java index 6a5b3000bc8..94d3f69ed2f 100644 --- a/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java +++ b/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSlice.java @@ -29,6 +29,7 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.BatteryUsageStats; import android.util.ArrayMap; import android.view.View; @@ -40,11 +41,10 @@ import androidx.slice.builders.ListBuilder; import androidx.slice.builders.ListBuilder.RowBuilder; import androidx.slice.builders.SliceAction; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.SubSettings; import com.android.settings.Utils; -import com.android.settings.fuelgauge.BatteryStatsHelperLoader; +import com.android.settings.fuelgauge.BatteryUsageStatsLoader; import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; @@ -206,9 +206,10 @@ public class BatteryFixSlice implements CustomSliceable { @WorkerThread @VisibleForTesting static List refreshBatteryTips(Context context) { - final BatteryStatsHelperLoader statsLoader = new BatteryStatsHelperLoader(context); - final BatteryStatsHelper statsHelper = statsLoader.loadInBackground(); - final BatteryTipLoader loader = new BatteryTipLoader(context, statsHelper); + final BatteryUsageStatsLoader statsLoader = new BatteryUsageStatsLoader(context, + /* includeBatteryHistory */ false); + final BatteryUsageStats batteryUsageStats = statsLoader.loadInBackground(); + final BatteryTipLoader loader = new BatteryTipLoader(context, batteryUsageStats); final List batteryTips = loader.loadInBackground(); for (BatteryTip batteryTip : batteryTips) { if (batteryTip.getState() != BatteryTip.StateType.INVISIBLE) { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java index 2d22a12a7e8..4c2d5edc43e 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java @@ -46,6 +46,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.BatteryStats; import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; import android.os.Build; import android.os.Bundle; import android.os.Process; @@ -120,6 +121,8 @@ public class BatteryUtilsTest { @Mock private BatteryStats.Timer mTimer; @Mock + private BatteryUsageStats mBatteryUsageStats; + @Mock private SystemBatteryConsumer mSystemBatteryConsumer; @Mock private BatterySipper mNormalBatterySipper; @@ -336,81 +339,6 @@ public class BatteryUtilsTest { assertThat(mBatteryUtils.shouldHideSystemBatteryConsumer(mSystemBatteryConsumer)).isFalse(); } - @Test - public void testShouldHideSipper_TypeUnAccounted_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeOverAccounted_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeIdle_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.IDLE; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeCell_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.CELL; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeScreen_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.SCREEN; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeWifi_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.WIFI; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeBluetooth_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH; - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_TypeSystem_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - when(mNormalBatterySipper.getUid()).thenReturn(Process.ROOT_UID); - when(mProvider.isTypeSystem(any())).thenReturn(true); - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_UidNormal_ReturnFalse() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - when(mNormalBatterySipper.getUid()).thenReturn(UID); - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isFalse(); - } - - @Test - public void testShouldHideSipper_TypeService_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - when(mNormalBatterySipper.getUid()).thenReturn(UID); - when(mProvider.isTypeService(any())).thenReturn(true); - - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - - @Test - public void testShouldHideSipper_hiddenSystemModule_ReturnTrue() { - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - when(mNormalBatterySipper.getUid()).thenReturn(UID); - when(mBatteryUtils.isHiddenSystemModule(mNormalBatterySipper)).thenReturn(true); - - assertThat(mBatteryUtils.shouldHideSipper(mNormalBatterySipper)).isTrue(); - } - @Test public void testCalculateBatteryPercent() { assertThat(mBatteryUtils.calculateBatteryPercent(BATTERY_SYSTEM_USAGE, TOTAL_BATTERY_USAGE, @@ -418,20 +346,14 @@ public class BatteryUtilsTest { .isWithin(PRECISION).of(PERCENT_SYSTEM_USAGE); } - @Test - public void testCalculateRunningTimeBasedOnStatsType() { - assertThat(mBatteryUtils.calculateRunningTimeBasedOnStatsType(mBatteryStatsHelper, - BatteryStats.STATS_SINCE_CHARGED)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS); - } - @Test public void testCalculateLastFullChargeTime() { final long currentTimeMs = System.currentTimeMillis(); - when(mBatteryStatsHelper.getStats().getStartClockTime()).thenReturn( + when(mBatteryUsageStats.getStatsStartRealtime()).thenReturn( currentTimeMs - TIME_SINCE_LAST_FULL_CHARGE_MS); - assertThat(mBatteryUtils.calculateLastFullChargeTime( - mBatteryStatsHelper, currentTimeMs)).isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS); + assertThat(mBatteryUtils.calculateLastFullChargeTime(mBatteryUsageStats, currentTimeMs)) + .isEqualTo(TIME_SINCE_LAST_FULL_CHARGE_MS); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java index c97d79ff2a1..82448d138d9 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java @@ -24,9 +24,9 @@ import static org.mockito.Mockito.spy; import android.content.Context; import android.content.Intent; +import android.os.BatteryUsageStats; import android.os.PowerManager; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.fuelgauge.BatteryInfo; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate; @@ -57,7 +57,7 @@ public class BatteryTipLoaderTest { BatteryTip.TipType.SUMMARY, BatteryTip.TipType.SMART_BATTERY_MANAGER}; @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStatsHelper mBatteryStatsHelper; + private BatteryUsageStats mBatteryUsageStats; @Mock private PowerManager mPowerManager; @Mock @@ -78,7 +78,7 @@ public class BatteryTipLoaderTest { doReturn(mPowerManager).when(mContext).getSystemService(Context.POWER_SERVICE); doReturn(mIntent).when(mContext).registerReceiver(any(), any()); doReturn(mBatteryInfo).when(mBatteryUtils).getBatteryInfo(any()); - mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryStatsHelper); + mBatteryTipLoader = new BatteryTipLoader(mContext, mBatteryUsageStats); mBatteryTipLoader.mBatteryUtils = mBatteryUtils; } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java index 93005d51093..c12587622c6 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/HighUsageDetectorTest.java @@ -19,23 +19,20 @@ package com.android.settings.fuelgauge.batterytip.detectors; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; -import android.os.BatteryStats; +import android.os.BatteryManager; import android.os.BatteryStatsManager; import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; +import android.os.UidBatteryConsumer; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.batterytip.AppInfo; import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy; @@ -46,7 +43,6 @@ import com.android.settings.fuelgauge.batterytip.tips.HighUsageTip; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -64,15 +60,14 @@ public class HighUsageDetectorTest { private static final int UID_LOW = 345; private static final double POWER_HIGH = 20000; private static final double POWER_LOW = 10000; + private Context mContext; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStatsHelper mBatteryStatsHelper; @Mock - private BatterySipper mHighBatterySipper; + private UidBatteryConsumer mHighBatteryConsumer; @Mock - private BatterySipper mLowBatterySipper; + private UidBatteryConsumer mLowBatteryConsumer; @Mock - private BatterySipper mSystemBatterySipper; + private UidBatteryConsumer mSystemBatteryConsumer; @Mock private HighUsageDataParser mDataParser; @Mock @@ -85,7 +80,6 @@ public class HighUsageDetectorTest { private BatteryTipPolicy mPolicy; private BatteryUtils mBatteryUtils; private HighUsageDetector mHighUsageDetector; - private List mUsageList; @Before public void setUp() { @@ -100,27 +94,22 @@ public class HighUsageDetectorTest { when(mBatteryStatsManager.getBatteryUsageStats(any(BatteryUsageStatsQuery.class))) .thenReturn(mBatteryUsageStats); - mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED)); + mContext.sendStickyBroadcast(new Intent(Intent.ACTION_BATTERY_CHANGED) + .putExtra(BatteryManager.EXTRA_PLUGGED, 0)); - mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryStatsHelper, + mHighUsageDetector = spy(new HighUsageDetector(mContext, mPolicy, mBatteryUsageStats, mBatteryUtils.getBatteryInfo(TAG))); mHighUsageDetector.mBatteryUtils = mBatteryUtils; mHighUsageDetector.mDataParser = mDataParser; doNothing().when(mHighUsageDetector).parseBatteryData(); - doReturn(UID_HIGH).when(mHighBatterySipper).getUid(); - doReturn(UID_LOW).when(mLowBatterySipper).getUid(); - mHighBatterySipper.uidObj = mock(BatteryStats.Uid.class); - mHighBatterySipper.drainType = BatterySipper.DrainType.APP; - mHighBatterySipper.totalSmearedPowerMah = POWER_HIGH; - mLowBatterySipper.uidObj = mock(BatteryStats.Uid.class); - mLowBatterySipper.drainType = BatterySipper.DrainType.APP; - mLowBatterySipper.totalSmearedPowerMah = POWER_LOW; - when(mBatteryUtils.shouldHideSipper(mSystemBatterySipper)).thenReturn(true); - when(mBatteryUtils.shouldHideSipper(mHighBatterySipper)).thenReturn(false); - when(mBatteryUtils.shouldHideSipper(mLowBatterySipper)).thenReturn(false); - when(mBatteryStatsHelper.getStats().getDischargeAmount(anyInt())).thenReturn(100); - when(mBatteryStatsHelper.getTotalPower()).thenReturn(POWER_HIGH + POWER_LOW); - + doReturn(UID_HIGH).when(mHighBatteryConsumer).getUid(); + doReturn(UID_LOW).when(mLowBatteryConsumer).getUid(); + doReturn(POWER_HIGH).when(mHighBatteryConsumer).getConsumedPower(); + doReturn(POWER_LOW).when(mLowBatteryConsumer).getConsumedPower(); + doReturn(false).when(mBatteryUtils).shouldHideUidBatteryConsumer(mHighBatteryConsumer); + doReturn(false).when(mBatteryUtils).shouldHideUidBatteryConsumer(mLowBatteryConsumer); + when(mBatteryUsageStats.getDischargePercentage()).thenReturn(100); + when(mBatteryUsageStats.getConsumedPower()).thenReturn(POWER_HIGH + POWER_LOW); mHighAppInfo = new AppInfo.Builder() .setUid(UID_HIGH) @@ -129,11 +118,11 @@ public class HighUsageDetectorTest { .setUid(UID_LOW) .build(); - mUsageList = new ArrayList<>(); - mUsageList.add(mSystemBatterySipper); - mUsageList.add(mLowBatterySipper); - mUsageList.add(mHighBatterySipper); - when(mBatteryStatsHelper.getUsageList()).thenReturn(mUsageList); + ArrayList consumers = new ArrayList<>(); + consumers.add(mSystemBatteryConsumer); + consumers.add(mLowBatteryConsumer); + consumers.add(mHighBatteryConsumer); + when(mBatteryUsageStats.getUidBatteryConsumers()).thenReturn(consumers); } @Test diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java index 68c97cfd0d4..d64d098aa87 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.net.Uri; +import android.os.BatteryUsageStats; import androidx.slice.Slice; import androidx.slice.SliceMetadata; @@ -32,6 +33,7 @@ import androidx.slice.widget.SliceLiveData; import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.fuelgauge.BatteryStatsHelperLoader; +import com.android.settings.fuelgauge.BatteryUsageStatsLoader; import com.android.settings.fuelgauge.batterytip.AppInfo; import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; @@ -57,7 +59,7 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, + BatteryFixSliceTest.ShadowBatteryUsageStatsLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public class BatteryFixSliceTest { @@ -144,6 +146,15 @@ public class BatteryFixSliceTest { } } + @Implements(BatteryUsageStatsLoader.class) + public static class ShadowBatteryUsageStatsLoader { + + @Implementation + protected BatteryUsageStats loadInBackground() { + return null; + } + } + @Implements(BatteryTipLoader.class) public static class ShadowBatteryTipLoader { From 5f2cf8e695063130529683a0201a600c99e58332 Mon Sep 17 00:00:00 2001 From: Kunhung Li Date: Mon, 15 Mar 2021 09:48:22 +0800 Subject: [PATCH 23/28] Clear WallpaperPicker task before launch There are different launch sources to start WallpaperPicker, clear previous task to prevent keeping old activity. Bug: 177638480 Test: make RunSettingsRoboTests Change-Id: Ia4d3d5c7e5df4a5d3acb137f644939c079d5028f --- .../TopLevelWallpaperPreferenceController.java | 2 +- ...opLevelWallpaperPreferenceControllerTest.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java index 5118b277b59..7b3d788d5ef 100644 --- a/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java +++ b/src/com/android/settings/display/TopLevelWallpaperPreferenceController.java @@ -105,7 +105,7 @@ public class TopLevelWallpaperPreferenceController extends BasePreferenceControl final Intent intent = new Intent().setComponent( getComponentName()).putExtra(mWallpaperLaunchExtra, LAUNCHED_SETTINGS); if (areStylesAvailable()) { - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); } preference.getContext().startActivity(intent); return true; diff --git a/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java index 7b3ae659c33..6ad99745748 100644 --- a/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/TopLevelWallpaperPreferenceControllerTest.java @@ -202,4 +202,20 @@ public class TopLevelWallpaperPreferenceControllerTest { assertThat(Shadows.shadowOf(mContext).getNextStartedActivityForResult() .intent.hasExtra("com.android.wallpaper.LAUNCH_SOURCE")).isTrue(); } + + @Test + public void handlePreferenceTreeClick_launchClearTask() { + mShadowPackageManager.setResolveInfosForIntent( + mWallpaperIntent, Lists.newArrayList()); + mShadowPackageManager.setResolveInfosForIntent( + mStylesAndWallpaperIntent, Lists.newArrayList(mock(ResolveInfo.class))); + + Preference preference = new Preference(mContext); + preference.setKey(TEST_KEY); + + mController.handlePreferenceTreeClick(preference); + + assertThat((Shadows.shadowOf(mContext).getNextStartedActivityForResult() + .intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TASK) != 0).isTrue(); + } } From 313dbc0355e9b281c03085058d566a83f7782805 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Mon, 15 Mar 2021 14:58:45 -0700 Subject: [PATCH 24/28] Remove references to BatteryStatsHelper from PowerUsageBase Bug: 180630447 Bug: 173745486 Test: make RunSettingsRoboTests Test: male RunSettingsGoogleRoboTests Change-Id: Ifed69c4fdd741f75b0b962f9d3200f0ed533358f --- .../fuelgauge/BatteryStatsHelperLoader.java | 57 ------------ .../settings/fuelgauge/PowerUsageBase.java | 40 --------- .../accounts/AvatarViewMixinTest.java | 1 - .../BatteryBroadcastReceiverTest.java | 6 -- .../BatteryStatsHelperLoaderTest.java | 64 -------------- .../BatteryUsageStatsLoaderTest.java | 86 +++++++++++++++++++ .../fuelgauge/PowerUsageBaseTest.java | 8 -- .../fuelgauge/PowerUsageSummaryTest.java | 42 --------- .../SettingsHomepageActivityTest.java | 2 - .../slices/BatteryFixSliceTest.java | 11 --- 10 files changed, 86 insertions(+), 231 deletions(-) delete mode 100644 src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java delete mode 100644 tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java diff --git a/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java b/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java deleted file mode 100644 index 5de83d3f429..00000000000 --- a/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2017 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.fuelgauge; - -import android.content.Context; -import android.os.UserManager; - -import androidx.annotation.VisibleForTesting; - -import com.android.internal.os.BatteryStatsHelper; -import com.android.settingslib.utils.AsyncLoaderCompat; - -/** - * Loader to get new {@link BatteryStatsHelper} in the background - */ -public class BatteryStatsHelperLoader extends AsyncLoaderCompat { - @VisibleForTesting - UserManager mUserManager; - @VisibleForTesting - BatteryUtils mBatteryUtils; - - public BatteryStatsHelperLoader(Context context) { - super(context); - mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); - mBatteryUtils = BatteryUtils.getInstance(context); - } - - @Override - public BatteryStatsHelper loadInBackground() { - Context context = getContext(); - final BatteryStatsHelper statsHelper = new BatteryStatsHelper(context, - true /* collectBatteryBroadcast */); - mBatteryUtils.initBatteryStatsHelper(statsHelper, null /* bundle */, mUserManager); - - return statsHelper; - } - - @Override - protected void onDiscardResult(BatteryStatsHelper result) { - - } - -} diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java index 29ecedc2f10..28d77159938 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageBase.java +++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java @@ -29,7 +29,6 @@ import androidx.annotation.VisibleForTesting; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.dashboard.DashboardFragment; /** @@ -44,10 +43,8 @@ public abstract class PowerUsageBase extends DashboardFragment { private static final String KEY_REFRESH_TYPE = "refresh_type"; private static final String KEY_INCLUDE_HISTORY = "include_history"; - private static final int LOADER_BATTERY_STATS_HELPER = 0; private static final int LOADER_BATTERY_USAGE_STATS = 1; - protected BatteryStatsHelper mStatsHelper; @VisibleForTesting BatteryUsageStats mBatteryUsageStats; @@ -55,12 +52,6 @@ public abstract class PowerUsageBase extends DashboardFragment { private BatteryBroadcastReceiver mBatteryBroadcastReceiver; protected boolean mIsBatteryPresent = true; - // TODO(b/180630447): switch to BatteryUsageStatsLoader and remove all references to - // BatteryStatsHelper and BatterySipper - @VisibleForTesting - final BatteryStatsHelperLoaderCallbacks mBatteryStatsHelperLoaderCallbacks = - new BatteryStatsHelperLoaderCallbacks(); - @VisibleForTesting final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks = new BatteryUsageStatsLoaderCallbacks(); @@ -69,13 +60,11 @@ public abstract class PowerUsageBase extends DashboardFragment { public void onAttach(Activity activity) { super.onAttach(activity); mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE); - mStatsHelper = new BatteryStatsHelper(activity, true); } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mStatsHelper.create(icicle); setHasOptionsMenu(true); mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext()); @@ -103,18 +92,11 @@ public abstract class PowerUsageBase extends DashboardFragment { final Bundle bundle = new Bundle(); bundle.putInt(KEY_REFRESH_TYPE, refreshType); bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded()); - getLoaderManager().restartLoader(LOADER_BATTERY_STATS_HELPER, bundle, - mBatteryStatsHelperLoaderCallbacks); getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle, mBatteryUsageStatsLoaderCallbacks); } private void onLoadFinished(@BatteryUpdateType int refreshType) { - // Wait for both loaders to finish before proceeding. - if (mStatsHelper == null || mBatteryUsageStats == null) { - return; - } - refreshUi(refreshType); } @@ -127,28 +109,6 @@ public abstract class PowerUsageBase extends DashboardFragment { BatteryUtils.logRuntime(TAG, "updatePreference", startTime); } - private class BatteryStatsHelperLoaderCallbacks - implements LoaderManager.LoaderCallbacks { - private int mRefreshType; - - @Override - public Loader onCreateLoader(int id, Bundle args) { - mRefreshType = args.getInt(KEY_REFRESH_TYPE); - return new BatteryStatsHelperLoader(getContext()); - } - - @Override - public void onLoadFinished(Loader loader, - BatteryStatsHelper batteryHelper) { - mStatsHelper = batteryHelper; - PowerUsageBase.this.onLoadFinished(mRefreshType); - } - - @Override - public void onLoaderReset(Loader loader) { - } - } - private class BatteryUsageStatsLoaderCallbacks implements LoaderManager.LoaderCallbacks { private int mRefreshType; diff --git a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java index 02b318fb3bb..534d3c656ef 100644 --- a/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AvatarViewMixinTest.java @@ -120,7 +120,6 @@ public class AvatarViewMixinTest { @Test @Config(qualifiers = "mcc999", shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void onStart_useMockAvatarViewMixin_shouldBeExecuted() { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java index a072988df4c..5f08698b4bd 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java @@ -78,7 +78,6 @@ public class BatteryBroadcastReceiverTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void testOnReceive_batteryLevelChanged_dataUpdated() { @@ -93,7 +92,6 @@ public class BatteryBroadcastReceiverTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void testOnReceive_batteryHealthChanged_dataUpdated() { @@ -108,7 +106,6 @@ public class BatteryBroadcastReceiverTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void onReceive_batteryNotPresent_shouldShowHelpMessage() { @@ -121,7 +118,6 @@ public class BatteryBroadcastReceiverTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void testOnReceive_powerSaveModeChanged_listenerInvoked() { @@ -133,7 +129,6 @@ public class BatteryBroadcastReceiverTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void testOnReceive_batteryDataNotChanged_listenerNotInvoked() { @@ -154,7 +149,6 @@ public class BatteryBroadcastReceiverTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void testRegister_updateBatteryStatus() { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java deleted file mode 100644 index 92a3dc0110c..00000000000 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2017 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.fuelgauge; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.net.ConnectivityManager; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; - -@RunWith(RobolectricTestRunner.class) -public class BatteryStatsHelperLoaderTest { - @Mock - private BatteryUtils mBatteryUtils; - @Mock - private ConnectivityManager mConnectivityManager; - - private Context mContext; - private BatteryStatsHelperLoader mBatteryStatsHelperLoader; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - doReturn(mConnectivityManager).when(mContext).getSystemService( - Context.CONNECTIVITY_SERVICE); - - mBatteryStatsHelperLoader = spy(new BatteryStatsHelperLoader(mContext)); - mBatteryStatsHelperLoader.mBatteryUtils = mBatteryUtils; - } - - @Test - public void testLoadInBackground_loadWithoutBundle() { - when(mBatteryStatsHelperLoader.getContext()).thenReturn(mContext); - mBatteryStatsHelperLoader.loadInBackground(); - - verify(mBatteryUtils).initBatteryStatsHelper(any(), eq(null), any()); - } -} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java new file mode 100644 index 00000000000..8c47ff680bd --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUsageStatsLoaderTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2017 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.fuelgauge; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.BatteryStatsManager; +import android.os.BatteryUsageStats; +import android.os.BatteryUsageStatsQuery; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class BatteryUsageStatsLoaderTest { + private Context mContext; + @Mock + private BatteryStatsManager mBatteryStatsManager; + @Mock + private BatteryUsageStats mBatteryUsageStats; + @Captor + private ArgumentCaptor mUsageStatsQueryCaptor; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + doReturn(mBatteryStatsManager).when(mContext).getSystemService( + Context.BATTERY_STATS_SERVICE); + } + + @Test + public void testLoadInBackground_loadWithoutHistory() { + BatteryUsageStatsLoader loader = new BatteryUsageStatsLoader( + mContext, /* includeBatteryHistory */ false); + + when(mBatteryStatsManager.getBatteryUsageStats(mUsageStatsQueryCaptor.capture())) + .thenReturn(mBatteryUsageStats); + + loader.loadInBackground(); + + final int queryFlags = mUsageStatsQueryCaptor.getValue().getFlags(); + assertThat(queryFlags + & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY).isEqualTo(0); + } + + @Test + public void testLoadInBackground_loadWithHistory() { + BatteryUsageStatsLoader loader = new BatteryUsageStatsLoader( + mContext, /* includeBatteryHistory */ true); + + when(mBatteryStatsManager.getBatteryUsageStats(mUsageStatsQueryCaptor.capture())) + .thenReturn(mBatteryUsageStats); + + loader.loadInBackground(); + + final int queryFlags = mUsageStatsQueryCaptor.getValue().getFlags(); + assertThat(queryFlags + & BatteryUsageStatsQuery.FLAG_BATTERY_USAGE_STATS_INCLUDE_HISTORY).isNotEqualTo(0); + } +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java index 87547008d2f..451e605985b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageBaseTest.java @@ -27,7 +27,6 @@ import android.os.Bundle; import androidx.loader.app.LoaderManager; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.testutils.shadow.ShadowDashboardFragment; import com.android.settingslib.core.AbstractPreferenceController; @@ -45,8 +44,6 @@ import java.util.List; @Config(shadows = ShadowDashboardFragment.class) public class PowerUsageBaseTest { - @Mock - private BatteryStatsHelper mBatteryStatsHelper; @Mock private LoaderManager mLoaderManager; private TestFragment mFragment; @@ -56,7 +53,6 @@ public class PowerUsageBaseTest { MockitoAnnotations.initMocks(this); mFragment = spy(new TestFragment()); - mFragment.setBatteryStatsHelper(mBatteryStatsHelper); doReturn(mLoaderManager).when(mFragment).getLoaderManager(); } @@ -98,9 +94,5 @@ public class PowerUsageBaseTest { protected List createPreferenceControllers(Context context) { return null; } - - private void setBatteryStatsHelper(BatteryStatsHelper batteryStatsHelper) { - mStatsHelper = batteryStatsHelper; - } } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java index e345ab23a27..11b6ad27f94 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java @@ -21,7 +21,6 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -40,8 +39,6 @@ import android.provider.Settings; import androidx.loader.app.LoaderManager; import androidx.preference.PreferenceScreen; -import com.android.internal.os.BatterySipper; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; @@ -54,7 +51,6 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; @@ -62,35 +58,19 @@ import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; -import java.util.ArrayList; import java.util.List; // TODO: Improve this test class so that it starts up the real activity and fragment. @RunWith(RobolectricTestRunner.class) public class PowerUsageSummaryTest { - private static final int UID = 123; - private static final int POWER_MAH = 100; private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000; - private static final long TIME_SINCE_LAST_FULL_CHARGE_US = - TIME_SINCE_LAST_FULL_CHARGE_MS * 1000; - private static final long USAGE_TIME_MS = 65 * 60 * 1000; - private static final double TOTAL_POWER = 200; private static Intent sAdditionalBatteryInfoIntent; @BeforeClass public static void beforeClass() { sAdditionalBatteryInfoIntent = new Intent("com.example.app.ADDITIONAL_BATTERY_INFO"); } - - @Mock - private BatterySipper mNormalBatterySipper; - @Mock - private BatterySipper mScreenBatterySipper; - @Mock - private BatterySipper mCellBatterySipper; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private BatteryStatsHelper mBatteryHelper; @Mock private SettingsActivity mSettingsActivity; @Mock @@ -104,7 +84,6 @@ public class PowerUsageSummaryTest { @Mock private PreferenceScreen mPreferenceScreen; - private List mUsageList; private Context mRealContext; private TestFragment mFragment; private FakeFeatureFactory mFeatureFactory; @@ -123,27 +102,6 @@ public class PowerUsageSummaryTest { when(mFragment.getActivity()).thenReturn(mSettingsActivity); when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent()) .thenReturn(sAdditionalBatteryInfoIntent); - when(mBatteryHelper.getTotalPower()).thenReturn(TOTAL_POWER); - when(mBatteryHelper.getStats().computeBatteryRealtime(anyLong(), anyInt())) - .thenReturn(TIME_SINCE_LAST_FULL_CHARGE_US); - - when(mNormalBatterySipper.getUid()).thenReturn(UID); - mNormalBatterySipper.totalPowerMah = POWER_MAH; - mNormalBatterySipper.drainType = BatterySipper.DrainType.APP; - - mCellBatterySipper.drainType = BatterySipper.DrainType.CELL; - mCellBatterySipper.totalPowerMah = POWER_MAH; - - mScreenBatterySipper.drainType = BatterySipper.DrainType.SCREEN; - mScreenBatterySipper.usageTimeMs = USAGE_TIME_MS; - - mUsageList = new ArrayList<>(); - mUsageList.add(mNormalBatterySipper); - mUsageList.add(mScreenBatterySipper); - mUsageList.add(mCellBatterySipper); - - mFragment.mStatsHelper = mBatteryHelper; - when(mBatteryHelper.getUsageList()).thenReturn(mUsageList); mFragment.mBatteryUtils = spy(new BatteryUtils(mRealContext)); ReflectionHelpers.setField(mFragment, "mVisibilityLoggerMixin", mVisibilityLoggerMixin); ReflectionHelpers.setField(mFragment, "mBatteryBroadcastReceiver", diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 40315d267fb..173f62558c7 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -68,7 +68,6 @@ public class SettingsHomepageActivityTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class }) public void onStart_isNotDebuggable_shouldHideSystemOverlay() { @@ -88,7 +87,6 @@ public class SettingsHomepageActivityTest { @Test @Config(shadows = { - BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class, BatteryFixSliceTest.ShadowBatteryTipLoader.class, }) public void onStop_isNotDebuggable_shouldRemoveHideSystemOverlay() { diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java index d64d098aa87..cffc4d1f55b 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BatteryFixSliceTest.java @@ -30,9 +30,7 @@ import androidx.slice.SliceMetadata; import androidx.slice.SliceProvider; import androidx.slice.widget.SliceLiveData; -import com.android.internal.os.BatteryStatsHelper; import com.android.settings.R; -import com.android.settings.fuelgauge.BatteryStatsHelperLoader; import com.android.settings.fuelgauge.BatteryUsageStatsLoader; import com.android.settings.fuelgauge.batterytip.AppInfo; import com.android.settings.fuelgauge.batterytip.BatteryTipLoader; @@ -137,15 +135,6 @@ public class BatteryFixSliceTest { assertThat(ShadowEarlyWarningTip.isIconTintColorIdCalled()).isTrue(); } - @Implements(BatteryStatsHelperLoader.class) - public static class ShadowBatteryStatsHelperLoader { - - @Implementation - protected BatteryStatsHelper loadInBackground() { - return null; - } - } - @Implements(BatteryUsageStatsLoader.class) public static class ShadowBatteryUsageStatsLoader { From 395f26a66ec528e1f80e03cb326ac2a06056c6c5 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Thu, 18 Mar 2021 14:22:28 +0800 Subject: [PATCH 25/28] Remove grouping from homepage Based on the latest UX design to remove the grouping from homepage. Fixes: 183070484 Test: visual Change-Id: I5834366f37e9198e8830ee67980eabc016d56909 --- res/xml/top_level_settings_grouped.xml | 225 +++++++++++-------------- 1 file changed, 100 insertions(+), 125 deletions(-) diff --git a/res/xml/top_level_settings_grouped.xml b/res/xml/top_level_settings_grouped.xml index d6564b71f93..2c93f3d65dd 100644 --- a/res/xml/top_level_settings_grouped.xml +++ b/res/xml/top_level_settings_grouped.xml @@ -36,149 +36,124 @@ android:title="@string/connected_devices_dashboard_title" settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/> - - + android:title="@string/apps_dashboard_title"/> - - + - - + android:title="@string/power_usage_summary_title" + settings:controller="com.android.settings.fuelgauge.TopLevelBatteryPreferenceController"/> - + - + - + - + - - + - - + android:title="@string/privacy_dashboard_title"/> - + - + - - - - - - + android:fragment="com.android.settings.emergency.EmergencyDashboardFragment"/> - + + - + android:title="@string/header_category_system"/> - + - - + From 6290ad950990a823d5df569d8265265feef65ca0 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 18 Mar 2021 14:13:17 +0800 Subject: [PATCH 26/28] Update mocking to correct target methods The correct target context should use the mActivity in MobileNetworkSettingsTest, so that the mocking for telephony service could correctly applied. Both AutoTimeZonePreferenceControllerTest and BasebandVersionPreferenceControllerTest refer to the lib implemented shadow Connectivitymanager but that does not the correct reference after utils class being updated. Update the test logic inside to refer to correct method. The reference to ShadowConnectivityManager does not needed anymore so remove it from the test. Fix: 183068151 Fix: 183067742 Fix: 183068139 Test: make RunSettingsRoboTests ROBOTEST_FILTER=\ com.android.settings.network.telephony.MobileNetworkSettingsTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=\ com.android.settings.datetime.AutoTimeZonePreferenceControllerTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings\ .deviceinfo.firmwareversion.BasebandVersionPreferenceControllerTest Change-Id: I15ecc6aab7d530d20cd23b06267cc184a2c62b40 --- .../AutoTimeZonePreferenceControllerTest.java | 28 +++++++++---------- ...sebandVersionPreferenceControllerTest.java | 27 ++++++++---------- .../telephony/MobileNetworkSettingsTest.java | 2 +- 3 files changed, 25 insertions(+), 32 deletions(-) diff --git a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java index 8a68f38fcfe..eb29b7ca76e 100644 --- a/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/AutoTimeZonePreferenceControllerTest.java @@ -18,17 +18,16 @@ package com.android.settings.datetime; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import static org.robolectric.shadow.api.Shadow.extract; +import static org.mockito.Mockito.when; import android.content.Context; -import android.net.ConnectivityManager; import android.provider.Settings; +import android.telephony.TelephonyManager; import androidx.preference.Preference; -import com.android.settings.testutils.shadow.ShadowConnectivityManager; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,27 +35,28 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowConnectivityManager.class) public class AutoTimeZonePreferenceControllerTest { @Mock private UpdateTimeAndDateCallback mCallback; - + @Mock private Context mContext; private AutoTimeZonePreferenceController mController; private Preference mPreference; - private ShadowConnectivityManager connectivityManager; + @Mock + private TelephonyManager mTelephonyManager; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); + mPreference = new Preference(mContext); - connectivityManager = extract(mContext.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true); + + when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + when(mTelephonyManager.isDataCapable()).thenReturn(true); } @Test @@ -77,8 +77,7 @@ public class AutoTimeZonePreferenceControllerTest { @Test public void isWifiOnly_notAvailable() { - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false); - + when(mTelephonyManager.isDataCapable()).thenReturn(false); mController = new AutoTimeZonePreferenceController( mContext, null /* callback */, false /* fromSUW */); @@ -95,8 +94,7 @@ public class AutoTimeZonePreferenceControllerTest { @Test public void isWifiOnly_notEnable() { - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false); - + when(mTelephonyManager.isDataCapable()).thenReturn(false); mController = new AutoTimeZonePreferenceController( mContext, null /* callback */, false /* fromSUW */); diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java index 79df2215545..87fdb222c42 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceControllerTest.java @@ -21,44 +21,42 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; -import static org.robolectric.shadow.api.Shadow.extract; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.content.Context; -import android.net.ConnectivityManager; import android.sysprop.TelephonyProperties; - -import com.android.settings.testutils.shadow.ShadowConnectivityManager; +import android.telephony.TelephonyManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; import java.util.Arrays; @RunWith(RobolectricTestRunner.class) -@Config(shadows = ShadowConnectivityManager.class) public class BasebandVersionPreferenceControllerTest { - + @Mock private Context mContext; private BasebandVersionPreferenceController mController; + @Mock + private TelephonyManager mTelephonyManager; @Before public void setup() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); mController = new BasebandVersionPreferenceController(mContext, "key"); + when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); } @Test public void getAvailability_wifiOnly_unavailable() { - final ShadowConnectivityManager connectivityManager = - extract(mContext.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, false); - + when(mTelephonyManager.isDataCapable()).thenReturn(false); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @@ -66,10 +64,7 @@ public class BasebandVersionPreferenceControllerTest { public void getAvailability_hasMobile_available() { final String text = "test"; TelephonyProperties.baseband_version(Arrays.asList(new String[]{text})); - ShadowConnectivityManager connectivityManager = - extract(mContext.getSystemService(ConnectivityManager.class)); - connectivityManager.setNetworkSupported(ConnectivityManager.TYPE_MOBILE, true); - + when(mTelephonyManager.isDataCapable()).thenReturn(true); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java index ea908602e24..44611cec616 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkSettingsTest.java @@ -74,7 +74,7 @@ public class MobileNetworkSettingsTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); + when(mActivity.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager); when(mContext.getSystemService(NetworkStatsManager.class)).thenReturn(mNetworkStatsManager); ShadowEntityHeaderController.setUseMock(mock(EntityHeaderController.class)); From 0e05b2e8ac62911be12a1adcacb0fe321b9697b7 Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Thu, 18 Mar 2021 17:15:23 +0800 Subject: [PATCH 27/28] Remove Advanced category from Network & internet Based on the latest UX design to remove the Advanced category. Fixes: 182742887 Bug: 182237530 Test: robotests & visual Change-Id: Idc184960c3ac74610545c036d5a22959ac6730c1 --- res/xml/network_and_internet.xml | 3 +-- res/xml/network_provider_internet.xml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/res/xml/network_and_internet.xml b/res/xml/network_and_internet.xml index c92ce940758..4a11cbedecc 100644 --- a/res/xml/network_and_internet.xml +++ b/res/xml/network_and_internet.xml @@ -18,8 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:key="network_and_internet_screen" - android:title="@string/network_dashboard_title" - settings:initialExpandedChildrenCount="5"> + android:title="@string/network_dashboard_title"> + android:title="@string/network_dashboard_title"> Date: Thu, 18 Mar 2021 10:17:48 -0700 Subject: [PATCH 28/28] Remove tests for Location Services summary Bug: 183068632 Test: make -j64 RunSettingsRoboTests ROBOTEST_FILTER="com.android.settings.location.LocationServicesPreferenceControllerTest" Change-Id: I9c310ba1c320c182030e5ba7c64099e1b65ea109 --- ...ationServicesPreferenceControllerTest.java | 43 ------------------- 1 file changed, 43 deletions(-) diff --git a/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java index d7d76bef7c7..f5868c2f8ec 100644 --- a/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/location/LocationServicesPreferenceControllerTest.java @@ -19,13 +19,8 @@ package com.android.settings.location; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; import android.content.Context; -import android.net.wifi.WifiManager; -import android.provider.Settings; - -import com.android.settings.R; import org.junit.Before; import org.junit.Test; @@ -39,7 +34,6 @@ import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) public class LocationServicesPreferenceControllerTest { @Mock - private WifiManager mWifiManager; private Context mContext; private LocationServicesPreferenceController mController; @@ -47,7 +41,6 @@ public class LocationServicesPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - when(mContext.getSystemService(WifiManager.class)).thenReturn(mWifiManager); mController = new LocationServicesPreferenceController(mContext, "key"); } @@ -56,42 +49,6 @@ public class LocationServicesPreferenceControllerTest { assertThat(mController.isAvailable()).isTrue(); } - @Test - public void testLocationScanning_WifiOnBleOn() { - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1); - assertThat(mController.getSummary()).isEqualTo( - mContext.getString(R.string.scanning_status_text_wifi_on_ble_on)); - } - - @Test - public void testLocationScanning_WifiOnBleOff() { - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(true); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0); - assertThat(mController.getSummary()).isEqualTo( - mContext.getString(R.string.scanning_status_text_wifi_on_ble_off)); - } - - @Test - public void testLocationScanning_WifiOffBleOn() { - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1); - assertThat(mController.getSummary()).isEqualTo( - mContext.getString(R.string.scanning_status_text_wifi_off_ble_on)); - } - - @Test - public void testLocationScanning_WifiOffBleOff() { - when(mWifiManager.isScanAlwaysAvailable()).thenReturn(false); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0); - assertThat(mController.getSummary()).isEqualTo( - mContext.getString(R.string.scanning_status_text_wifi_off_ble_off)); - } - @Test @Config(qualifiers = "mcc999") public void testLocationScanning_ifDisabled_shouldNotBeShown() {