From 8d50393223338fb6871e492772c9033eb66cc753 Mon Sep 17 00:00:00 2001 From: Daniel Hunt Date: Thu, 22 Apr 2021 17:59:10 +0200 Subject: [PATCH 01/17] Add personal dictionary summary text The resource id 'user_dict_settings_summary' was used to display summary text of personal dictionary in Froyo. But from GingerBread it is not used and an empty string is set. Display above resource as summary text of personal dictionary entry. Bug: 152970252 Test: Manual Change-Id: Ib2d6abe1c128d2c7519be2017880cd2d53c026f3 --- res/values/strings.xml | 2 +- res/xml/language_and_input.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 55043b0ff9a..194dafd4cfc 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4776,7 +4776,7 @@ Personal dictionary for work - "" + Add words to be used in apps such as Spell checker Add diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml index 50968d94558..699d5f419c8 100644 --- a/res/xml/language_and_input.xml +++ b/res/xml/language_and_input.xml @@ -64,6 +64,7 @@ From d1312e8e6eba15590123a43961ef3b978b45949b Mon Sep 17 00:00:00 2001 From: Yanting Yang Date: Wed, 5 May 2021 23:49:06 +0800 Subject: [PATCH 02/17] Add summary back to the homepage Also update some summaries with new strings. Bug: 183586663 Test: robotests & atest & visual Change-Id: I692be9b34e8867501aaa8c8e40428870b99644f8 --- res/layout/homepage_preference.xml | 10 ++ res/xml/top_level_settings_grouped.xml | 28 +++- ...LevelAccountEntryPreferenceController.java | 6 - ...lConnectedDevicesPreferenceController.java | 7 - .../DashboardFeatureProviderImpl.java | 6 - .../TopLevelStoragePreferenceController.java | 7 - ...pLevelAboutDevicePreferenceController.java | 7 - .../TopLevelDisplayPreferenceController.java | 7 - .../TopLevelBatteryPreferenceController.java | 6 - .../TopLevelLocationPreferenceController.java | 7 - ...LevelNetworkEntryPreferenceController.java | 7 - ...evelSecurityEntryPreferenceController.java | 26 ---- ...lAccountEntryPreferenceControllerTest.java | 10 -- ...nectedDevicesPreferenceControllerTest.java | 10 -- .../DashboardFeatureProviderImplTest.java | 27 ---- ...elAboutDevicePreferenceControllerTest.java | 12 -- ...pLevelDisplayPreferenceControllerTest.java | 10 -- ...pLevelBatteryPreferenceControllerTest.java | 11 -- ...LevelLocationPreferenceControllerTest.java | 10 -- ...lNetworkEntryPreferenceControllerTest.java | 10 -- ...SecurityEntryPreferenceControllerTest.java | 143 ------------------ ...pLevelStoragePreferenceControllerTest.java | 10 -- 22 files changed, 33 insertions(+), 344 deletions(-) delete mode 100644 tests/robotests/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java diff --git a/res/layout/homepage_preference.xml b/res/layout/homepage_preference.xml index c08a74f2418..480340a04dc 100644 --- a/res/layout/homepage_preference.xml +++ b/res/layout/homepage_preference.xml @@ -61,5 +61,15 @@ android:singleLine="true" android:textAppearance="@style/TextAppearance.HomepagePreferenceTitle" android:ellipsize="marquee"/> + + \ No newline at end of file diff --git a/res/xml/top_level_settings_grouped.xml b/res/xml/top_level_settings_grouped.xml index df935d03b28..2b29940d803 100644 --- a/res/xml/top_level_settings_grouped.xml +++ b/res/xml/top_level_settings_grouped.xml @@ -26,6 +26,7 @@ android:key="top_level_network" android:order="-150" android:title="@string/network_dashboard_title" + android:summary="@string/summary_placeholder" settings:controller="com.android.settings.network.TopLevelNetworkEntryPreferenceController"/> + android:title="@string/apps_dashboard_title" + android:summary="@string/app_and_notification_dashboard_summary"/> + android:title="@string/configure_notification_settings" + android:summary="@string/notification_dashboard_summary"/> + android:title="@string/sound_settings" + android:summary="@string/sound_dashboard_summary"/> + android:title="@string/privacy_dashboard_title" + android:summary="@string/privacy_dashboard_summary"/> @@ -132,6 +146,7 @@ android:key="top_level_accounts" android:order="-10" android:title="@string/account_dashboard_title" + android:summary="@string/summary_placeholder" settings:controller="com.android.settings.accounts.TopLevelAccountEntryPreferenceController"/> + android:title="@string/header_category_system" + android:summary="@string/system_dashboard_summary"/> diff --git a/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceController.java b/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceController.java index 174ef0f7a92..152bb6733b1 100644 --- a/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceController.java +++ b/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceController.java @@ -17,11 +17,9 @@ package com.android.settings.accounts; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; public class TopLevelAccountEntryPreferenceController extends BasePreferenceController { public TopLevelAccountEntryPreferenceController(Context context, String preferenceKey) { @@ -35,10 +33,6 @@ public class TopLevelAccountEntryPreferenceController extends BasePreferenceCont @Override public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } return mContext.getString(R.string.account_dashboard_default_summary); } } diff --git a/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceController.java b/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceController.java index fac3201e284..fd36bca6338 100644 --- a/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceController.java +++ b/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceController.java @@ -17,11 +17,9 @@ package com.android.settings.connecteddevice; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; public class TopLevelConnectedDevicesPreferenceController extends BasePreferenceController { @@ -38,11 +36,6 @@ public class TopLevelConnectedDevicesPreferenceController extends BasePreference @Override public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } - return mContext.getText( AdvancedConnectedDeviceController.getConnectedDevicesSummaryResourceId(mContext)); } diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java index 92f078ec88a..254a6a7646a 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java @@ -261,12 +261,6 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { } private DynamicDataObserver bindSummaryAndGetObserver(Preference preference, Tile tile) { - // Skip binding homepage tile summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME) - && TextUtils.equals(tile.getCategory(), CategoryKey.CATEGORY_HOMEPAGE)) { - return null; - } - final CharSequence summary = tile.getSummary(mContext); if (summary != null) { preference.setSummary(summary); diff --git a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java index 89d349f44f4..61e5c8474c2 100644 --- a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java +++ b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java @@ -19,14 +19,12 @@ package com.android.settings.deviceinfo; import android.content.Context; import android.os.storage.StorageManager; import android.text.format.Formatter; -import android.util.FeatureFlagUtils; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settingslib.deviceinfo.PrivateStorageInfo; import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; import com.android.settingslib.utils.ThreadUtils; @@ -52,11 +50,6 @@ public class TopLevelStoragePreferenceController extends BasePreferenceControlle @Override protected void refreshSummary(Preference preference) { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return; - } - if (preference == null) { return; } diff --git a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java index 3bda7b9c983..83efcc4028f 100644 --- a/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java +++ b/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceController.java @@ -17,10 +17,8 @@ package com.android.settings.deviceinfo.aboutphone; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settings.deviceinfo.DeviceNamePreferenceController; public class TopLevelAboutDevicePreferenceController extends BasePreferenceController { @@ -36,11 +34,6 @@ public class TopLevelAboutDevicePreferenceController extends BasePreferenceContr @Override public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } - final DeviceNamePreferenceController deviceNamePreferenceController = new DeviceNamePreferenceController(mContext, "unused_key"); return deviceNamePreferenceController.getSummary(); diff --git a/src/com/android/settings/display/TopLevelDisplayPreferenceController.java b/src/com/android/settings/display/TopLevelDisplayPreferenceController.java index cd2dd1307a7..73aafe53453 100644 --- a/src/com/android/settings/display/TopLevelDisplayPreferenceController.java +++ b/src/com/android/settings/display/TopLevelDisplayPreferenceController.java @@ -17,11 +17,9 @@ package com.android.settings.display; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; public class TopLevelDisplayPreferenceController extends BasePreferenceController { @@ -38,11 +36,6 @@ public class TopLevelDisplayPreferenceController extends BasePreferenceControlle @Override public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } - final WallpaperPreferenceController controller = new WallpaperPreferenceController(mContext, "unused_key"); if (controller.isAvailable()) { diff --git a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java index 1912c2fb1e5..99eb05d8116 100644 --- a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java +++ b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java @@ -17,7 +17,6 @@ package com.android.settings.fuelgauge; import android.content.Context; -import android.util.FeatureFlagUtils; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -25,7 +24,6 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; @@ -87,10 +85,6 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle } private CharSequence getSummary(boolean batteryStatusUpdate) { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } // Display help message if battery is not present. if (!mIsBatteryPresent) { return mContext.getText(R.string.battery_missing_message); diff --git a/src/com/android/settings/location/TopLevelLocationPreferenceController.java b/src/com/android/settings/location/TopLevelLocationPreferenceController.java index fe85c7f42b2..ec58a3422d2 100644 --- a/src/com/android/settings/location/TopLevelLocationPreferenceController.java +++ b/src/com/android/settings/location/TopLevelLocationPreferenceController.java @@ -11,7 +11,6 @@ import android.location.LocationManager; import android.os.UserHandle; import android.os.UserManager; import android.permission.PermissionControllerManager; -import android.util.FeatureFlagUtils; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -19,7 +18,6 @@ import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; @@ -52,11 +50,6 @@ public class TopLevelLocationPreferenceController extends BasePreferenceControll @Override public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } - if (mLocationManager.isLocationEnabled()) { if (mNumTotal == -1) { return mContext.getString(R.string.location_settings_loading_app_permission_stats); diff --git a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java index fe2392b705d..c630cc78507 100644 --- a/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java +++ b/src/com/android/settings/network/TopLevelNetworkEntryPreferenceController.java @@ -20,12 +20,10 @@ import android.content.Context; import android.icu.text.ListFormatter; import android.text.BidiFormatter; import android.text.TextUtils; -import android.util.FeatureFlagUtils; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settings.wifi.WifiPrimarySwitchPreferenceController; import java.util.ArrayList; @@ -53,11 +51,6 @@ public class TopLevelNetworkEntryPreferenceController extends BasePreferenceCont @Override public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } - final String wifiSummary = BidiFormatter.getInstance() .unicodeWrap(mContext.getString(R.string.wifi_settings_title)); final String mobileSummary = mContext.getString( diff --git a/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java b/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java index 349a91d36b0..8fab3c9dbd1 100644 --- a/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java +++ b/src/com/android/settings/security/TopLevelSecurityEntryPreferenceController.java @@ -17,17 +17,11 @@ package com.android.settings.security; import android.content.Context; -import android.hardware.face.FaceManager; -import android.hardware.fingerprint.FingerprintManager; import android.text.TextUtils; -import android.util.FeatureFlagUtils; import androidx.preference.Preference; -import com.android.settings.R; -import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.core.FeatureFlags; import com.android.settings.core.SubSettingLauncher; import com.android.settings.overlay.FeatureFactory; @@ -42,26 +36,6 @@ public class TopLevelSecurityEntryPreferenceController extends BasePreferenceCon return AVAILABLE; } - @Override - public CharSequence getSummary() { - // Remove homepage summaries for silky home. - if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.SILKY_HOME)) { - return null; - } - - final FingerprintManager fpm = - Utils.getFingerprintManagerOrNull(mContext); - final FaceManager faceManager = - Utils.getFaceManagerOrNull(mContext); - if (faceManager != null && faceManager.isHardwareDetected()) { - return mContext.getText(R.string.security_dashboard_summary_face); - } else if (fpm != null && fpm.isHardwareDetected()) { - return mContext.getText(R.string.security_dashboard_summary); - } else { - return mContext.getText(R.string.security_dashboard_summary_no_fingerprint); - } - } - @Override public boolean handlePreferenceTreeClick(Preference preference) { if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) { diff --git a/tests/robotests/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceControllerTest.java index 1d63cd11295..937e38d668b 100644 --- a/tests/robotests/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accounts/TopLevelAccountEntryPreferenceControllerTest.java @@ -19,10 +19,8 @@ package com.android.settings.accounts; import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import org.junit.Before; import org.junit.Test; @@ -40,7 +38,6 @@ public class TopLevelAccountEntryPreferenceControllerTest { public void setUp() { mContext = RuntimeEnvironment.application; mController = new TopLevelAccountEntryPreferenceController(mContext, "test_key"); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -48,11 +45,4 @@ public class TopLevelAccountEntryPreferenceControllerTest { assertThat(mController.getSummary()).isEqualTo( mContext.getText(R.string.account_dashboard_default_summary)); } - - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceControllerTest.java index b1f9ed17719..14fe4bd19e6 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/TopLevelConnectedDevicesPreferenceControllerTest.java @@ -22,10 +22,8 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import org.junit.Before; import org.junit.Test; @@ -46,7 +44,6 @@ public class TopLevelConnectedDevicesPreferenceControllerTest { public void setUp() { mContext = RuntimeEnvironment.application; mController = new TopLevelConnectedDevicesPreferenceController(mContext, "test_key"); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -67,13 +64,6 @@ public class TopLevelConnectedDevicesPreferenceControllerTest { .isEqualTo(mContext.getText(R.string.settings_label_launcher)); } - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } - @Implements(AdvancedConnectedDeviceController.class) private static class ShadowAdvancedConnectedDeviceController { diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java index fa1aaa8942e..1fba12ba979 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java @@ -673,33 +673,6 @@ public class DashboardFeatureProviderImplTest { verify(mActivity, never()).getSupportFragmentManager(); } - @Test - public void bindPreference_silkyHomeEnabled_shouldNotBindHomepageTileSummary() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - final Preference preference = new Preference(RuntimeEnvironment.application); - final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_HOMEPAGE); - - mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, - MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, - Preference.DEFAULT_ORDER); - - assertThat(preference.getSummary()).isNull(); - } - - @Test - public void bindPreference_silkyHomeEnabled_shouldBindSubpageTileSummary() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - final Preference preference = new Preference(RuntimeEnvironment.application); - final Tile tile = new ActivityTile(mActivityInfo, CategoryKey.CATEGORY_SYSTEM); - - mImpl.bindPreferenceToTileAndGetObservers(mActivity, mForceRoundedIcon, - MetricsEvent.VIEW_UNKNOWN, preference, tile, null /*key */, - Preference.DEFAULT_ORDER); - - assertThat(preference.getSummary()).isEqualTo( - mContext.getText(R.string.about_settings_summary)); - } - @Test @Config(qualifiers = "mcc999") public void bindPreference_specificHomepageTile_shouldOverridePosition() { diff --git a/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java index d20beabf3a5..988a94b6650 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/aboutphone/TopLevelAboutDevicePreferenceControllerTest.java @@ -23,9 +23,6 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.os.Build; import android.provider.Settings.Global; -import android.util.FeatureFlagUtils; - -import com.android.settings.core.FeatureFlags; import org.junit.Before; import org.junit.Test; @@ -43,7 +40,6 @@ public class TopLevelAboutDevicePreferenceControllerTest { public void setUp() { mContext = RuntimeEnvironment.application; mController = new TopLevelAboutDevicePreferenceController(mContext, "test_key"); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -61,12 +57,4 @@ public class TopLevelAboutDevicePreferenceControllerTest { Global.putString(mContext.getContentResolver(), Global.DEVICE_NAME, "Test"); assertThat(mController.getSummary().toString()).isEqualTo("Test"); } - - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - Global.putString(mContext.getContentResolver(), Global.DEVICE_NAME, "Test"); - - assertThat(mController.getSummary()).isNull(); - } } diff --git a/tests/robotests/src/com/android/settings/display/TopLevelDisplayPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/TopLevelDisplayPreferenceControllerTest.java index 864d2b925fd..d16a6d29559 100644 --- a/tests/robotests/src/com/android/settings/display/TopLevelDisplayPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/TopLevelDisplayPreferenceControllerTest.java @@ -31,10 +31,8 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.util.FeatureFlagUtils; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import org.junit.Before; import org.junit.Test; @@ -65,7 +63,6 @@ public class TopLevelDisplayPreferenceControllerTest { when(mContext.getString(R.string.config_wallpaper_picker_class)).thenReturn("cls"); mController = new TopLevelDisplayPreferenceController(mContext, "test_key"); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -112,11 +109,4 @@ public class TopLevelDisplayPreferenceControllerTest { assertThat(mController.getSummary()) .isEqualTo(mContext.getText(R.string.display_dashboard_nowallpaper_summary)); } - - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java index f2677ce8fd8..1a3c98f8ba1 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java @@ -22,10 +22,8 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.util.FeatureFlagUtils; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import org.junit.Before; import org.junit.Test; @@ -43,7 +41,6 @@ public class TopLevelBatteryPreferenceControllerTest { public void setUp() { mContext = RuntimeEnvironment.application; mController = new TopLevelBatteryPreferenceController(mContext, "test_key"); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -73,16 +70,8 @@ public class TopLevelBatteryPreferenceControllerTest { assertThat(mController.getDashboardLabel(mContext, info, true)).isEqualTo("5% - charging"); } - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } - @Test public void getSummary_batteryNotPresent_shouldShowWarningMessage() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); mController.mIsBatteryPresent = false; assertThat(mController.getSummary()) diff --git a/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java index f5bc9619acd..68e7f88ddf5 100644 --- a/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/location/TopLevelLocationPreferenceControllerTest.java @@ -20,10 +20,8 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.location.LocationManager; -import android.util.FeatureFlagUtils; import com.android.settings.R; -import com.android.settings.core.FeatureFlags; import org.junit.Before; import org.junit.Test; @@ -43,7 +41,6 @@ public class TopLevelLocationPreferenceControllerTest { mContext = RuntimeEnvironment.application; mController = new TopLevelLocationPreferenceController(mContext, PREFERENCE_KEY); mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -86,11 +83,4 @@ public class TopLevelLocationPreferenceControllerTest { R.plurals.location_settings_summary_location_on, LOCATION_APP_COUNT, LOCATION_APP_COUNT)); } - - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java index fc01c6872ba..a3f0c90c1a2 100644 --- a/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/TopLevelNetworkEntryPreferenceControllerTest.java @@ -24,9 +24,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.os.UserManager; -import android.util.FeatureFlagUtils; -import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.shadow.ShadowRestrictedLockUtilsInternal; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.wifi.WifiPrimarySwitchPreferenceController; @@ -74,7 +72,6 @@ public class TopLevelNetworkEntryPreferenceControllerTest { mMobileNetworkPreferenceController); ReflectionHelpers.setField(mController, "mTetherPreferenceController", mTetherPreferenceController); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @After @@ -106,11 +103,4 @@ public class TopLevelNetworkEntryPreferenceControllerTest { assertThat(mController.getSummary()).isEqualTo("Wi\u2011Fi and data usage"); } - - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } } diff --git a/tests/robotests/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java deleted file mode 100644 index 05abc40b312..00000000000 --- a/tests/robotests/src/com/android/settings/security/TopLevelSecurityEntryPreferenceControllerTest.java +++ /dev/null @@ -1,143 +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.security; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.hardware.face.FaceManager; -import android.hardware.fingerprint.FingerprintManager; -import android.util.FeatureFlagUtils; - -import com.android.settings.R; -import com.android.settings.core.FeatureFlags; - -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; - -@RunWith(RobolectricTestRunner.class) -public class TopLevelSecurityEntryPreferenceControllerTest { - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mContext; - @Mock - private FingerprintManager mFingerprintManager; - @Mock - private FaceManager mFaceManager; - private TopLevelSecurityEntryPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - when(mContext.getSystemService(Context.FINGERPRINT_SERVICE)) - .thenReturn(mFingerprintManager); - when(mContext.getSystemService(Context.FACE_SERVICE)) - .thenReturn(mFaceManager); - mController = new TopLevelSecurityEntryPreferenceController(mContext, "test_key"); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); - } - - @Test - public void geSummary_hasFace_hasStaticSummary() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) - .thenReturn(true); - when(mFaceManager.isHardwareDetected()).thenReturn(true); - - mController.getSummary(); - - verify(mContext).getText(R.string.security_dashboard_summary_face); - } - - @Test - public void geSummary_hasFingerPrint_hasStaticSummary() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) - .thenReturn(false); - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(true); - when(mFingerprintManager.isHardwareDetected()).thenReturn(true); - - mController.getSummary(); - - verify(mContext).getText(R.string.security_dashboard_summary); - } - - @Test - public void geSummary_noFpFeature_shouldSetSummaryWithNoBiometrics() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(false); - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) - .thenReturn(false); - - mController.getSummary(); - - verify(mContext).getText(R.string.security_dashboard_summary_no_fingerprint); - } - - @Test - public void geSummary_noFpHardware_shouldSetSummaryWithNoBiometrics() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) - .thenReturn(false); - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(true); - when(mFingerprintManager.isHardwareDetected()).thenReturn(false); - - mController.getSummary(); - - verify(mContext).getText(R.string.security_dashboard_summary_no_fingerprint); - } - - @Test - public void geSummary_noFaceFeature_shouldSetSummaryWithNoBiometrics() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(false); - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) - .thenReturn(false); - - mController.getSummary(); - - verify(mContext).getText(R.string.security_dashboard_summary_no_fingerprint); - } - - @Test - public void geSummary_noFaceHardware_shouldSetSummaryWithNoBiometrics() { - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) - .thenReturn(true); - when(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) - .thenReturn(false); - when(mFaceManager.isHardwareDetected()).thenReturn(false); - - mController.getSummary(); - - verify(mContext).getText(R.string.security_dashboard_summary_no_fingerprint); - } - - @Test - public void getSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } -} diff --git a/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java index d4157b85d47..6318c9c6914 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java @@ -30,13 +30,11 @@ import android.content.Context; import android.icu.text.NumberFormat; import android.os.storage.VolumeInfo; import android.text.format.Formatter; -import android.util.FeatureFlagUtils; import androidx.preference.Preference; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.android.settings.core.FeatureFlags; import com.android.settings.testutils.ResourcesUtils; import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; @@ -72,7 +70,6 @@ public class TopLevelStoragePreferenceControllerTest { when(mStorageManagerVolumeProvider.getVolumes()).thenReturn(mVolumes); mController = spy(new TopLevelStoragePreferenceController(mContext, "test_key")); - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); } @Test @@ -108,11 +105,4 @@ public class TopLevelStoragePreferenceControllerTest { assertThat(preference.getSummary()).isEqualTo(ResourcesUtils.getResourcesString( mContext, "storage_summary", percentage, freeSpace)); } - - @Test - public void refreshSummary_silkyHomeEnabled_shouldBeNull() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, true); - - assertThat(mController.getSummary()).isNull(); - } } From 872db9c41a285bab6b6d891bac4e20c33cecbf21 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Thu, 6 May 2021 16:57:08 +0800 Subject: [PATCH 03/17] Add require scrolling button for FingerprintEnrolling intro The consent in the fingerprint introduction has been updated. Users are required to read through the content. Adding a scrolling button is to prevent directly going to next page from this page. It also makes sure the content has to be scrolled down to the bottom of page. Fix: 184591438 Test: visual verified 1) Prepare a device with fingerprint sensor 2) Settings > Security > Fingerprint unlock 3) Entering the enrollment flow and see if the introduction has a button named "More" on the right-bottom side. Change-Id: I1916293807ca9fb04f5d576cf4f6aaccbbe1ff00 --- .../FingerprintEnrollIntroduction.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java index 0996a582d44..162208697b1 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollIntroduction.java @@ -37,6 +37,7 @@ import com.android.settingslib.RestrictedLockUtilsInternal; import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; import com.google.android.setupdesign.span.LinkSpan; +import com.google.android.setupdesign.template.RequireScrollMixin; import java.util.List; @@ -69,14 +70,18 @@ public class FingerprintEnrollIntroduction extends BiometricEnrollIntroduction { .build() ); - mFooterBarMixin.setPrimaryButton( - new FooterButton.Builder(this) - .setText(R.string.security_settings_fingerprint_enroll_introduction_agree) - .setListener(this::onNextButtonClick) - .setButtonType(FooterButton.ButtonType.NEXT) - .setTheme(R.style.SudGlifButton_Primary) - .build() - ); + final FooterButton nextButton = new FooterButton.Builder(this) + .setText(R.string.security_settings_fingerprint_enroll_introduction_agree) + .setListener(this::onNextButtonClick) + .setButtonType(FooterButton.ButtonType.NEXT) + .setTheme(R.style.SudGlifButton_Primary) + .build(); + + mFooterBarMixin.setPrimaryButton(nextButton); + final RequireScrollMixin requireScrollMixin = + getLayout().getMixin(RequireScrollMixin.class); + requireScrollMixin.requireScrollWithButton(this, nextButton, + R.string.security_settings_face_enroll_introduction_more, this::onNextButtonClick); } int getNegativeButtonTextId() { From e4cd381d3ca4e8405baee38db0ddaffdfd0da596 Mon Sep 17 00:00:00 2001 From: changbetty Date: Thu, 6 May 2021 19:09:10 +0800 Subject: [PATCH 04/17] Change Network detail string form TYPE to Type Screenshot: https://photos.app.goo.gl/k9xSS3f7LcDQih6u9 Bug: 187252277 Test: manual test Change-Id: Ia17a01c77880d62b65b25d4f85c75d963591fa4c --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 68f666aead5..8c3574d856f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2426,7 +2426,7 @@ Subnet mask - TYPE + Type DNS From 8850c3c677fe912640f3673739b6acbdd993c1d5 Mon Sep 17 00:00:00 2001 From: Matt Pietal Date: Thu, 6 May 2021 08:35:13 -0400 Subject: [PATCH 05/17] Wallet/controls - Migrate existing settings Step 2 of 2. Move wallet settings from System -> Gestures -> Power Menu to Display -> Lockscreen. Split the existing sensitivity setting into two separate toggles to give users better control of their privacy settings. Bug: 185597511 Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.display Change-Id: Ifc390945a45258bbcc3c0a6ac67a0c4a3f7a9e91 --- AndroidManifest.xml | 11 -- res/values/strings.xml | 44 ++--- res/xml/global_actions_panel_settings.xml | 36 ----- res/xml/power_menu_settings.xml | 15 -- res/xml/security_lockscreen_settings.xml | 13 +- src/com/android/settings/Settings.java | 2 - .../core/gateway/SettingsGateway.java | 2 - .../ControlsPrivacyPreferenceController.java} | 39 ++--- .../WalletPrivacyPreferenceController.java | 95 +++++++++++ .../gestures/GlobalActionsPanelSettings.java | 48 ------ .../PowerMenuPreferenceController.java | 24 +-- ...trolsPrivacyPreferenceControllerTest.java} | 67 +++----- ...WalletPrivacyPreferenceControllerTest.java | 151 ++++++++++++++++++ ...erMenuPreferenceControllerSummaryTest.java | 86 ---------- .../PowerMenuPreferenceControllerTest.java | 42 +---- ...yPreferenceControllerAvailabilityTest.java | 116 -------------- 16 files changed, 305 insertions(+), 486 deletions(-) delete mode 100644 res/xml/global_actions_panel_settings.xml rename src/com/android/settings/{gestures/PowerMenuPrivacyPreferenceController.java => display/ControlsPrivacyPreferenceController.java} (59%) create mode 100644 src/com/android/settings/display/WalletPrivacyPreferenceController.java delete mode 100644 src/com/android/settings/gestures/GlobalActionsPanelSettings.java rename tests/robotests/src/com/android/settings/{gestures/PowerMenuPrivacyPreferenceControllerTest.java => display/ControlsPrivacyPreferenceControllerTest.java} (65%) create mode 100644 tests/robotests/src/com/android/settings/display/WalletPrivacyPreferenceControllerTest.java delete mode 100644 tests/robotests/src/com/android/settings/gestures/PowerMenuPreferenceControllerSummaryTest.java delete mode 100644 tests/robotests/src/com/android/settings/gestures/PowerMenuPrivacyPreferenceControllerAvailabilityTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9b11fe81c98..05dd0839f08 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3682,17 +3682,6 @@ android:value="com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleSettings" /> - - - - - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index 8368b4647e8..ed7afbadd16 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8082,8 +8082,7 @@ work challenge, work, profile work profile, managed profile, unify, unification, work, profile gestures - cards, passes - device controls, controls + wallet pay, tap, payments backup, back up gesture @@ -12979,32 +12978,11 @@ Power button menu - - Show cards & passes - - - Lock screen - Don\u2019t show any content - - Sensitive content - - - Show cards and controls when locked - - - Show controls when locked - - - Show cards when locked - - - Hide cards and controls when locked - - To use, first set a screen lock + To use, first set a screen lock Hold for Assistant @@ -13012,17 +12990,15 @@ Trigger the Assistant by holding the power button + + Show wallet + + Allow access to wallet from lock screen and quick settings + - Show device controls - - - Show cards & passes - - - To access controls for connected devices, hold the Power button - - - To access things like your payment methods and boarding passes, press and hold the Power button. + Show device controls + + Access controls when locked diff --git a/res/xml/global_actions_panel_settings.xml b/res/xml/global_actions_panel_settings.xml deleted file mode 100644 index e49c0d2b0d7..00000000000 --- a/res/xml/global_actions_panel_settings.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - diff --git a/res/xml/power_menu_settings.xml b/res/xml/power_menu_settings.xml index 406cd0b3708..f88531e3802 100644 --- a/res/xml/power_menu_settings.xml +++ b/res/xml/power_menu_settings.xml @@ -26,19 +26,4 @@ android:summary="@string/power_menu_long_press_for_assist_summary" settings:controller="com.android.settings.gestures.LongPressPowerButtonPreferenceController" /> - - - - - - - diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml index 8962fc2cf74..82cb8609114 100644 --- a/res/xml/security_lockscreen_settings.xml +++ b/res/xml/security_lockscreen_settings.xml @@ -46,11 +46,16 @@ android:summary="@string/owner_info_settings_summary" /> + android:key="lockscreen_privacy_wallet_switch" + android:title="@string/lockscreen_privacy_wallet_setting_toggle" + android:summary="@string/lockscreen_privacy_wallet_summary" + settings:controller="com.android.settings.display.WalletPrivacyPreferenceController" /> + Date: Thu, 6 May 2021 15:16:40 +0100 Subject: [PATCH 06/17] Move myself to the emeritus section As I no longer expect to be working on security-related settings, move myself to the emeritus section. Bug: 187395769 Test: N/A Change-Id: Ic91dd36f6de39ef79f1ced90083e1c5c7836c651 --- src/com/android/settings/security/OWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/security/OWNERS b/src/com/android/settings/security/OWNERS index 6e4f5532bd4..701feb8f8bb 100644 --- a/src/com/android/settings/security/OWNERS +++ b/src/com/android/settings/security/OWNERS @@ -1,7 +1,9 @@ # Enterprise security reviewers -eranm@google.com pgrafov@google.com rubinxu@google.com # Emergency sandness@google.com + +# Emeritus +eranm@google.com From aff80d1e141bd939d4eed1f17c11e18ecc7d8cd1 Mon Sep 17 00:00:00 2001 From: Alex Stetson Date: Wed, 5 May 2021 08:49:15 -0700 Subject: [PATCH 07/17] Use shared model for non-system overlay toggle Allows settings applications on other platforms to re-use values by migrating to Settings.secure and moving HideNonSystemOverlayMixin to SettingsLib. Bug: 184967544 Test: atest SettingsUnitTests Change-Id: If9aaeca29ebb8b481d75622934503e368d7435d3 --- .../core/HideNonSystemOverlayMixin.java | 72 ------------ .../settings/core/SettingsBaseActivity.java | 1 + .../OverlaySettingsPreferenceController.java | 18 +-- .../homepage/SettingsHomepageActivity.java | 2 +- .../app/ChannelPanelActivity.java | 3 +- .../settings/panel/SettingsPanelActivity.java | 2 +- .../settings/security/CredentialStorage.java | 2 +- .../AddAppNetworksActivity.java | 2 +- .../core/HideNonSystemOverlayMixinTest.java | 104 ------------------ .../SettingsHomepageActivityTest.java | 2 +- .../panel/SettingsPanelActivityTest.java | 2 +- ...erlaySettingsPreferenceControllerTest.java | 16 ++- 12 files changed, 24 insertions(+), 202 deletions(-) delete mode 100644 src/com/android/settings/core/HideNonSystemOverlayMixin.java delete mode 100644 tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.java diff --git a/src/com/android/settings/core/HideNonSystemOverlayMixin.java b/src/com/android/settings/core/HideNonSystemOverlayMixin.java deleted file mode 100644 index eff1792c622..00000000000 --- a/src/com/android/settings/core/HideNonSystemOverlayMixin.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2019 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.core; - -import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - -import static androidx.lifecycle.Lifecycle.Event.ON_START; -import static androidx.lifecycle.Lifecycle.Event.ON_STOP; - -import android.app.Activity; -import android.view.Window; -import android.view.WindowManager; - -import androidx.annotation.VisibleForTesting; -import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; - -import com.android.settings.development.OverlaySettingsPreferenceController; - - -/** - * A mixin that adds window flag to prevent non-system overlays showing on top of Settings - * activities. - */ -public class HideNonSystemOverlayMixin implements LifecycleObserver { - - private final Activity mActivity; - - public HideNonSystemOverlayMixin(Activity activity) { - mActivity = activity; - } - - @VisibleForTesting - boolean isEnabled() { - return !OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mActivity); - } - - @OnLifecycleEvent(ON_START) - public void onStart() { - if (mActivity == null || !isEnabled()) { - return; - } - mActivity.getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS); - android.util.EventLog.writeEvent(0x534e4554, "120484087", -1, ""); - } - - - @OnLifecycleEvent(ON_STOP) - public void onStop() { - if (mActivity == null || !isEnabled()) { - return; - } - final Window window = mActivity.getWindow(); - final WindowManager.LayoutParams attrs = window.getAttributes(); - attrs.privateFlags &= ~SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - window.setAttributes(attrs); - } -} diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 903805e6ddb..2e2eeff1c8f 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -47,6 +47,7 @@ import com.android.settings.R; import com.android.settings.SubSettings; import com.android.settings.Utils; import com.android.settings.dashboard.CategoryManager; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import com.android.settingslib.drawer.Tile; import com.android.settingslib.transition.SettingsTransitionHelper; diff --git a/src/com/android/settings/development/OverlaySettingsPreferenceController.java b/src/com/android/settings/development/OverlaySettingsPreferenceController.java index 50f98672976..cd08793a9e4 100644 --- a/src/com/android/settings/development/OverlaySettingsPreferenceController.java +++ b/src/com/android/settings/development/OverlaySettingsPreferenceController.java @@ -16,8 +16,10 @@ package com.android.settings.development; +import static com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin.SECURE_OVERLAY_SETTINGS; + import android.content.Context; -import android.content.SharedPreferences; +import android.provider.Settings; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -33,7 +35,6 @@ import com.android.settingslib.development.DeveloperOptionsPreferenceController; public class OverlaySettingsPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { - public static final String SHARE_PERFS = "overlay_settings"; private static final String KEY_OVERLAY_SETTINGS = "overlay_settings"; public OverlaySettingsPreferenceController(Context context) { @@ -64,10 +65,10 @@ public class OverlaySettingsPreferenceController extends DeveloperOptionsPrefere /** * Check if this setting is enabled or not. */ - public static boolean isOverlaySettingsEnabled(Context context) { - final SharedPreferences editor = context.getSharedPreferences(SHARE_PERFS, - Context.MODE_PRIVATE); - return editor.getBoolean(SHARE_PERFS, false /* defValue */); + @VisibleForTesting + static boolean isOverlaySettingsEnabled(Context context) { + return Settings.Secure.getInt(context.getContentResolver(), + SECURE_OVERLAY_SETTINGS, 0 /* defValue */) != 0; } /** @@ -75,9 +76,8 @@ public class OverlaySettingsPreferenceController extends DeveloperOptionsPrefere */ @VisibleForTesting static void setOverlaySettingsEnabled(Context context, boolean enabled) { - final SharedPreferences editor = context.getSharedPreferences(SHARE_PERFS, - Context.MODE_PRIVATE); - editor.edit().putBoolean(SHARE_PERFS, enabled).apply(); + Settings.Secure.putInt(context.getContentResolver(), + SECURE_OVERLAY_SETTINGS, enabled ? 1 : 0); } @Override diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java index cd980f32a6f..c59b805c437 100644 --- a/src/com/android/settings/homepage/SettingsHomepageActivity.java +++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java @@ -39,9 +39,9 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.accounts.AvatarViewMixin; import com.android.settings.core.FeatureFlags; -import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.homepage.contextualcards.ContextualCardsFragment; import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import com.android.settingslib.transition.SettingsTransitionHelper; public class SettingsHomepageActivity extends FragmentActivity { diff --git a/src/com/android/settings/notification/app/ChannelPanelActivity.java b/src/com/android/settings/notification/app/ChannelPanelActivity.java index 3ba118ee4d9..9889183d4d7 100644 --- a/src/com/android/settings/notification/app/ChannelPanelActivity.java +++ b/src/com/android/settings/notification/app/ChannelPanelActivity.java @@ -31,10 +31,9 @@ import androidx.annotation.Nullable; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; -import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.core.SubSettingLauncher; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; /** * Dialog Activity to host channel settings diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java index 856dc35c6ec..77949eb2983 100644 --- a/src/com/android/settings/panel/SettingsPanelActivity.java +++ b/src/com/android/settings/panel/SettingsPanelActivity.java @@ -35,7 +35,7 @@ import androidx.fragment.app.FragmentManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settings.core.HideNonSystemOverlayMixin; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; /** * Dialog Activity to host Settings Slices. diff --git a/src/com/android/settings/security/CredentialStorage.java b/src/com/android/settings/security/CredentialStorage.java index be428503724..090fdf6bb07 100644 --- a/src/com/android/settings/security/CredentialStorage.java +++ b/src/com/android/settings/security/CredentialStorage.java @@ -44,9 +44,9 @@ import androidx.fragment.app.FragmentActivity; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; -import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.vpn2.VpnUtils; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; /** * CredentialStorage handles resetting and installing keys into KeyStore. diff --git a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java index f276603d7dc..7b5eaa9ecb1 100644 --- a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java +++ b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksActivity.java @@ -30,7 +30,7 @@ import androidx.fragment.app.FragmentManager; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; -import com.android.settings.core.HideNonSystemOverlayMixin; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; /** * When apps send a new intent with a WifiConfiguration list extra to Settings APP. Settings APP diff --git a/tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.java b/tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.java deleted file mode 100644 index cf0f1380cfb..00000000000 --- a/tests/robotests/src/com/android/settings/core/HideNonSystemOverlayMixinTest.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2019 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.core; - -import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.view.WindowManager; - -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; - -import com.android.settings.R; -import com.android.settings.development.OverlaySettingsPreferenceController; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.Robolectric; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.android.controller.ActivityController; - -@RunWith(RobolectricTestRunner.class) -public class HideNonSystemOverlayMixinTest { - - private ActivityController mActivityController; - - @Before - public void setUp() { - mActivityController = Robolectric.buildActivity(TestActivity.class); - } - - @Test - public void startActivity_shouldHideNonSystemOverlay() { - mActivityController.setup(); - TestActivity activity = mActivityController.get(); - - // Activity start: HIDE_NON_SYSTEM_OVERLAY should be set. - final WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); - assertThat(attrs.privateFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) - .isNotEqualTo(0); - } - - @Test - public void stopActivity_shouldUnhideNonSystemOverlay() { - mActivityController.setup().stop(); - TestActivity activity = mActivityController.get(); - - final WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); - assertThat(attrs.privateFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) - .isEqualTo(0); - } - - @Test - public void isEnabled_isAllowedOverlaySettings_returnFalse() { - mActivityController.setup(); - final TestActivity activity = mActivityController.get(); - final SharedPreferences editor = activity.getSharedPreferences( - OverlaySettingsPreferenceController.SHARE_PERFS, - Context.MODE_PRIVATE); - editor.edit().putBoolean(OverlaySettingsPreferenceController.SHARE_PERFS, true).apply(); - - assertThat(new HideNonSystemOverlayMixin(activity).isEnabled()).isFalse(); - } - - @Test - public void isEnabled_isNotAllowedOverlaySettings_returnTrue() { - mActivityController.setup(); - TestActivity activity = mActivityController.get(); - final SharedPreferences editor = activity.getSharedPreferences( - OverlaySettingsPreferenceController.SHARE_PERFS, - Context.MODE_PRIVATE); - editor.edit().putBoolean(OverlaySettingsPreferenceController.SHARE_PERFS, false).apply(); - - assertThat(new HideNonSystemOverlayMixin(activity).isEnabled()).isTrue(); - } - - public static class TestActivity extends AppCompatActivity { - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setTheme(R.style.Theme_AppCompat); - getLifecycle().addObserver(new HideNonSystemOverlayMixin(this)); - } - } -} diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 620f6d74b17..9a4ad3c29f7 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -35,11 +35,11 @@ import android.widget.FrameLayout; import androidx.fragment.app.Fragment; import com.android.settings.R; -import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; import com.android.settings.homepage.contextualcards.slices.BatteryFixSliceTest; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUtils; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java index 25e17865e2f..5cdc12a26df 100644 --- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java +++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java @@ -36,8 +36,8 @@ import android.view.WindowManager; import androidx.fragment.app.FragmentManager; import com.android.settings.R; -import com.android.settings.core.HideNonSystemOverlayMixin; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; import org.junit.Before; import org.junit.Test; diff --git a/tests/unit/src/com/android/settings/development/OverlaySettingsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/OverlaySettingsPreferenceControllerTest.java index 827f5a199a9..66fc24c92d5 100644 --- a/tests/unit/src/com/android/settings/development/OverlaySettingsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/development/OverlaySettingsPreferenceControllerTest.java @@ -16,10 +16,12 @@ package com.android.settings.development; +import static com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin.SECURE_OVERLAY_SETTINGS; + import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.content.SharedPreferences; +import android.provider.Settings; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; @@ -83,20 +85,16 @@ public class OverlaySettingsPreferenceControllerTest { @Test public void isOverlaySettingsEnabled_sharePreferenceSetTrue_shouldReturnTrue() { - final SharedPreferences editor = mContext.getSharedPreferences( - OverlaySettingsPreferenceController.SHARE_PERFS, - Context.MODE_PRIVATE); - editor.edit().putBoolean(OverlaySettingsPreferenceController.SHARE_PERFS, true).apply(); + Settings.Secure.putInt(mContext.getContentResolver(), + SECURE_OVERLAY_SETTINGS, 1); assertThat(OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isTrue(); } @Test public void isOverlaySettingsEnabled_sharePreferenceSetFalse_shouldReturnFalse() { - final SharedPreferences editor = mContext.getSharedPreferences( - OverlaySettingsPreferenceController.SHARE_PERFS, - Context.MODE_PRIVATE); - editor.edit().putBoolean(OverlaySettingsPreferenceController.SHARE_PERFS, false).apply(); + Settings.Secure.putInt(mContext.getContentResolver(), + SECURE_OVERLAY_SETTINGS, 0); assertThat( OverlaySettingsPreferenceController.isOverlaySettingsEnabled(mContext)).isFalse(); From f76ba1189a28873561f1e164098a1e4e2be6f824 Mon Sep 17 00:00:00 2001 From: ykhung Date: Thu, 6 May 2021 15:29:41 +0800 Subject: [PATCH 08/17] Adopt new battery history map with interpolation method Bug: 184807417 Test: make SettingsRoboTests Change-Id: I5c45a443d0a72df352d4bb707412328ad009f6d4 --- .../BatteryChartPreferenceController.java | 64 +++++++----------- .../fuelgauge/BatteryHistoryLoader.java | 7 +- .../settings/fuelgauge/ConvertUtils.java | 29 ++------ .../fuelgauge/PowerUsageAdvanced.java | 13 ++-- .../fuelgauge/PowerUsageFeatureProvider.java | 3 +- .../PowerUsageFeatureProviderImpl.java | 3 +- .../BatteryChartPreferenceControllerTest.java | 53 +++++---------- .../fuelgauge/BatteryHistoryLoaderTest.java | 3 +- .../settings/fuelgauge/ConvertUtilsTest.java | 66 +++++++++++-------- 9 files changed, 94 insertions(+), 147 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index 4f19785482b..c4efef88ccd 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -53,8 +53,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll implements PreferenceControllerMixin, LifecycleObserver, OnPause, OnDestroy, BatteryChartView.OnSelectListener, ExpandDividerPreference.OnExpandListener { private static final String TAG = "BatteryChartPreferenceController"; - private static final int CHART_KEY_ARRAY_SIZE = 25; + /** Desired battery history size for timestamp slots. */ + public static final int DESIRED_HISTORY_SIZE = 25; private static final int CHART_LEVEL_ARRAY_SIZE = 13; + private static final int CHART_KEY_ARRAY_SIZE = DESIRED_HISTORY_SIZE; private static final long VALID_USAGE_TIME_DURATION = DateUtils.HOUR_IN_MILLIS * 2; private static final long VALID_DIFF_DURATION = DateUtils.MINUTE_IN_MILLIS * 3; @@ -176,12 +178,12 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } void setBatteryHistoryMap( - final Map> batteryHistoryMap) { + final Map> batteryHistoryMap) { mHandler.post(() -> setBatteryHistoryMapInner(batteryHistoryMap)); } private void setBatteryHistoryMapInner( - final Map> batteryHistoryMap) { + final Map> batteryHistoryMap) { // Resets all battery history data relative variables. if (batteryHistoryMap == null) { mBatteryIndexedMap = null; @@ -189,31 +191,32 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll mBatteryHistoryLevels = null; return; } - // Generates battery history keys. + // Generates battery history timestamp slots. final List batteryHistoryKeyList = - new ArrayList(batteryHistoryMap.keySet()); + new ArrayList<>(batteryHistoryMap.keySet()); Collections.sort(batteryHistoryKeyList); - validateSlotTimestamp(batteryHistoryKeyList); mBatteryHistoryKeys = new long[CHART_KEY_ARRAY_SIZE]; - final int listSize = batteryHistoryKeyList.size(); - final int elementSize = Math.min(listSize, CHART_KEY_ARRAY_SIZE); - for (int index = 0; index < elementSize; index++) { - mBatteryHistoryKeys[CHART_KEY_ARRAY_SIZE - index - 1] = - batteryHistoryKeyList.get(listSize - index - 1); + for (int index = 0; index < CHART_KEY_ARRAY_SIZE; index++) { + mBatteryHistoryKeys[index] = batteryHistoryKeyList.get(index); } - // Generates the battery history levels. + // Generates the battery history levels for chart graph. mBatteryHistoryLevels = new int[CHART_LEVEL_ARRAY_SIZE]; for (int index = 0; index < CHART_LEVEL_ARRAY_SIZE; index++) { - final Long timestamp = Long.valueOf(mBatteryHistoryKeys[index * 2]); - final List entryList = batteryHistoryMap.get(timestamp); - if (entryList != null && !entryList.isEmpty()) { - // All battery levels are the same in the same timestamp snapshot. - mBatteryHistoryLevels[index] = entryList.get(0).mBatteryLevel; - } else if (entryList != null && entryList.isEmpty()) { - Log.e(TAG, "abnormal entry list in the timestamp:" + - ConvertUtils.utcToLocalTime(timestamp)); + final long timestamp = mBatteryHistoryKeys[index * 2]; + final Map entryMap = batteryHistoryMap.get(timestamp); + if (entryMap == null || entryMap.isEmpty()) { + Log.e(TAG, "abnormal entry list in the timestamp:" + + ConvertUtils.utcToLocalTime(timestamp)); + continue; } + // Averages the battery level in each time slot to avoid corner conditions. + float batteryLevelCounter = 0; + for (BatteryHistEntry entry : entryMap.values()) { + batteryLevelCounter += entry.mBatteryLevel; + } + mBatteryHistoryLevels[index] = + Math.round(batteryLevelCounter / entryMap.size()); } // Generates indexed usage map for chart. mBatteryIndexedMap = @@ -532,25 +535,4 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll } return true; } - - @VisibleForTesting - static boolean validateSlotTimestamp(List batteryHistoryKeys) { - // Whether the nearest two slot time diff is valid or not? - final int size = batteryHistoryKeys.size(); - for (int index = 0; index < size - 1; index++) { - final long currentTime = batteryHistoryKeys.get(index); - final long nextTime = batteryHistoryKeys.get(index + 1); - final long diffTime = Math.abs( - DateUtils.HOUR_IN_MILLIS - Math.abs(currentTime - nextTime)); - if (currentTime == 0) { - continue; - } else if (diffTime > VALID_DIFF_DURATION) { - Log.e(TAG, String.format("validateSlotTimestamp() %s > %s", - ConvertUtils.utcToLocalTime(currentTime), - ConvertUtils.utcToLocalTime(nextTime))); - return false; - } - } - return true; - } } diff --git a/src/com/android/settings/fuelgauge/BatteryHistoryLoader.java b/src/com/android/settings/fuelgauge/BatteryHistoryLoader.java index 97bdbd630a2..ddf3bf47d43 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoryLoader.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoryLoader.java @@ -20,12 +20,11 @@ import android.content.Context; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.utils.AsyncLoaderCompat; -import java.util.List; import java.util.Map; /** Loader that can be used to load battery history information. */ public class BatteryHistoryLoader - extends AsyncLoaderCompat>> { + extends AsyncLoaderCompat>> { private static final String TAG = "BatteryHistoryLoader"; private final Context mContext; @@ -36,11 +35,11 @@ public class BatteryHistoryLoader } @Override - protected void onDiscardResult(Map> result) { + protected void onDiscardResult(Map> result) { } @Override - public Map> loadInBackground() { + public Map> loadInBackground() { final PowerUsageFeatureProvider powerUsageFeatureProvider = FeatureFactory.getFactory(mContext).getPowerUsageFeatureProvider(mContext); return powerUsageFeatureProvider.getBatteryHistory(mContext); diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java index f2c86f5cba9..1f6600bc272 100644 --- a/src/com/android/settings/fuelgauge/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/ConvertUtils.java @@ -144,30 +144,9 @@ public final class ConvertUtils { final Context context, final int timeSlotSize, final long[] batteryHistoryKeys, - final Map> batteryHistoryMap, + final Map> batteryHistoryMap, final boolean purgeLowPercentageData) { final Map> resultMap = new HashMap<>(); - // Generates a temporary map to calculate diff usage data, which converts the inputted - // List into Map with the key comes from - // the BatteryHistEntry.getKey() method. - final Map> newBatteryHistoryMap = new HashMap<>(); - for (int index = 0; index < batteryHistoryKeys.length; index++) { - final Long timestamp = Long.valueOf(batteryHistoryKeys[index]); - final List entries = batteryHistoryMap.get(timestamp); - if (entries == null || entries.isEmpty()) { - continue; - } - final Map slotBatteryHistDataMap = new HashMap<>(); - for (BatteryHistEntry entry : entries) { - // Excludes auto-generated fake BatteryHistEntry data, - // which is used to record battery level and status purpose only. - if (!FAKE_PACKAGE_NAME.equals(entry.mPackageName)) { - slotBatteryHistDataMap.put(entry.getKey(), entry); - } - } - newBatteryHistoryMap.put(timestamp, slotBatteryHistDataMap); - } - // Each time slot usage diff data = // Math.abs(timestamp[i+2] data - timestamp[i+1] data) + // Math.abs(timestamp[i+1] data - timestamp[i] data); @@ -188,11 +167,11 @@ public final class ConvertUtils { // Fetches BatteryHistEntry data from corresponding time slot. final Map currentBatteryHistMap = - newBatteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP); + batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP); final Map nextBatteryHistMap = - newBatteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP); + batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP); final Map nextTwoBatteryHistMap = - newBatteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP); + batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP); // Collects all keys in these three time slot records as population. final Set allBatteryHistEntryKeys = new HashSet<>(); diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java index 98cbc8aa567..7c696184af6 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java +++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java @@ -52,7 +52,7 @@ public class PowerUsageAdvanced extends PowerUsageBase { @VisibleForTesting BatteryHistoryPreference mHistPref; @VisibleForTesting - Map> mBatteryHistoryMap; + Map> mBatteryHistoryMap; @VisibleForTesting final BatteryHistoryLoaderCallbacks mBatteryHistoryLoaderCallbacks = new BatteryHistoryLoaderCallbacks(); @@ -210,25 +210,26 @@ public class PowerUsageAdvanced extends PowerUsageBase { }; private class BatteryHistoryLoaderCallbacks - implements LoaderManager.LoaderCallbacks>> { + implements LoaderManager.LoaderCallbacks>> { private int mRefreshType; @Override @NonNull - public Loader>> onCreateLoader(int id, Bundle bundle) { + public Loader>> onCreateLoader( + int id, Bundle bundle) { mRefreshType = bundle.getInt(KEY_REFRESH_TYPE); return new BatteryHistoryLoader(getContext()); } @Override - public void onLoadFinished(Loader>> loader, - Map> batteryHistoryMap) { + public void onLoadFinished(Loader>> loader, + Map> batteryHistoryMap) { mBatteryHistoryMap = batteryHistoryMap; PowerUsageAdvanced.this.onLoadFinished(mRefreshType); } @Override - public void onLoaderReset(Loader>> loader) { + public void onLoaderReset(Loader>> loader) { } } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 29487b912c3..7b97bdf6f76 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -23,7 +23,6 @@ import android.util.SparseIntArray; import com.android.internal.os.BatterySipper; import com.android.settingslib.fuelgauge.Estimate; -import java.util.List; import java.util.Map; /** @@ -136,5 +135,5 @@ public interface PowerUsageFeatureProvider { /** * Returns battery history data with corresponding timestamp key. */ - Map> getBatteryHistory(Context context); + Map> getBatteryHistory(Context context); } diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index 1bbbba4ed46..b9f225b92f4 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -26,7 +26,6 @@ import com.android.internal.os.BatterySipper; import com.android.internal.util.ArrayUtils; import com.android.settingslib.fuelgauge.Estimate; -import java.util.List; import java.util.Map; public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider { @@ -160,7 +159,7 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider } @Override - public Map> getBatteryHistory(Context context) { + public Map> getBatteryHistory(Context context) { return null; } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java index 4e1d16ca4e5..a4f52dcfbc6 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryChartPreferenceControllerTest.java @@ -62,6 +62,8 @@ import java.util.TimeZone; public final class BatteryChartPreferenceControllerTest { private static final String PREF_KEY = "pref_key"; private static final String PREF_SUMMARY = "fake preference summary"; + private static final int DESIRED_HISTORY_SIZE = + BatteryChartPreferenceController.DESIRED_HISTORY_SIZE; @Mock private InstrumentedPreferenceFragment mFragment; @Mock private SettingsActivity mSettingsActivity; @@ -98,7 +100,7 @@ public final class BatteryChartPreferenceControllerTest { "fakeBatteryDiffEntryKey", new BatteryEntry.NameAndIcon("fakeName", /*icon=*/ null, /*iconId=*/ 1)); mBatteryChartPreferenceController.setBatteryHistoryMap( - createBatteryHistoryMap(/*size=*/ 5)); + createBatteryHistoryMap()); } @Test @@ -142,19 +144,19 @@ public final class BatteryChartPreferenceControllerTest { @Test public void testSetBatteryHistoryMap_createExpectedKeysAndLevels() { mBatteryChartPreferenceController.setBatteryHistoryMap( - createBatteryHistoryMap(/*size=*/ 5)); + createBatteryHistoryMap()); // Verifies the created battery keys array. - for (int index = 0; index < 25; index++) { + for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) { assertThat(mBatteryChartPreferenceController.mBatteryHistoryKeys[index]) // These values is are calculated by hand from createBatteryHistoryMap(). - .isEqualTo(index < 20 ? 0 : (index - 20 + 1)); + .isEqualTo(index + 1); } // Verifies the created battery levels array. for (int index = 0; index < 13; index++) { assertThat(mBatteryChartPreferenceController.mBatteryHistoryLevels[index]) // These values is are calculated by hand from createBatteryHistoryMap(). - .isEqualTo(index < 10 ? 0 : (100 - (index - 10) * 2)); + .isEqualTo(100 - index * 2); } assertThat(mBatteryChartPreferenceController.mBatteryIndexedMap).hasSize(13); } @@ -162,10 +164,10 @@ public final class BatteryChartPreferenceControllerTest { @Test public void testSetBatteryHistoryMap_largeSize_createExpectedKeysAndLevels() { mBatteryChartPreferenceController.setBatteryHistoryMap( - createBatteryHistoryMap(/*size=*/ 25)); + createBatteryHistoryMap()); // Verifies the created battery keys array. - for (int index = 0; index < 25; index++) { + for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) { assertThat(mBatteryChartPreferenceController.mBatteryHistoryKeys[index]) // These values is are calculated by hand from createBatteryHistoryMap(). .isEqualTo(index + 1); @@ -214,7 +216,7 @@ public final class BatteryChartPreferenceControllerTest { mBatteryChartPreferenceController.mTrapezoidIndex = BatteryChartView.SELECTED_INDEX_INVALID; mBatteryChartPreferenceController.setBatteryHistoryMap( - createBatteryHistoryMap(/*size=*/ 25)); + createBatteryHistoryMap()); assertThat(mBatteryChartPreferenceController.mTrapezoidIndex) .isEqualTo(BatteryChartView.SELECTED_INDEX_ALL); @@ -426,31 +428,6 @@ public final class BatteryChartPreferenceControllerTest { .isFalse(); } - @Test - public void testValidateSlotTimestamp_emptyContent_returnTrue() { - assertThat(BatteryChartPreferenceController.validateSlotTimestamp( - new ArrayList())).isTrue(); - } - - @Test - public void testValidateSlotTimestamp_returnExpectedResult() { - final ArrayList slotTimestampList = new ArrayList( - Arrays.asList( - Long.valueOf(0), - Long.valueOf(DateUtils.HOUR_IN_MILLIS), - Long.valueOf(DateUtils.HOUR_IN_MILLIS * 2 + DateUtils.MINUTE_IN_MILLIS), - Long.valueOf(DateUtils.HOUR_IN_MILLIS * 3 + DateUtils.MINUTE_IN_MILLIS * 2))); - // Verifies the testing data is correct before we added invalid data into it. - assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList)) - .isTrue(); - - // Insert invalid timestamp into the list. - slotTimestampList.add( - Long.valueOf(DateUtils.HOUR_IN_MILLIS * 4 + DateUtils.MINUTE_IN_MILLIS * 6)); - assertThat(BatteryChartPreferenceController.validateSlotTimestamp(slotTimestampList)) - .isFalse(); - } - @Test public void testOnExpand_expandedIsTrue_addSystemEntriesToPreferenceGroup() { doReturn(1).when(mAppListGroup).getPreferenceCount(); @@ -582,13 +559,15 @@ public final class BatteryChartPreferenceControllerTest { .setTimestamps(any()); } - private static Map> createBatteryHistoryMap(int size) { - final Map> batteryHistoryMap = new HashMap<>(); - for (int index = 0; index < size; index++) { + private static Map> createBatteryHistoryMap() { + final Map> batteryHistoryMap = new HashMap<>(); + for (int index = 0; index < DESIRED_HISTORY_SIZE; index++) { final ContentValues values = new ContentValues(); values.put("batteryLevel", Integer.valueOf(100 - index)); final BatteryHistEntry entry = new BatteryHistEntry(values); - batteryHistoryMap.put(Long.valueOf(index + 1), Arrays.asList(entry)); + final Map entryMap = new HashMap<>(); + entryMap.put("fake_entry_key" + index, entry); + batteryHistoryMap.put(Long.valueOf(index + 1), entryMap); } return batteryHistoryMap; } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java index c3ab5e50ea9..a0fd5fd5f52 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoryLoaderTest.java @@ -23,7 +23,6 @@ import android.content.Context; import com.android.settings.testutils.FakeFeatureFactory; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.junit.Before; @@ -51,7 +50,7 @@ public final class BatteryHistoryLoaderTest { @Test public void testLoadIBackground_returnsMapFromPowerFeatureProvider() { - final Map> batteryHistoryMap = new HashMap<>(); + final Map> batteryHistoryMap = new HashMap<>(); doReturn(batteryHistoryMap).when(mFeatureFactory.powerUsageFeatureProvider) .getBatteryHistory(mContext); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java index 9539f0edb85..30df466bee1 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java @@ -145,35 +145,45 @@ public final class ConvertUtilsTest { // Creates the fake testing data. final int timeSlotSize = 2; final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L}; - final Map> batteryHistoryMap = new HashMap<>(); + final Map> batteryHistoryMap = + new HashMap<>(); + // Adds the index = 0 data. + Map entryMap = new HashMap<>(); + BatteryHistEntry entry = createBatteryHistEntry( + "package1", "label1", 5.0, 1L, 10L, 20L); + entryMap.put(entry.getKey(), entry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap); + // Adds the index = 1 data. batteryHistoryMap.put( - Long.valueOf(batteryHistoryKeys[0]), - Arrays.asList( - createBatteryHistEntry( - "package1", "label1", 5.0, 1L, 10L, 20L))); - batteryHistoryMap.put( - Long.valueOf(batteryHistoryKeys[1]), new ArrayList()); - batteryHistoryMap.put( - Long.valueOf(batteryHistoryKeys[2]), - Arrays.asList( - createBatteryHistEntry( - "package2", "label2", 10.0, 2L, 15L, 25L))); - batteryHistoryMap.put( - Long.valueOf(batteryHistoryKeys[3]), - Arrays.asList( - createBatteryHistEntry( - "package2", "label2", 15.0, 2L, 25L, 35L), - createBatteryHistEntry( - "package3", "label3", 5.0, 3L, 5L, 5L))); - batteryHistoryMap.put( - Long.valueOf(batteryHistoryKeys[4]), - Arrays.asList( - createBatteryHistEntry( - "package2", "label2", 30.0, 2L, 30L, 40L), - createBatteryHistEntry( - "package2", "label2", 75.0, 4L, 40L, 50L), - createBatteryHistEntry( - "package3", "label3", 5.0, 3L, 5L, 5L))); + Long.valueOf(batteryHistoryKeys[1]), + new HashMap()); + // Adds the index = 2 data. + entryMap = new HashMap<>(); + entry = createBatteryHistEntry( + "package2", "label2", 10.0, 2L, 15L, 25L); + entryMap.put(entry.getKey(), entry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap); + // Adds the index = 3 data. + entryMap = new HashMap<>(); + entry = createBatteryHistEntry( + "package2", "label2", 15.0, 2L, 25L, 35L); + entryMap.put(entry.getKey(), entry); + entry = createBatteryHistEntry( + "package3", "label3", 5.0, 3L, 5L, 5L); + entryMap.put(entry.getKey(), entry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[3]), entryMap); + // Adds the index = 4 data. + entryMap = new HashMap<>(); + entry = createBatteryHistEntry( + "package2", "label2", 30.0, 2L, 30L, 40L); + entryMap.put(entry.getKey(), entry); + entry = createBatteryHistEntry( + "package2", "label2", 75.0, 4L, 40L, 50L); + entryMap.put(entry.getKey(), entry); + entry = createBatteryHistEntry( + "package3", "label3", 5.0, 3L, 5L, 5L); + entryMap.put(entry.getKey(), entry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[4]), entryMap); final Map> resultMap = ConvertUtils.getIndexedUsageMap( From 8e4acdbf510428c2ab82ca1a32e701783a9f6017 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Wed, 14 Apr 2021 14:32:26 +0100 Subject: [PATCH 09/17] Refactor ChooseLockGenericController * Move all logics around aggregating password policies to the controller * Replace HIDE_DISABLED_PREFS and MINIMUM_QUALITY_KEY with HIDE_INSECURE_OPTIONS as all call sites are just using them to hide insecure screenlock options. * Remove password policy aggregation logic from ChooseLockPassword and make it use policies passed in. * Remove padlock from disabled screen lock options, per UX mock. * Increase char limit for some strings Bug: 177638284 Bug: 177641868 Bug: 182561862 Test: m RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.password Test: 1. set profile password quality/complexity and enroll device lock 2. set profile password quality/complexity and enroll work challenge 3. set parent password quality/complexity and enroll device lock 4. set parent password quality/complexity and enroll work challenge 5. set profile and parent password complexity, then enroll work challenge 6. set profile and parent password complexity, then unify work challenge 7. Enroll device lock during SUW Change-Id: Iba1d37e6f33eba7b7e8e1f805f8e37aaec108404 --- res/values/strings.xml | 8 +- .../biometrics/BiometricEnrollActivity.java | 7 +- .../BiometricEnrollIntroduction.java | 4 +- .../combination/BiometricsSettingsBase.java | 6 +- .../fingerprint/FingerprintSettings.java | 4 +- .../settings/password/ChooseLockGeneric.java | 86 ++---- .../password/ChooseLockGenericController.java | 269 ++++++++++++------ .../settings/password/ChooseLockPassword.java | 13 - .../ChooseLockTypeDialogFragment.java | 10 +- .../password/SetNewPasswordController.java | 13 +- .../password/SetupChooseLockGeneric.java | 19 +- .../password/SetupChooseLockPassword.java | 9 +- .../security/ScreenPinningSettings.java | 4 +- .../android/settings/users/UserSettings.java | 4 +- .../ChooseLockGenericControllerTest.java | 212 ++++++++++---- .../password/ChooseLockPasswordTest.java | 13 - .../SetNewPasswordControllerTest.java | 21 +- .../password/SetupChooseLockPasswordTest.java | 3 +- 18 files changed, 386 insertions(+), 319 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 742ed97ae2e..ee3ecb48948 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1311,16 +1311,16 @@ Choose screen lock - + Choose a screen lock - + Choose a new screen lock - + Choose a lock for work apps - + Choose a new work lock diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index eede22ac868..97cda4b5118 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -298,9 +298,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { private void launchChooseLock() { Log.d(TAG, "launchChooseLock"); Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent()); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true); @@ -350,8 +348,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { final Intent intent; // If only device credential was specified, ask the user to only set that up. intent = new Intent(this, ChooseLockGeneric.class); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); launchEnrollActivity(intent); } diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index b44c2c9da1a..c34b2843706 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -222,9 +222,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase private void launchChooseLock() { Intent intent = BiometricUtils.getChooseLockIntent(this, getIntent()); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); intent.putExtra(getExtraKeyForBiometric(), true); if (mUserId != UserHandle.USER_NULL) { diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java index c449ff4bfce..b5f6ef328a6 100644 --- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java +++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java @@ -19,7 +19,6 @@ import static android.app.Activity.RESULT_OK; import static com.android.settings.password.ChooseLockPattern.RESULT_FINISHED; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.hardware.face.FaceManager; @@ -193,9 +192,8 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { if (!launched) { Intent intent = BiometricUtils.getChooseLockIntent(getActivity(), getIntent()); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, + true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true); diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index a328f21e578..dbac4150380 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -685,9 +685,7 @@ public class FingerprintSettings extends SubSettings { // TODO: This should be cleaned up. ChooseLockGeneric should provide a way of // specifying arguments/requests, instead of relying on callers setting extras. intent.setClassName(SETTINGS_PACKAGE_NAME, ChooseLockGeneric.class.getName()); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, + intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 67fc7efc67c..a1826ba0cbc 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -75,8 +75,6 @@ import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.search.SearchFeatureProvider; -import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; -import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -112,8 +110,7 @@ public class ChooseLockGeneric extends SettingsActivity { private static final String KEY_SKIP_BIOMETRICS = "unlock_skip_biometrics"; private static final String PASSWORD_CONFIRMED = "password_confirmed"; private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation"; - public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; - public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs"; + public static final String HIDE_INSECURE_OPTIONS = "hide_insecure_options"; public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog"; public static final String KEY_LOCK_SETTINGS_FOOTER ="lock_settings_footer"; @@ -277,21 +274,20 @@ public class ChooseLockGeneric extends SettingsActivity { arguments, intent.getExtras()).getIdentifier(); mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mUserId); - mController = new ChooseLockGenericController( - getContext(), mUserId, mRequestedMinComplexity, - mOnlyEnforceDevicePasswordRequirement, - mLockPatternUtils); - - final int aggregatedComplexity = mController.getAggregatedPasswordComplexity(); - final boolean isComplexityProvidedByAdmin = - aggregatedComplexity > mRequestedMinComplexity - && aggregatedComplexity > PASSWORD_COMPLEXITY_NONE; + mController = new ChooseLockGenericController.Builder( + getContext(), mUserId, mLockPatternUtils) + .setAppRequestedMinComplexity(mRequestedMinComplexity) + .setEnforceDevicePasswordRequirementOnly(mOnlyEnforceDevicePasswordRequirement) + .setProfileToUnify(mUnificationProfileId) + .setHideInsecureScreenLockTypes(alwaysHideInsecureScreenLockTypes() + || intent.getBooleanExtra(HIDE_INSECURE_OPTIONS, false)) + .build(); // If the complexity is provided by the admin, do not get the caller app's name. // If the app requires, for example, low complexity, and the admin requires high // complexity, it does not make sense to show a footer telling the user it's the app // requesting a particular complexity because the admin-set complexity will override it. - mCallerAppName = isComplexityProvidedByAdmin ? null : + mCallerAppName = mController.isComplexityProvidedByAdmin() ? null : intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME); mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId); @@ -330,6 +326,10 @@ public class ChooseLockGeneric extends SettingsActivity { return super.onCreateView(inflater, container, savedInstanceState); } + protected boolean alwaysHideInsecureScreenLockTypes() { + return false; + } + private void updateActivityTitle() { if (mLockPatternUtils == null) { // mLockPatternUtils will be uninitialized if ChooseLockGenericFragment.onCreate() @@ -606,16 +606,12 @@ public class ChooseLockGeneric extends SettingsActivity { } if (quality == -1) { // If caller didn't specify password quality, show UI and allow the user to choose. - quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1); - quality = mController.upgradeQuality(quality); - final boolean hideDisabledPrefs = intent.getBooleanExtra( - HIDE_DISABLED_PREFS, false); final PreferenceScreen prefScreen = getPreferenceScreen(); if (prefScreen != null) { prefScreen.removeAll(); } addPreferences(); - disableUnusablePreferences(quality, hideDisabledPrefs); + disableUnusablePreferences(); updatePreferenceText(); updateCurrentPreference(); updatePreferenceSummaryIfNeeded(); @@ -746,71 +742,23 @@ public class ChooseLockGeneric extends SettingsActivity { return lock != null ? lock.preferenceKey : null; } - /*** - * Disables preferences that are less secure than required quality. The actual - * implementation is in disableUnusablePreferenceImpl. - * - * @param quality the requested quality. - * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise - * they're not shown at all. - */ - protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) { - disableUnusablePreferencesImpl(quality, hideDisabledPrefs); - } - /*** * Disables preferences that are less secure than required quality. * - * @param quality the requested quality. - * @param hideDisabled whether to hide disable screen lock options. */ - protected void disableUnusablePreferencesImpl(final int quality, - boolean hideDisabled) { + private void disableUnusablePreferences() { final PreferenceScreen entries = getPreferenceScreen(); - int adminEnforcedQuality = LockPatternUtils.credentialTypeToPasswordQuality( - mLockPatternUtils.getRequestedPasswordMetrics( - mUserId, mOnlyEnforceDevicePasswordRequirement).credType); - EnforcedAdmin enforcedAdmin = - RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(getActivity(), - mUserId); - // If we are to unify a work challenge at the end of the credential enrollment, manually - // merge any password policy from that profile here, so we are enrolling a compliant - // password. This is because once unified, the profile's password policy will - // be enforced on the new credential. - if (mUnificationProfileId != UserHandle.USER_NULL) { - int profileEnforceQuality = mDpm.getPasswordQuality(null, mUnificationProfileId); - if (profileEnforceQuality > adminEnforcedQuality) { - adminEnforcedQuality = profileEnforceQuality; - enforcedAdmin = EnforcedAdmin.combine(enforcedAdmin, - RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet( - getActivity(), mUnificationProfileId)); - } - } - for (ScreenLockType lock : ScreenLockType.values()) { String key = lock.preferenceKey; Preference pref = findPreference(key); if (pref instanceof RestrictedPreference) { boolean visible = mController.isScreenLockVisible(lock); - boolean enabled = mController.isScreenLockEnabled(lock, quality); - boolean disabledByAdmin = - mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality); - if (hideDisabled) { - visible = visible && enabled; - } + boolean enabled = mController.isScreenLockEnabled(lock); if (!visible) { entries.removePreference(pref); - } else if (disabledByAdmin && enforcedAdmin != null) { - ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin); } else if (!enabled) { - // we need to setDisabledByAdmin to null first to disable the padlock - // in case it was set earlier. - ((RestrictedPreference) pref).setDisabledByAdmin(null); - pref.setSummary(R.string.unlock_set_unlock_disabled_summary); pref.setEnabled(false); - } else { - ((RestrictedPreference) pref).setDisabledByAdmin(null); } } } diff --git a/src/com/android/settings/password/ChooseLockGenericController.java b/src/com/android/settings/password/ChooseLockGenericController.java index 6900e3d0f60..1b951d4f968 100644 --- a/src/com/android/settings/password/ChooseLockGenericController.java +++ b/src/com/android/settings/password/ChooseLockGenericController.java @@ -17,6 +17,7 @@ package com.android.settings.password; import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; @@ -24,6 +25,7 @@ import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.app.admin.PasswordMetrics; import android.content.Context; import android.os.UserHandle; +import android.os.UserManager; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -36,84 +38,140 @@ import java.util.List; /** * A controller for ChooseLockGeneric, and other similar classes which shows a list of possible - * screen locks for the user to choose from. + * screen lock types for the user to choose from. This is the main place where different + * restrictions on allowed screen lock types are aggregated in Settings. + * + * Each screen lock type has two states: whether it is visible and whether it is enabled. + * Visibility is affected by things like resource configs, whether it's for a managed profile, + * or whether the caller allows it or not. This is determined by + * {@link #isScreenLockVisible(ScreenLockType)}. For visible screen lock types, they can be disabled + * by a combination of admin policies and request from the calling app, which is determined by + * {@link #isScreenLockEnabled(ScreenLockType}. */ + public class ChooseLockGenericController { private final Context mContext; private final int mUserId; - @PasswordComplexity private final int mRequestedMinComplexity; + private final boolean mHideInsecureScreenLockTypes; + @PasswordComplexity private final int mAppRequestedMinComplexity; private final boolean mDevicePasswordRequirementOnly; - private ManagedLockPasswordProvider mManagedPasswordProvider; + private final int mUnificationProfileId; + private final ManagedLockPasswordProvider mManagedPasswordProvider; private final LockPatternUtils mLockPatternUtils; - public ChooseLockGenericController(Context context, int userId) { - this( - context, - userId, - PASSWORD_COMPLEXITY_NONE, - /* mOnlyEnforceDevicePasswordRequirement */ false, - new LockPatternUtils(context)); - } - - /** - * @param requestedMinComplexity specifies the min password complexity to be taken into account - * when determining the available screen lock types - */ public ChooseLockGenericController(Context context, int userId, - @PasswordComplexity int requestedMinComplexity, - boolean devicePasswordRequirementOnly, - LockPatternUtils lockPatternUtils) { - this( - context, - userId, - requestedMinComplexity, - devicePasswordRequirementOnly, - ManagedLockPasswordProvider.get(context, userId), - lockPatternUtils); - } - - @VisibleForTesting - ChooseLockGenericController( - Context context, - int userId, - @PasswordComplexity int requestedMinComplexity, - boolean devicePasswordRequirementOnly, - ManagedLockPasswordProvider managedLockPasswordProvider, - LockPatternUtils lockPatternUtils) { + ManagedLockPasswordProvider managedPasswordProvider, LockPatternUtils lockPatternUtils, + boolean hideInsecureScreenLockTypes, int appRequestedMinComplexity, + boolean devicePasswordRequirementOnly, int unificationProfileId) { mContext = context; mUserId = userId; - mRequestedMinComplexity = requestedMinComplexity; - mDevicePasswordRequirementOnly = devicePasswordRequirementOnly; - mManagedPasswordProvider = managedLockPasswordProvider; + mManagedPasswordProvider = managedPasswordProvider; mLockPatternUtils = lockPatternUtils; + mHideInsecureScreenLockTypes = hideInsecureScreenLockTypes; + mAppRequestedMinComplexity = appRequestedMinComplexity; + mDevicePasswordRequirementOnly = devicePasswordRequirementOnly; + mUnificationProfileId = unificationProfileId; + } + + /** Builder class for {@link ChooseLockGenericController} */ + public static class Builder { + private final Context mContext; + private final int mUserId; + private final ManagedLockPasswordProvider mManagedPasswordProvider; + private final LockPatternUtils mLockPatternUtils; + + private boolean mHideInsecureScreenLockTypes = false; + @PasswordComplexity private int mAppRequestedMinComplexity = PASSWORD_COMPLEXITY_NONE; + private boolean mDevicePasswordRequirementOnly = false; + private int mUnificationProfileId = UserHandle.USER_NULL; + + public Builder(Context context, int userId) { + this(context, userId, new LockPatternUtils(context)); + } + + public Builder(Context context, int userId, + LockPatternUtils lockPatternUtils) { + this( + context, + userId, + ManagedLockPasswordProvider.get(context, userId), + lockPatternUtils); + } + + @VisibleForTesting + Builder( + Context context, + int userId, + ManagedLockPasswordProvider managedLockPasswordProvider, + LockPatternUtils lockPatternUtils) { + mContext = context; + mUserId = userId; + mManagedPasswordProvider = managedLockPasswordProvider; + mLockPatternUtils = lockPatternUtils; + } + /** + * Sets the password complexity requested by the calling app via + * {@link android.app.admin.DevicePolicyManager#EXTRA_PASSWORD_COMPLEXITY}. + */ + public Builder setAppRequestedMinComplexity(int complexity) { + mAppRequestedMinComplexity = complexity; + return this; + } + + /** + * Sets whether the enrolment flow should discard any password policies originating from the + * work profile, even if the work profile currently has unified challenge. This can be + * requested by the calling app via + * {@link android.app.admin.DevicePolicyManager#EXTRA_DEVICE_PASSWORD_REQUIREMENT_ONLY}. + */ + public Builder setEnforceDevicePasswordRequirementOnly(boolean deviceOnly) { + mDevicePasswordRequirementOnly = deviceOnly; + return this; + } + + /** + * Sets the user ID of any profile whose work challenge should be unified at the end of this + * enrolment flow. This will lead to all password policies from that profile to be taken + * into consideration by this class, so that we are enrolling a compliant password. This is + * because once unified, the profile's password policy will be enforced on the new + * credential. + */ + public Builder setProfileToUnify(int profileId) { + mUnificationProfileId = profileId; + return this; + } + + /** + * Sets whether insecure screen lock types (NONE and SWIPE) should be hidden in the UI. + */ + public Builder setHideInsecureScreenLockTypes(boolean hide) { + mHideInsecureScreenLockTypes = hide; + return this; + } + + /** Creates {@link ChooseLockGenericController} instance. */ + public ChooseLockGenericController build() { + return new ChooseLockGenericController(mContext, mUserId, mManagedPasswordProvider, + mLockPatternUtils, mHideInsecureScreenLockTypes, mAppRequestedMinComplexity, + mDevicePasswordRequirementOnly, mUnificationProfileId); + } } /** - * Returns the highest quality among the specified {@code quality}, the password requirement - * set by device admins (legacy password quality metrics and password complexity), and the - * min password complexity requested by the calling app. - */ - public int upgradeQuality(int quality) { - // Compare specified quality and dpm quality - // TODO(b/142781408): convert from quality to credential type once PIN is supported. - int dpmUpgradedQuality = Math.max(quality, LockPatternUtils.credentialTypeToPasswordQuality( - getAggregatedPasswordMetrics().credType)); - return Math.max(dpmUpgradedQuality, - PasswordMetrics.complexityLevelToMinQuality(getAggregatedPasswordComplexity())); - } - - /** - * Whether the given screen lock type should be visible in the given context. + * Returns whether the given screen lock type should be visible in the given context. */ public boolean isScreenLockVisible(ScreenLockType type) { - final boolean managedProfile = mUserId != UserHandle.myUserId(); + final boolean managedProfile = mContext.getSystemService(UserManager.class) + .isManagedProfile(mUserId); switch (type) { case NONE: - return !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option) + return !mHideInsecureScreenLockTypes + && !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option) && !managedProfile; // Profiles should use unified challenge instead. case SWIPE: - return !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option) + return !mHideInsecureScreenLockTypes + && !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option) && !managedProfile; // Swipe doesn't make sense for profiles. case MANAGED: return mManagedPasswordProvider.isManagedPasswordChoosable(); @@ -128,29 +186,27 @@ public class ChooseLockGenericController { } /** - * Whether screen lock with {@code type} should be enabled. - * - * @param type The screen lock type. - * @param quality The minimum required quality. This can either be requirement by device policy - * manager or because some flow only makes sense with secure lock screens. + * Whether screen lock with {@code type} should be enabled assuming all relevant password + * requirements. The lock's visibility ({@link #isScreenLockVisible}) is not considered here. */ - public boolean isScreenLockEnabled(ScreenLockType type, int quality) { - return type.maxQuality >= quality; + public boolean isScreenLockEnabled(ScreenLockType type) { + return type.maxQuality >= upgradeQuality(PASSWORD_QUALITY_UNSPECIFIED); } /** - * Whether screen lock with {@code type} is disabled by device policy admin. - * - * @param type The screen lock type. - * @param adminEnforcedQuality The minimum quality that the admin enforces. + * Increases the given quality to be as high as the combined quality from all relevant + * password requirements. */ - public boolean isScreenLockDisabledByAdmin(ScreenLockType type, int adminEnforcedQuality) { - boolean disabledByAdmin = type.maxQuality < adminEnforcedQuality; - if (type == ScreenLockType.MANAGED) { - disabledByAdmin = disabledByAdmin - || !mManagedPasswordProvider.isManagedPasswordChoosable(); - } - return disabledByAdmin; + // TODO(b/142781408): convert from quality to credential type once PIN is supported. + public int upgradeQuality(int quality) { + return Math.max(quality, + Math.max( + LockPatternUtils.credentialTypeToPasswordQuality( + getAggregatedPasswordMetrics().credType), + PasswordMetrics.complexityLevelToMinQuality( + getAggregatedPasswordComplexity()) + ) + ); } /** @@ -175,43 +231,72 @@ public class ChooseLockGenericController { } /** - * Gets a list of screen locks that should be visible for the given quality. The returned list - * is ordered in the natural order of the enum (the order those enums were defined). - * - * @param quality The minimum quality required in the context of the current flow. This should - * be one of the constants defined in - * {@code DevicePolicyManager#PASSWORD_QUALITY_*}. - * @param includeDisabled Whether to include screen locks disabled by {@code quality} - * requirements in the returned list. + * Gets a list of screen lock types that should be visible for the given quality. The returned + * list is ordered in the natural order of the enum (the order those enums were defined). Screen + * locks disabled by password policy will not be returned. */ @NonNull - public List getVisibleScreenLockTypes(int quality, boolean includeDisabled) { - int upgradedQuality = upgradeQuality(quality); + public List getVisibleAndEnabledScreenLockTypes() { List locks = new ArrayList<>(); // EnumSet's iterator guarantees the natural order of the enums for (ScreenLockType lock : ScreenLockType.values()) { - if (isScreenLockVisible(lock)) { - if (includeDisabled || isScreenLockEnabled(lock, upgradedQuality)) { - locks.add(lock); - } + if (isScreenLockVisible(lock) && isScreenLockEnabled(lock)) { + locks.add(lock); } } return locks; } + /** + * Returns the combined password metrics from all relevant policies which affects the current + * user. Normally password policies set on the current user's work profile instance will be + * taken into consideration here iff the work profile doesn't have its own work challenge. + * By setting {@link #mUnificationProfileId}, the work profile's password policy will always + * be combined here. Alternatively, by setting {@link #mDevicePasswordRequirementOnly}, its + * password policy will always be disregarded here. + */ public PasswordMetrics getAggregatedPasswordMetrics() { - return mLockPatternUtils.getRequestedPasswordMetrics(mUserId, + PasswordMetrics metrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId, mDevicePasswordRequirementOnly); + if (mUnificationProfileId != UserHandle.USER_NULL) { + metrics.maxWith(mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId)); + } + return metrics; } + /** + * Returns the combined password complexity from all relevant policies which affects the current + * user. The same logic of handling work profile password policies as + * {@link #getAggregatedPasswordMetrics} applies here. + */ public int getAggregatedPasswordComplexity() { - return Math.max(mRequestedMinComplexity, + int complexity = Math.max(mAppRequestedMinComplexity, mLockPatternUtils.getRequestedPasswordComplexity( mUserId, mDevicePasswordRequirementOnly)); + if (mUnificationProfileId != UserHandle.USER_NULL) { + complexity = Math.max(complexity, + mLockPatternUtils.getRequestedPasswordComplexity(mUnificationProfileId)); + } + return complexity; } + /** + * Returns whether any screen lock type has been disabled only due to password policy + * from the admin. Will return {@code false} if the restriction is purely due to calling + * app's request. + */ public boolean isScreenLockRestrictedByAdmin() { return getAggregatedPasswordMetrics().credType != CREDENTIAL_TYPE_NONE - || getAggregatedPasswordComplexity() != PASSWORD_COMPLEXITY_NONE; + || isComplexityProvidedByAdmin(); + } + + /** + * Returns whether the aggregated password complexity is non-zero and comes from + * admin policy. + */ + public boolean isComplexityProvidedByAdmin() { + final int aggregatedComplexity = getAggregatedPasswordComplexity(); + return aggregatedComplexity > mAppRequestedMinComplexity + && aggregatedComplexity > PASSWORD_COMPLEXITY_NONE; } } diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index de377a73d67..6382abf9dbf 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -416,19 +416,6 @@ public class ChooseLockPassword extends SettingsActivity { mMinComplexity = intent.getIntExtra(EXTRA_KEY_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE); mMinMetrics = intent.getParcelableExtra(EXTRA_KEY_MIN_METRICS); if (mMinMetrics == null) mMinMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE); - // If we are to unify a work challenge at the end of the credential enrollment, manually - // merge any password policy from that profile here, so we are enrolling a compliant - // password. This is because once unified, the profile's password policy will - // be enforced on the new credential. - //TODO: Move this logic to ChooseLockGeneric; let ChooseLockGeneric be the only place - //where password requirement mixing happens. ChooseLockPassword simply enforces what's - //set via IntentBuilder.setPasswordRequirement() - if (mUnificationProfileId != UserHandle.USER_NULL) { - mMinMetrics.maxWith( - mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId)); - mMinComplexity = Math.max(mMinComplexity, - mLockPatternUtils.getRequestedPasswordComplexity(mUnificationProfileId)); - } if (intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT, false)) { diff --git a/src/com/android/settings/password/ChooseLockTypeDialogFragment.java b/src/com/android/settings/password/ChooseLockTypeDialogFragment.java index 8bc29763e2c..6ec70574b11 100644 --- a/src/com/android/settings/password/ChooseLockTypeDialogFragment.java +++ b/src/com/android/settings/password/ChooseLockTypeDialogFragment.java @@ -18,7 +18,6 @@ package com.android.settings.password; import android.app.Activity; import android.app.Dialog; -import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; @@ -100,7 +99,9 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final int userId = getArguments().getInt(ARG_USER_ID); - mController = new ChooseLockGenericController(getContext(), userId); + mController = new ChooseLockGenericController.Builder(getContext(), userId) + .setHideInsecureScreenLockTypes(true) + .build(); } @Override @@ -124,10 +125,7 @@ public class ChooseLockTypeDialogFragment extends InstrumentedDialogFragment public Dialog onCreateDialog(Bundle savedInstanceState) { Context context = getContext(); Builder builder = new Builder(context); - List locks = - mController.getVisibleScreenLockTypes( - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, - false /* includeDisabled */); + List locks = mController.getVisibleAndEnabledScreenLockTypes(); mAdapter = new ScreenLockAdapter(context, locks, mController); builder.setAdapter(mAdapter, this); builder.setTitle(R.string.setup_lock_settings_options_dialog_title); diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java index 03efa605d53..ef4ff75497c 100644 --- a/src/com/android/settings/password/SetNewPasswordController.java +++ b/src/com/android/settings/password/SetNewPasswordController.java @@ -19,7 +19,6 @@ package com.android.settings.password; import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FACE; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; -import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; import static com.android.internal.util.Preconditions.checkNotNull; @@ -145,10 +144,8 @@ final class SetNewPasswordController { private Bundle getBiometricChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - PASSWORD_QUALITY_SOMETHING); chooseLockExtras.putBoolean( - ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, true); return chooseLockExtras; @@ -156,10 +153,8 @@ final class SetNewPasswordController { private Bundle getFingerprintChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - PASSWORD_QUALITY_SOMETHING); chooseLockExtras.putBoolean( - ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true); return chooseLockExtras; @@ -167,10 +162,8 @@ final class SetNewPasswordController { private Bundle getFaceChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - PASSWORD_QUALITY_SOMETHING); chooseLockExtras.putBoolean( - ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true); + ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true); chooseLockExtras.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, true); return chooseLockExtras; diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java index 7818f0d2fc9..15a90e3fdbf 100644 --- a/src/com/android/settings/password/SetupChooseLockGeneric.java +++ b/src/com/android/settings/password/SetupChooseLockGeneric.java @@ -21,7 +21,6 @@ import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -160,22 +159,12 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { return SetupChooseLockGeneric.InternalActivity.class; } - /*** - * Disables preferences that are less secure than required quality and shows only secure - * screen lock options here. - * - * @param quality the requested quality. - */ @Override - protected void disableUnusablePreferences(final int quality, boolean hideDisabled) { + protected boolean alwaysHideInsecureScreenLockTypes() { // At this part of the flow, the user has already indicated they want to add a pin, - // pattern or password, so don't show "None" or "Slide". We disable them here and set - // the HIDE_DISABLED flag to true to hide them. This only happens for setup wizard. - // We do the following max check here since the device may already have a Device Admin - // installed with a policy we need to honor. - final int newQuality = Math.max(quality, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); - super.disableUnusablePreferencesImpl(newQuality, true /* hideDisabled */); + // pattern or password, so don't show "None" or "Slide". We disable them here. + // This only happens for setup wizard. + return true; } @Override diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java index 25f5a348904..7cf90c09929 100644 --- a/src/com/android/settings/password/SetupChooseLockPassword.java +++ b/src/com/android/settings/password/SetupChooseLockPassword.java @@ -17,7 +17,6 @@ package com.android.settings.password; import android.app.Activity; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -81,9 +80,11 @@ public class SetupChooseLockPassword extends ChooseLockPassword { super.onViewCreated(view, savedInstanceState); final Activity activity = getActivity(); ChooseLockGenericController chooseLockGenericController = - new ChooseLockGenericController(activity, mUserId); - boolean anyOptionsShown = chooseLockGenericController.getVisibleScreenLockTypes( - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false).size() > 0; + new ChooseLockGenericController.Builder(activity, mUserId) + .setHideInsecureScreenLockTypes(true) + .build(); + boolean anyOptionsShown = chooseLockGenericController + .getVisibleAndEnabledScreenLockTypes().size() > 0; boolean showOptionsButton = activity.getIntent().getBooleanExtra( ChooseLockGeneric.ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, false); if (!anyOptionsShown) { diff --git a/src/com/android/settings/security/ScreenPinningSettings.java b/src/com/android/settings/security/ScreenPinningSettings.java index 3fa098b826a..e219b44084d 100644 --- a/src/com/android/settings/security/ScreenPinningSettings.java +++ b/src/com/android/settings/security/ScreenPinningSettings.java @@ -136,8 +136,8 @@ public class ScreenPinningSettings extends SettingsPreferenceFragment if (passwordQuality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); chooseLockIntent.putExtra( - ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, + true); startActivityForResult(chooseLockIntent, CHANGE_LOCK_METHOD_REQUEST); return false; } diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index d88d8b5c316..5f14399a26b 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -432,8 +432,8 @@ public class UserSettings extends SettingsPreferenceFragment private void launchChooseLockscreen() { Intent chooseLockIntent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD); - chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + chooseLockIntent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS, + true); startActivityForResult(chooseLockIntent, REQUEST_CHOOSE_LOCK); } diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java index 02b89cba845..049a34969c1 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericControllerTest.java @@ -20,23 +20,31 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH; import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW; import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM; import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; +import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import static org.robolectric.RuntimeEnvironment.application; import android.app.admin.DevicePolicyManager; -import android.app.admin.DevicePolicyManager.PasswordComplexity; import android.app.admin.PasswordPolicy; +import android.os.UserHandle; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.testutils.shadow.ShadowUserManager; import org.junit.After; import org.junit.Before; @@ -48,10 +56,11 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.util.Arrays; +import java.util.Set; import java.util.regex.Pattern; @RunWith(RobolectricTestRunner.class) -@Config(shadows = SettingsShadowResources.class) +@Config(shadows = {ShadowUserManager.class, SettingsShadowResources.class}) public class ChooseLockGenericControllerTest { private ChooseLockGenericController mController; @@ -68,7 +77,7 @@ public class ChooseLockGenericControllerTest { when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true); setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); - mController = createController(PASSWORD_COMPLEXITY_NONE); + mController = createBuilder().build(); SettingsShadowResources.overrideResource(R.bool.config_hide_none_security_option, false); SettingsShadowResources.overrideResource(R.bool.config_hide_swipe_security_option, false); } @@ -95,8 +104,8 @@ public class ChooseLockGenericControllerTest { } @Test - public void isScreenLockVisible_notCurrentUser_shouldHideInsecure() { - mController = new ChooseLockGenericController(application, 1 /* userId */); + public void isScreenLockVisible_ManagedProfile_shouldHideInsecure() { + ShadowUserManager.getShadow().setManagedProfiles(Set.of(0)); assertWithMessage("SWIPE visible").that( mController.isScreenLockVisible(ScreenLockType.SWIPE)).isFalse(); assertWithMessage("NONE visible").that(mController.isScreenLockVisible(ScreenLockType.NONE)) @@ -112,62 +121,116 @@ public class ChooseLockGenericControllerTest { } @Test - public void isScreenLockEnabled_lowerQuality_shouldReturnFalse() { - for (ScreenLockType lock : ScreenLockType.values()) { - assertWithMessage(lock + " enabled").that( - mController.isScreenLockEnabled(lock, lock.maxQuality + 1)).isFalse(); - } + public void isScreenLockEnabled_Default() { + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test - public void isScreenLockEnabled_equalQuality_shouldReturnTrue() { - for (ScreenLockType lock : ScreenLockType.values()) { - assertWithMessage(lock + " enabled").that( - mController.isScreenLockEnabled(lock, lock.defaultQuality)).isTrue(); - } + public void isScreenLockEnabled_QualityUnspecified() { + setDevicePolicyPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test - public void isScreenLockEnabled_higherQuality_shouldReturnTrue() { - for (ScreenLockType lock : ScreenLockType.values()) { - assertWithMessage(lock + " enabled").that( - mController.isScreenLockEnabled(lock, lock.maxQuality - 1)).isTrue(); - } + public void isScreenLockEnabled_QualitySomething() { + setDevicePolicyPasswordQuality(PASSWORD_QUALITY_SOMETHING); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test - public void isScreenLockDisabledByAdmin_lowerQuality_shouldReturnTrue() { - doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable(); - for (ScreenLockType lock : ScreenLockType.values()) { - assertWithMessage(lock + " disabledByAdmin").that( - mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality + 1)).isTrue(); - } + public void isScreenLockEnabled_QualityNumeric() { + setDevicePolicyPasswordQuality(PASSWORD_QUALITY_NUMERIC); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test - public void isScreenLockDisabledByAdmin_equalQuality_shouldReturnFalse() { - doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable(); - for (ScreenLockType lock : ScreenLockType.values()) { - assertWithMessage(lock + " disabledByAdmin").that( - mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality)).isFalse(); - } + public void isScreenLockEnabled_QualityNumericComplex() { + setDevicePolicyPasswordQuality(PASSWORD_QUALITY_NUMERIC_COMPLEX); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test - public void isScreenLockDisabledByAdmin_higherQuality_shouldReturnFalse() { - doReturn(true).when(mManagedLockPasswordProvider).isManagedPasswordChoosable(); - for (ScreenLockType lock : ScreenLockType.values()) { - assertWithMessage(lock + " disabledByAdmin").that( - mController.isScreenLockDisabledByAdmin(lock, lock.maxQuality - 1)).isFalse(); - } + public void isScreenLockEnabled_QualityAlphabetic() { + setDevicePolicyPasswordQuality(PASSWORD_QUALITY_ALPHABETIC); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test - public void isScreenLockDisabledByAdmin_managedNotChoosable_shouldReturnTrue() { - doReturn(false).when(mManagedLockPasswordProvider).isManagedPasswordChoosable(); - assertWithMessage("MANANGED disabledByAdmin").that(mController.isScreenLockDisabledByAdmin( - ScreenLockType.MANAGED, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) - .isTrue(); + public void isScreenLockEnabled_QualityComplex() { + setDevicePolicyPasswordQuality(PASSWORD_QUALITY_COMPLEX); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); + } + + @Test + public void isScreenLockEnabled_NoneComplexity() { + when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean())) + .thenReturn(PASSWORD_COMPLEXITY_NONE); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); + } + + @Test + public void isScreenLockEnabled_lowComplexity() { + when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean())) + .thenReturn(PASSWORD_COMPLEXITY_LOW); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); + } + + @Test + public void isScreenLockEnabled_mediumComplexity() { + when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean())) + .thenReturn(PASSWORD_COMPLEXITY_MEDIUM); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); + } + + @Test + public void isScreenLockEnabled_highComplexity() { + when(mLockPatternUtils.getRequestedPasswordComplexity(anyInt(), anyBoolean())) + .thenReturn(PASSWORD_COMPLEXITY_HIGH); + assertThat(mController.isScreenLockEnabled(ScreenLockType.NONE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.SWIPE)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PATTERN)).isFalse(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PIN)).isTrue(); + assertThat(mController.isScreenLockEnabled(ScreenLockType.PASSWORD)).isTrue(); } @Test @@ -181,8 +244,8 @@ public class ChooseLockGenericControllerTest { @Test public void getVisibleScreenLockTypes_qualitySomething_shouldReturnPatterPinPassword() { - assertThat(mController.getVisibleScreenLockTypes( - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false)) + mController = createBuilder().setHideInsecureScreenLockTypes(true).build(); + assertThat(mController.getVisibleAndEnabledScreenLockTypes()) .isEqualTo(Arrays.asList( ScreenLockType.PATTERN, ScreenLockType.PIN, @@ -191,8 +254,7 @@ public class ChooseLockGenericControllerTest { @Test public void getVisibleScreenLockTypes_showDisabled_shouldReturnAllButManaged() { - assertThat(mController.getVisibleScreenLockTypes( - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, true)) + assertThat(mController.getVisibleAndEnabledScreenLockTypes()) .isEqualTo(Arrays.asList( ScreenLockType.NONE, ScreenLockType.SWIPE, @@ -223,31 +285,68 @@ public class ChooseLockGenericControllerTest { @Test public void upgradeQuality_complexityHigh_minQualityNumericComplex() { + mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_HIGH) + .build(); setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); - ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_HIGH); - assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) + assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX); } @Test public void upgradeQuality_complexityMedium_minQualityNumericComplex() { + mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_MEDIUM) + .build(); setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); - ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_MEDIUM); - assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) + assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX); } @Test public void upgradeQuality_complexityLow_minQualitySomething() { + mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW) + .build(); setDevicePolicyPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); - ChooseLockGenericController controller = createController(PASSWORD_COMPLEXITY_LOW); - assertThat(controller.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) + assertThat(mController.upgradeQuality(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED)) .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); } + @Test + public void getAggregatedPasswordComplexity_AppRequest() { + mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_HIGH) + .build(); + assertThat(mController.getAggregatedPasswordComplexity()) + .isEqualTo(PASSWORD_COMPLEXITY_HIGH); + } + + @Test + public void getAggregatedPasswordComplexity_DevicePolicy() { + mController = createBuilder().setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW) + .build(); + when(mLockPatternUtils.getRequestedPasswordComplexity(eq(UserHandle.myUserId()), eq(false))) + .thenReturn(PASSWORD_COMPLEXITY_MEDIUM); + + assertThat(mController.getAggregatedPasswordComplexity()) + .isEqualTo(PASSWORD_COMPLEXITY_MEDIUM); + } + + @Test + public void getAggregatedPasswordComplexity_ProfileUnification() { + mController = createBuilder() + .setProfileToUnify(123) + .setAppRequestedMinComplexity(PASSWORD_COMPLEXITY_LOW) + .build(); + when(mLockPatternUtils.getRequestedPasswordComplexity(eq(UserHandle.myUserId()), eq(false))) + .thenReturn(PASSWORD_COMPLEXITY_MEDIUM); + when(mLockPatternUtils.getRequestedPasswordComplexity(eq(123))) + .thenReturn(PASSWORD_COMPLEXITY_HIGH); + + assertThat(mController.getAggregatedPasswordComplexity()) + .isEqualTo(PASSWORD_COMPLEXITY_HIGH); + } + private void setDevicePolicyPasswordQuality(int quality) { PasswordPolicy policy = new PasswordPolicy(); policy.quality = quality; @@ -256,13 +355,10 @@ public class ChooseLockGenericControllerTest { .thenReturn(policy.getMinMetrics()); } - private ChooseLockGenericController createController( - @PasswordComplexity int minPasswordComplexity) { - return new ChooseLockGenericController( + private ChooseLockGenericController.Builder createBuilder() { + return new ChooseLockGenericController.Builder( application, 0 /* userId */, - minPasswordComplexity, - false, mManagedLockPasswordProvider, mLockPatternUtils); } diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 2233f1d1d00..7da9c505b8e 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -30,7 +30,6 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY; import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS; -import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -429,18 +428,6 @@ public class ChooseLockPasswordTest { "PIN must be at least 8 digits"); } - @Test - public void validateComplexityMergedFromUnificationUserOnCreate() { - ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW); - ShadowLockPatternUtils.setRequiredPasswordComplexity(123, PASSWORD_COMPLEXITY_HIGH); - - Intent intent = createIntentForPasswordValidation(null, PASSWORD_COMPLEXITY_NONE, - PASSWORD_QUALITY_NUMERIC); - intent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, 123); - assertPasswordValidationResultForIntent(LockscreenCredential.createNone(), intent, - "PIN must be at least 8 digits"); - } - private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) { return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get(); } diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java index 3034807baa6..f7b8d2d3f1b 100644 --- a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java @@ -19,8 +19,7 @@ package com.android.settings.password; import static android.content.pm.PackageManager.FEATURE_FACE; import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; -import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS; -import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY; +import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.HIDE_INSECURE_OPTIONS; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE; @@ -262,12 +261,9 @@ public final class SetNewPasswordControllerTest { private void compareFingerprintExtras(Bundle actualBundle) { assertEquals( - "Password quality must be something in order to config fingerprint.", - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, - actualBundle.getInt(MINIMUM_QUALITY_KEY)); - assertTrue( - "All disabled preference should be removed.", - actualBundle.getBoolean(HIDE_DISABLED_PREFS)); + "Insecure options must be disabled in order to config fingerprint.", + true, + actualBundle.getBoolean(HIDE_INSECURE_OPTIONS)); assertTrue( "Fingerprint enroll must request Gatekeeper Password.", actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE)); @@ -282,12 +278,9 @@ public final class SetNewPasswordControllerTest { private void compareFaceExtras(Bundle actualBundle) { assertEquals( - "Password quality must be something in order to config face.", - DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, - actualBundle.getInt(MINIMUM_QUALITY_KEY)); - assertTrue( - "All disabled preference should be removed.", - actualBundle.getBoolean(HIDE_DISABLED_PREFS)); + "Insecure options must be disabled in order to config face.", + true, + actualBundle.getBoolean(HIDE_INSECURE_OPTIONS)); assertTrue( "Face enroll must request Gatekeeper Password", actualBundle.getBoolean(EXTRA_KEY_REQUEST_GK_PW_HANDLE)); diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java index 5242e11a6e7..af4ae0b8a30 100644 --- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java @@ -198,8 +198,7 @@ public class SetupChooseLockPasswordTest { @Implements(ChooseLockGenericController.class) public static class ShadowChooseLockGenericController { @Implementation - protected List getVisibleScreenLockTypes(int quality, - boolean includeDisabled) { + protected List getVisibleScreenLockTypes() { return Collections.emptyList(); } } From 3b6e225a5c2745d43a66df255f44f44f94108928 Mon Sep 17 00:00:00 2001 From: ykhung Date: Fri, 7 May 2021 10:48:28 +0800 Subject: [PATCH 10/17] Fix the battery usage screen left alignment issue Bug: 187383692 Test: make SettingsRoboTests Change-Id: I9abb17562bea3727f31ce781cf452412a4ee7818 --- res/layout/battery_chart_graph.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layout/battery_chart_graph.xml b/res/layout/battery_chart_graph.xml index a3fcc405215..18e650ce1d4 100644 --- a/res/layout/battery_chart_graph.xml +++ b/res/layout/battery_chart_graph.xml @@ -18,7 +18,7 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingStart="?android:attr/listPreferredItemPaddingEnd" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" android:orientation="vertical"> From 955c8349ed678379f63c85581a5134385a5a177e Mon Sep 17 00:00:00 2001 From: Joe Bolinger Date: Thu, 6 May 2021 21:41:43 -0700 Subject: [PATCH 11/17] Prevent multi-sensor enrollment from doing nothing. Fix: 186499864 Test: manual (setup with managed account) Change-Id: If2b2623b2e348ef9d335c81189dbe23e4fe5f003 --- .../android/settings/biometrics/BiometricEnrollActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index eede22ac868..0cf82897a47 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -271,7 +271,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { mIsFingerprintEnrollable = fingerprintManager.getEnrolledFingerprints(mUserId).size() < fpProperties.get(0).maxEnrollmentsPerUser; - if (!mConfirmingCredentials && mGkPwHandle == null) { + if (!mConfirmingCredentials) { mConfirmingCredentials = true; if (!userHasPassword(mUserId)) { launchChooseLock(); From 1be773da62202726ce433a7abaffe05a8a231bf4 Mon Sep 17 00:00:00 2001 From: Yi-Ling Chuang Date: Fri, 7 May 2021 12:07:45 +0800 Subject: [PATCH 12/17] Turn on the transition flag Test: robotests Bug: 186701900 Change-Id: I09c821e17fca88ee532f6535031a52c4c832a1e8 --- src/com/android/settings/Utils.java | 2 +- .../android/settings/homepage/SettingsHomepageActivityTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index fd67aa813b7..6895fbb9c3f 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -1205,7 +1205,7 @@ public final class Utils extends com.android.settingslib.Utils { public static boolean isPageTransitionEnabled(Context context) { final boolean isSilkyHome = FeatureFlagUtils.isEnabled(context, FeatureFlags.SILKY_HOME); final boolean isTransitionEnabled = Settings.Global.getInt(context.getContentResolver(), - SETTINGS_SHARED_AXIS_ENABLED, 0) == 1; + SETTINGS_SHARED_AXIS_ENABLED, 1) == 1; return isSilkyHome && isTransitionEnabled; } diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java index 620f6d74b17..05547496b2a 100644 --- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java +++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java @@ -65,7 +65,7 @@ public class SettingsHomepageActivityTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - ShadowUtils.setIsPageTransitionEnabled(false); + ShadowUtils.setIsPageTransitionEnabled(true); } @Test From bc1e5321abc0e500da58304a3ba7ad658bc8548c Mon Sep 17 00:00:00 2001 From: Syaoran Kuo Date: Thu, 6 May 2021 17:50:14 +0800 Subject: [PATCH 13/17] Remove wifi related test. To add these case back, add a success case to avoid empty test error. Bug: 186372528 Test: atest SettingsComponentTest Change-Id: I6d973a244338f67e3d35e9657d1d46eba8ba4501 --- .../com/android/settings/wifi/WifiSettings2ActivityTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java b/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java index aa6b25244e3..b13a57a8460 100644 --- a/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java +++ b/tests/componenttests/src/com/android/settings/wifi/WifiSettings2ActivityTest.java @@ -43,6 +43,7 @@ import com.android.settings.testutils.CommonUtils; import com.android.settings.testutils.Constants; import com.android.settings.testutils.UiUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,7 +62,7 @@ public class WifiSettings2ActivityTest { BatterySaverButtonPreferenceControllerComponentTest.class.getSimpleName(); private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); - @Test + @Test @Ignore public void test_connect_to_wifi() throws Exception { //For some reason the ActivityScenario gets null activity here mInstrumentation.getTargetContext().startActivity( From 4280a7f897da029e79ced0ae43a5332b1fbac169 Mon Sep 17 00:00:00 2001 From: ykhung Date: Fri, 7 May 2021 12:27:38 +0800 Subject: [PATCH 14/17] Refine the interpolation rule and clip the usage time data Bug: 184807417 Test: make SettingsRoboTests Change-Id: I6c115beed34abd393e5c615cc59d3c4c323dfa0b --- .../BatteryChartPreferenceController.java | 2 +- .../settings/fuelgauge/ConvertUtils.java | 62 +++++++++++----- .../settings/fuelgauge/ConvertUtilsTest.java | 74 +++++++++++++++++-- 3 files changed, 114 insertions(+), 24 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index c4efef88ccd..f4c9b0ce775 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -223,7 +223,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll ConvertUtils.getIndexedUsageMap( mPrefContext, /*timeSlotSize=*/ CHART_LEVEL_ARRAY_SIZE - 1, mBatteryHistoryKeys, batteryHistoryMap, - /*purgeLowPercentageData=*/ true); + /*purgeLowPercentageAndFakeData=*/ true); forceRefreshUi(); Log.d(TAG, String.format( diff --git a/src/com/android/settings/fuelgauge/ConvertUtils.java b/src/com/android/settings/fuelgauge/ConvertUtils.java index 1f6600bc272..fc58e501af5 100644 --- a/src/com/android/settings/fuelgauge/ConvertUtils.java +++ b/src/com/android/settings/fuelgauge/ConvertUtils.java @@ -18,12 +18,15 @@ import android.content.ContentValues; import android.content.Context; import android.os.BatteryUsageStats; import android.os.UserHandle; +import android.text.format.DateUtils; +import android.util.Log; import androidx.annotation.VisibleForTesting; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.text.SimpleDateFormat; +import java.time.Duration; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -41,6 +44,8 @@ public final class ConvertUtils { private static final Map EMPTY_BATTERY_MAP = new HashMap<>(); private static final BatteryHistEntry EMPTY_BATTERY_HIST_ENTRY = new BatteryHistEntry(new ContentValues()); + // Maximum total time value for each slot cumulative data at most 2 hours. + private static final float TOTAL_TIME_THRESHOLD = DateUtils.HOUR_IN_MILLIS * 2; @VisibleForTesting static double PERCENTAGE_OF_TOTAL_THRESHOLD = 1f; @@ -145,7 +150,10 @@ public final class ConvertUtils { final int timeSlotSize, final long[] batteryHistoryKeys, final Map> batteryHistoryMap, - final boolean purgeLowPercentageData) { + final boolean purgeLowPercentageAndFakeData) { + if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) { + return new HashMap<>(); + } final Map> resultMap = new HashMap<>(); // Each time slot usage diff data = // Math.abs(timestamp[i+2] data - timestamp[i+1] data) + @@ -155,16 +163,10 @@ public final class ConvertUtils { for (int index = 0; index < timeSlotSize; index++) { final Long currentTimestamp = Long.valueOf(batteryHistoryKeys[index * timestampStride]); - // Uses empty list if the timestamp is default value. - if (currentTimestamp == 0) { - resultMap.put(Integer.valueOf(index), new ArrayList()); - continue; - } final Long nextTimestamp = Long.valueOf(batteryHistoryKeys[index * timestampStride + 1]); final Long nextTwoTimestamp = Long.valueOf(batteryHistoryKeys[index * timestampStride + 2]); - // Fetches BatteryHistEntry data from corresponding time slot. final Map currentBatteryHistMap = batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP); @@ -172,8 +174,17 @@ public final class ConvertUtils { batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP); final Map nextTwoBatteryHistMap = batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP); + // We should not get the empty list since we have at least one fake data to record + // the battery level and status in each time slot, the empty list is used to + // represent there is no enough data to apply interpolation arithmetic. + if (currentBatteryHistMap.isEmpty() + || nextBatteryHistMap.isEmpty() + || nextTwoBatteryHistMap.isEmpty()) { + resultMap.put(Integer.valueOf(index), new ArrayList()); + continue; + } - // Collects all keys in these three time slot records as population. + // Collects all keys in these three time slot records as all populations. final Set allBatteryHistEntryKeys = new HashSet<>(); allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet()); allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet()); @@ -193,12 +204,12 @@ public final class ConvertUtils { final BatteryHistEntry nextTwoEntry = nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY); // Cumulative values is a specific time slot for a specific app. - final long foregroundUsageTimeInMs = + long foregroundUsageTimeInMs = getDiffValue( currentEntry.mForegroundUsageTimeInMs, nextEntry.mForegroundUsageTimeInMs, nextTwoEntry.mForegroundUsageTimeInMs); - final long backgroundUsageTimeInMs = + long backgroundUsageTimeInMs = getDiffValue( currentEntry.mBackgroundUsageTimeInMs, nextEntry.mBackgroundUsageTimeInMs, @@ -212,8 +223,8 @@ public final class ConvertUtils { // Excludes entry since we don't have enough data to calculate. if (foregroundUsageTimeInMs == 0 - && backgroundUsageTimeInMs == 0 - && consumePower == 0) { + && backgroundUsageTimeInMs == 0 + && consumePower == 0) { continue; } final BatteryHistEntry selectedBatteryEntry = @@ -221,6 +232,21 @@ public final class ConvertUtils { if (selectedBatteryEntry == null) { continue; } + // Force refine the cumulative value since it may introduce deviation + // error since we will apply the interpolation arithmetic. + final float totalUsageTimeInMs = + foregroundUsageTimeInMs + backgroundUsageTimeInMs; + if (totalUsageTimeInMs > TOTAL_TIME_THRESHOLD) { + final float ratio = TOTAL_TIME_THRESHOLD / totalUsageTimeInMs; + Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s", + Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(), + Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(), + currentEntry)); + foregroundUsageTimeInMs = + Math.round(foregroundUsageTimeInMs * ratio); + backgroundUsageTimeInMs = + Math.round(backgroundUsageTimeInMs * ratio); + } batteryDiffEntryList.add( new BatteryDiffEntry( context, @@ -234,10 +260,10 @@ public final class ConvertUtils { diffEntry.setTotalConsumePower(totalConsumePower); } } - insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap); - if (purgeLowPercentageData) { - purgeLowPercentageData(resultMap); + if (purgeLowPercentageAndFakeData) { + purgeLowPercentageAndFakeData(resultMap); } + insert24HoursData(BatteryChartView.SELECTED_INDEX_ALL, resultMap); return resultMap; } @@ -273,13 +299,15 @@ public final class ConvertUtils { indexedUsageMap.put(Integer.valueOf(desiredIndex), resultList); } - private static void purgeLowPercentageData( + // Removes low percentage data and fake usage data, which will be zero value. + private static void purgeLowPercentageAndFakeData( final Map> indexedUsageMap) { for (List entries : indexedUsageMap.values()) { final Iterator iterator = entries.iterator(); while (iterator.hasNext()) { final BatteryDiffEntry entry = iterator.next(); - if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD) { + if (entry.getPercentOfTotal() < PERCENTAGE_OF_TOTAL_THRESHOLD + || FAKE_PACKAGE_NAME.equals(entry.getPackageName())) { iterator.remove(); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java index 30df466bee1..c4341ef91f3 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java @@ -140,6 +140,21 @@ public final class ConvertUtilsTest { .isEqualTo(ConvertUtils.FAKE_PACKAGE_NAME); } + @Test + public void testGetIndexedUsageMap_nullOrEmptyHistoryMap_returnEmptyCollection() { + final int timeSlotSize = 2; + final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L}; + + assertThat(ConvertUtils.getIndexedUsageMap( + mContext, timeSlotSize, batteryHistoryKeys, + /*batteryHistoryMap=*/ null, /*purgeLowPercentageAndFakeData=*/ true)) + .isEmpty(); + assertThat(ConvertUtils.getIndexedUsageMap( + mContext, timeSlotSize, batteryHistoryKeys, + new HashMap>(), + /*purgeLowPercentageAndFakeData=*/ true)) + .isEmpty(); + } @Test public void testGetIndexedUsageMap_returnsExpectedResult() { // Creates the fake testing data. @@ -147,21 +162,25 @@ public final class ConvertUtilsTest { final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L, 104L, 105L}; final Map> batteryHistoryMap = new HashMap<>(); + final BatteryHistEntry fakeEntry = createBatteryHistEntry( + ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L); // Adds the index = 0 data. Map entryMap = new HashMap<>(); BatteryHistEntry entry = createBatteryHistEntry( "package1", "label1", 5.0, 1L, 10L, 20L); entryMap.put(entry.getKey(), entry); + entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap); // Adds the index = 1 data. - batteryHistoryMap.put( - Long.valueOf(batteryHistoryKeys[1]), - new HashMap()); + entryMap = new HashMap<>(); + entryMap.put(fakeEntry.getKey(), fakeEntry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap); // Adds the index = 2 data. entryMap = new HashMap<>(); entry = createBatteryHistEntry( "package2", "label2", 10.0, 2L, 15L, 25L); entryMap.put(entry.getKey(), entry); + entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap); // Adds the index = 3 data. entryMap = new HashMap<>(); @@ -171,6 +190,7 @@ public final class ConvertUtilsTest { entry = createBatteryHistEntry( "package3", "label3", 5.0, 3L, 5L, 5L); entryMap.put(entry.getKey(), entry); + entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[3]), entryMap); // Adds the index = 4 data. entryMap = new HashMap<>(); @@ -183,12 +203,13 @@ public final class ConvertUtilsTest { entry = createBatteryHistEntry( "package3", "label3", 5.0, 3L, 5L, 5L); entryMap.put(entry.getKey(), entry); + entryMap.put(fakeEntry.getKey(), fakeEntry); batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[4]), entryMap); final Map> resultMap = ConvertUtils.getIndexedUsageMap( mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap, - /*purgeLowPercentageData=*/ false); + /*purgeLowPercentageAndFakeData=*/ false); assertThat(resultMap).hasSize(3); // Verifies the first timestamp result. @@ -213,7 +234,7 @@ public final class ConvertUtilsTest { final Map> purgedResultMap = ConvertUtils.getIndexedUsageMap( mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap, - /*purgeLowPercentageData=*/ true); + /*purgeLowPercentageAndFakeData=*/ true); assertThat(purgedResultMap).hasSize(3); // Verifies the first timestamp result. @@ -225,8 +246,49 @@ public final class ConvertUtilsTest { assertBatteryDiffEntry(entryList.get(0), 75, 40L, 50L); // Verifies the last 24 hours aggregate result. entryList = purgedResultMap.get(Integer.valueOf(-1)); + assertThat(entryList).hasSize(2); + // Verifies the fake data is cleared out. + assertThat(entryList.get(0).getPackageName()) + .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME); + assertThat(entryList.get(1).getPackageName()) + .isNotEqualTo(ConvertUtils.FAKE_PACKAGE_NAME); + } + + @Test + public void testGetIndexedUsageMap_usageTimeExceed_returnsExpectedResult() { + final int timeSlotSize = 1; + final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L}; + final Map> batteryHistoryMap = + new HashMap<>(); + final BatteryHistEntry fakeEntry = createBatteryHistEntry( + ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L); + // Adds the index = 0 data. + Map entryMap = new HashMap<>(); + entryMap.put(fakeEntry.getKey(), fakeEntry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap); + // Adds the index = 1 data. + entryMap = new HashMap<>(); + entryMap.put(fakeEntry.getKey(), fakeEntry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap); + // Adds the index = 2 data. + entryMap = new HashMap<>(); + final BatteryHistEntry entry = createBatteryHistEntry( + "package3", "label3", 500, 5L, 3600000L, 7200000L); + entryMap.put(entry.getKey(), entry); + batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap); + + final Map> purgedResultMap = + ConvertUtils.getIndexedUsageMap( + mContext, timeSlotSize, batteryHistoryKeys, batteryHistoryMap, + /*purgeLowPercentageAndFakeData=*/ true); + + assertThat(purgedResultMap).hasSize(2); + final List entryList = purgedResultMap.get(0); assertThat(entryList).hasSize(1); - assertBatteryDiffEntry(entryList.get(0), 68, 40L, 50L); + // Verifies the clipped usage time. + final BatteryDiffEntry resultEntry = entryList.get(0); + assertThat(resultEntry.mForegroundUsageTimeInMs).isEqualTo(2400000); + assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(4800000); } @Test From 3bc6bf43616a19423fdb484ea7dbdf6bd5df9047 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 7 May 2021 16:47:30 +0000 Subject: [PATCH 15/17] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I33d29fb6c9a4362b326a72b354aa44a219b813ba --- res/values-es-rUS/arrays.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-es-rUS/arrays.xml b/res/values-es-rUS/arrays.xml index b88ae64cdb1..a5c38db79da 100644 --- a/res/values-es-rUS/arrays.xml +++ b/res/values-es-rUS/arrays.xml @@ -102,7 +102,7 @@ "No validar" "Solicitar estado del certificado" "Exigir estado del certificado" - "Exigir estados de cert. no de confianza" + "Requerir estados de certificados no fiables" "Presionar botón" From b5d257a72d43c4bec050d11aa4c381b65b0ef2f5 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 7 May 2021 16:50:54 +0000 Subject: [PATCH 16/17] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Ib60837c4552e1516120c5c6f988fc4b103788f4a --- res/values-cs/strings.xml | 2 +- res/values-es-rUS/strings.xml | 2 +- res/values-es/strings.xml | 8 ++++---- res/values-fi/strings.xml | 2 +- res/values-fr-rCA/strings.xml | 6 +++--- res/values-hi/strings.xml | 4 ++-- res/values-in/strings.xml | 6 +++--- res/values-ml/strings.xml | 4 ++-- res/values-pl/strings.xml | 2 +- res/values-pt-rBR/strings.xml | 4 ++-- res/values-pt/strings.xml | 4 ++-- res/values-ro/strings.xml | 2 +- res/values-ru/strings.xml | 2 +- res/values-sv/strings.xml | 2 +- res/values-th/strings.xml | 6 +++--- res/values-zh-rCN/strings.xml | 6 +++--- 16 files changed, 31 insertions(+), 31 deletions(-) diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index e9286639ee2..21da6f7e2db 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -294,7 +294,7 @@ "Zobrazí vypínač, který vypíná funkci Smart Lock, biometrické odemykání a oznámení na obrazovce uzamčení" "Zamknout obrazovku při ztrátě důvěry" "Když bude možnost aktivována a poslední agent důvěry přestane být důvěryhodný, zařízení se zamkne." - "Žádná" + "Bez textu" "%1$d / %2$d" "Např. Tomův Android." "Zobrazit informace o profilu na zamčené obrazovce" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 443e282fc78..e28cd42ceee 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -3144,7 +3144,7 @@ "Usar siempre para llamadas" "Seleccionar SIM para datos" "Selecciona una SIM para los SMS" - "Cambiando SIM de datos, esto puede demorar unos minutos…" + "Cambiando SIM de datos. Este proceso puede tardar hasta un minuto." "Llamar con" "Seleccionar una tarjeta SIM" "SIM %1$d" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 5f5638d53b4..e0e48b063a7 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -3301,7 +3301,7 @@ "Volumen de notificaciones" "Tono de llamada del teléfono" "Sonido de notificación predeterminado" - "Sonido proporcionado de app" + "Sonido proporcionado por aplicación" "Sonido de notificación predeterminado" "Sonido de alarma predeterminado" "Vibrar en llamadas" @@ -3580,7 +3580,7 @@ "En la pantalla desplegable, muestra las notificaciones en una sola línea" "Sin sonido ni vibración" "Sin sonido ni vibración, y se muestra más abajo en la sección de conversaciones" - "Es posible que suene o vibre según los ajustes del teléfono" + "Puede sonar o vibrar según los ajustes del teléfono" "Cuando el dispositivo esté desbloqueado, muestra las notificaciones en la parte superior" "Todas las notificaciones de \"%1$s\"" "Todas las notificaciones de %1$s" @@ -4776,8 +4776,8 @@ "En rango" "Fuera de rango" "Añadir más" - "Activo / SIM" - "Inactivo / SIM" + "Activa / SIM" + "Inactiva / SIM" "Activa / SIM descargada" "Inactiva / SIM descargada" "Nombre y color de la SIM" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index e7979b399a9..5430717ac00 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -1623,7 +1623,7 @@ "Pyyhi kaikki tiedot" "Kaikki henkilökohtaiset tietosi ja ladatut sovellukset poistetaan. Toimintoa ei voi kumota." "Kaikki henkilökohtaiset tietosi poistetaan, mukaan lukien ladatut sovellukset ja SIM-kortit. Toimintoa ei voi kumota." - "Poista kaikki" + "Tyhjennä kaikki" "Palauttamista ei suoritettu, koska System Clear -palvelu ei ole käytettävissä." "Poistetaanko kaikki data?" "Tämä käyttäjä ei voi palauttaa tehdasasetuksia" diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index c88c38b9a6e..399f92e2c0f 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -3559,7 +3559,7 @@ "Afficher les conversations prioritaires en bulles" "Les conversations prioritaires s\'affichent dans le haut du volet déroulant. Vous pouvez aussi les configurer pour qu\'elles s\'affichent dans des bulles et interrompent le mode Ne pas déranger." "Les conversations prioritaires et modifiées s\'afficheront ici" - "Lorsque vous marquez des conversations comme prioritaires, ou si vous apportez d\'autres modifications aux conversations, elles s\'afficheront ici. \n\nPour modifier les paramètres de conversation : \nbalayez l\'écran du haut vers le bas pour ouvrir le volet déroulant, puis maintenez-le doigt sur une conversation." + "Lorsque vous marquez des conversations comme prioritaires, ou si vous apportez d\'autres modifications aux conversations, elles s\'afficheront ici. \n\nPour modifier les paramètres de conversation : \nbalayez l\'écran du haut vers le bas pour ouvrir le volet déroulant, puis maintenez le doigt sur une conversation." "Affichage silencieux et réduction" "Affichage silencieux" "Émettre un son" @@ -4778,8 +4778,8 @@ "Ajouter" "Services actifs/Carte SIM" "Services inactifs/Carte SIM" - "Services actifs/Cartes SIM téléchargées" - "Services inactifs/Cartes SIM téléchargées" + "Services actifs/Carte SIM téléchargée" + "Services inactifs/Carte SIM téléchargée" "Nom et couleur de la carte SIM" "Nom" "Couleur (utilisée par applis compatibles)" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index c42f598de0f..845c94529b6 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -3558,8 +3558,8 @@ "आपने जिन बातचीत में बदलाव किए हैं" "अहम बातचीत को बबल करें" "अहम बातचीत, पुल-डाउन शेड में सबसे ऊपर दिखती हैं. आप इन्हें बबल पर भी सेट कर सकते हैं और \'परेशान न करें\' मोड को रोक सकते हैं." - "यहां ऐसी बातचीत दिखेंगी जो ज़रूरी हैं और जिनमें बदलाव किए गए हैं" - "किसी बातचीत पर जब ज़रूरी का निशान लगाया जाता है या उनमें कोई बदलाव किया जाता है, तो वे यहां दिखेंगी. \n\nबातचीत की सेटिंग बदलने के लिए: \nस्क्रीन पर ऊपर से नीचे की ओर स्वाइप करें और पुल-डाउन शेड खोलें. इसके बाद, किसी बातचीत को दबाकर रखें." + "यहां प्राथमिकता वाली और ऐसी बातचीत दिखेंगी जिनमें बदलाव किए गए हैं" + "किसी बातचीत पर जब प्राथमिकता का निशान लगाया जाता है या उनमें कोई बदलाव किया जाता है, तो वे यहां दिखेंगी. \n\nबातचीत की सेटिंग बदलने के लिए: \nस्क्रीन पर ऊपर से नीचे की ओर स्वाइप करें और पुल-डाउन शेड खोलें. इसके बाद, किसी बातचीत को दबाकर रखें." "बिना आवाज़ के दिखाएं और छोटा करें" "बिना आवाज़ के दिखाएं" "रिंगटोन सेट करें" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index f51abd876cc..65a52643667 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -945,7 +945,7 @@ "Sertifikat tidak ditentukan. Sambungan tidak bersifat pribadi." "Nama jaringan terlalu panjang." "Domain harus ditentukan." - "Perlu sertifikat." + "Sertifikat diwajibkan." "WPS tersedia" " (WPS tersedia)" "Jaringan Wi‑Fi operator" @@ -1315,7 +1315,7 @@ "Gunakan %1$s untuk data seluler?" "Anda menggunakan %2$s untuk data seluler. Jika Anda beralih ke %1$s, %2$s tidak akan digunakan lagi untuk data seluler." "Gunakan %1$s" - "Perbarui kartu SIM piihan?" + "Perbarui kartu SIM pilihan?" "%1$s satu-satunya SIM di perangkat. Ingin menggunakan SIM ini untuk data seluler, panggilan telepon, dan SMS?" "Kode PIN SIM salah, sekarang Anda harus menghubungi operator untuk membuka kunci perangkat." @@ -1335,7 +1335,7 @@ "ID Peralatan" "Versi pita basis" "Versi kernel" - "Nomor versi" + "Nomor build" "Update sistem Google Play" "Tidak tersedia" "Status" diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml index 77c132f2b34..f84e80c98cd 100644 --- a/res/values-ml/strings.xml +++ b/res/values-ml/strings.xml @@ -2172,8 +2172,8 @@ "ലോക്ക് സ്‌ക്രീനിൽ നിന്നുള്ള കുറുക്കുവഴി" "ലോക്ക് സ്‌ക്രീനിൽ നിന്ന് ഓണാക്കാൻ \'ഫീച്ചർ കുറുക്കുവഴി\'യെ അനുവദിക്കുക. രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപിടിക്കുക." "ദൃശ്യതീവ്രതയേറിയ ടെക്‌സ്റ്റ്" - "സ്‌ക്രീൻ മാഗ്‌നിഫിക്കേഷൻ സ്വയമേവ അപ്‌ഡേറ്റുചെയ്യുക" - "അപ്ലിക്കേഷൻ സംക്രമണങ്ങളിൽ സ്‌ക്രീൻ മാഗ്‌നിഫിക്കേഷൻ അപ്‌ഡേറ്റുചെയ്യുക" + "സ്‌ക്രീൻ മാഗ്‌നിഫിക്കേഷൻ സ്വയമേവ അപ്‌ഡേറ്റ് ചെയ്യുക" + "ആപ്പ് സംക്രമണങ്ങളിൽ സ്‌ക്രീൻ മാഗ്‌നിഫിക്കേഷൻ അപ്‌ഡേറ്റ് ചെയ്യുക" "പവർബട്ടൺ കോൾ നിർത്തുന്നു" "വലിയ മൗസ് പോയിന്റർ" "ആനിമേഷനുകൾ നീക്കം ചെയ്യുക" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index c00b604fc42..f8646172d0a 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -2947,7 +2947,7 @@ "Jeśli ograniczysz mobilną transmisję danych w tle, niektóre aplikacje i usługi będą działać tylko przy połączeniu z Wi‑Fi." "Jeśli ograniczysz mobilną transmisję danych w tle, niektóre aplikacje i usługi będą działać tylko przy połączeniu z Wi‑Fi.\n\nTo ustawienie obowiązuje u wszystkich użytkowników tego tabletu." "Jeśli ograniczysz mobilną transmisję danych w tle, niektóre aplikacje i usługi będą działać tylko przy połączeniu z Wi‑Fi.\n\nTo ustawienie obowiązuje u wszystkich użytkowników tego telefonu." - "Ostrzeżenie:"\n"^1""^2" + "Alert:"\n"^1""^2" "^1"" ""^2"\n"limit" "Usunięte aplikacje" "Usunięte aplikacje i użytkownicy" diff --git a/res/values-pt-rBR/strings.xml b/res/values-pt-rBR/strings.xml index cb514db065e..59394280dbc 100644 --- a/res/values-pt-rBR/strings.xml +++ b/res/values-pt-rBR/strings.xml @@ -1315,7 +1315,7 @@ "Usar %1$s para dados móveis?" "Você está usando %2$s para dados móveis. Se alterar para %1$s, %2$s não será mais usada para dados móveis." "Usar %1$s" - "Atualiz. chip preferido?" + "Atualizar chip preferido?" "O %1$s é o único chip no seu dispositivo. Quer usá-lo para dados móveis, chamadas e mensagens SMS?" "Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo." @@ -1606,7 +1606,7 @@ "Os chips transferidos por download não podem ser limpos devido a um erro.\n\nReinicie o dispositivo e tente novamente." "Limpar todos os dados (redefinir para a configuração original)" "Limpar todos os dados" - "Essa ação apagará todos os dados do ""armazenamento interno"" do seu tablet, incluindo:\n\n"
  • "sua Conta do Google;"
  • \n
  • "configurações e dados do sistema e dos apps;"
  • \n
  • "apps transferidos."
  • + "Essa ação apagará todos os dados do ""armazenamento interno"" do seu tablet, incluindo:\n\n"
  • "Sua Conta do Google"
  • \n
  • "Configurações e dados do sistema e dos apps"
  • \n
  • "Apps instalados"
  • "Essa ação apagará todos os dados do ""armazenamento interno"" do seu smartphone, incluindo:\n\n"
  • "Sua Conta do Google"
  • \n
  • "Configurações e dados do sistema e dos apps"
  • \n
  • "Apps transferidos"
  • \n\n"No momento você está conectado às seguintes contas:\n" \n\n"Há outros usuários presentes neste dispositivo.\n" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index cb514db065e..59394280dbc 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -1315,7 +1315,7 @@ "Usar %1$s para dados móveis?" "Você está usando %2$s para dados móveis. Se alterar para %1$s, %2$s não será mais usada para dados móveis." "Usar %1$s" - "Atualiz. chip preferido?" + "Atualizar chip preferido?" "O %1$s é o único chip no seu dispositivo. Quer usá-lo para dados móveis, chamadas e mensagens SMS?" "Código PIN do chip incorreto. Entre em contato com a operadora para desbloquear o dispositivo." @@ -1606,7 +1606,7 @@ "Os chips transferidos por download não podem ser limpos devido a um erro.\n\nReinicie o dispositivo e tente novamente." "Limpar todos os dados (redefinir para a configuração original)" "Limpar todos os dados" - "Essa ação apagará todos os dados do ""armazenamento interno"" do seu tablet, incluindo:\n\n"
  • "sua Conta do Google;"
  • \n
  • "configurações e dados do sistema e dos apps;"
  • \n
  • "apps transferidos."
  • + "Essa ação apagará todos os dados do ""armazenamento interno"" do seu tablet, incluindo:\n\n"
  • "Sua Conta do Google"
  • \n
  • "Configurações e dados do sistema e dos apps"
  • \n
  • "Apps instalados"
  • "Essa ação apagará todos os dados do ""armazenamento interno"" do seu smartphone, incluindo:\n\n"
  • "Sua Conta do Google"
  • \n
  • "Configurações e dados do sistema e dos apps"
  • \n
  • "Apps transferidos"
  • \n\n"No momento você está conectado às seguintes contas:\n" \n\n"Há outros usuários presentes neste dispositivo.\n" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 8e142a8c358..532f9a9ad57 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -2304,7 +2304,7 @@ "Ridicată" "Setări" "Activată" - "Dezactivate" + "Dezactivată" "Previzualizare" "Opțiuni standard" "Limbă" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 2f90e0d761d..ba0779f4c4d 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -3648,7 +3648,7 @@ %d важного разговора
    "Важные разговоры" - "Показывать в верхней части списка разговоров и в виде всплывающих чатов" + "Показывать в верхней части списка разговоров и в виде всплывающих чатов:" "Показывать в верхней части списка разговоров" "Другие разговоры" "Разговоры, в которые вы вносили изменения:" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 8a43e218307..82a76da55c4 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -1627,7 +1627,7 @@ "Återställningen utfördes inte eftersom tjänsten för systemrensning inte är tillgänglig." "Vill du radera all data?" "Den här användaren kan inte återställa till standardinställningarna" - "Rensar" + "Raderar" "Vänta ..." "Samtalsinställningar" "Ställ in röstbrevlåda, vidarekoppla samtal, samtal väntar, nummerpres." diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index b67d72d4b6f..bf0d57663f3 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -874,7 +874,7 @@ "ที่อยู่ IP" "บันทึกผ่านทาง" "ข้อมูลรับรองของ %1$s" - "เมธอด EAP" + "วิธีการ EAP" "การตรวจสอบสิทธิ์เฟส 2" "ใบรับรอง CA" "สถานะใบรับรองออนไลน์" @@ -3031,8 +3031,8 @@ "ลบผู้ใช้" "ลบ" "ผู้ใช้ชั่วคราว" - "นำผู้เข้าร่วมออก" - "ต้องการนำผู้เข้าร่วมออกไหม" + "นำผู้ใช้ชั่วคราวออก" + "ต้องการนำผู้ใช้ชั่วคราวออกไหม" "ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้" "นำออก" "เปิดการโทร" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index ff1042de4fd..716dab65d79 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -3452,7 +3452,7 @@ "查看过去 7 天的所有应用" "高级" "工作通知" - "自动调节通知" + "自适应通知功能" "自适应通知优先级" "自动将优先级较低的通知设为无声通知" "自适应通知排序" @@ -3584,7 +3584,7 @@ "当设备处于解锁状态时,在屏幕顶端以横幅形式显示通知" "所有“%1$s”通知" "%1$s的所有通知" - "自动调节通知" + "自适应通知功能" 每天大约 %d 条通知 每天大约 %d 条通知 @@ -3601,7 +3601,7 @@ %d 个应用可以读取通知 %d 个应用可以读取通知 - "自动调节通知" + "自适应通知功能" "无" "没有任何已安装的应用请求通知使用权。" "授予通知使用权" From bf5dd80d4fa8e0cf95908bf76db6e8d949782255 Mon Sep 17 00:00:00 2001 From: ykhung Date: Sat, 8 May 2021 01:15:21 +0800 Subject: [PATCH 17/17] Fix corner case IndexOutOfBound exception for null content Bug: 184807417 Test: make SettingsRoboTests Change-Id: Icf35b4084bcea62c2879a100d1b35b5448d8276d --- .../settings/fuelgauge/BatteryChartPreferenceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java index f4c9b0ce775..3af0163354c 100644 --- a/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryChartPreferenceController.java @@ -185,7 +185,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll private void setBatteryHistoryMapInner( final Map> batteryHistoryMap) { // Resets all battery history data relative variables. - if (batteryHistoryMap == null) { + if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) { mBatteryIndexedMap = null; mBatteryHistoryKeys = null; mBatteryHistoryLevels = null;