From 5087e71b59666b46ab7a45a661e61762fbceaa96 Mon Sep 17 00:00:00 2001 From: Evan Severson Date: Wed, 14 Apr 2021 15:03:04 -0700 Subject: [PATCH 01/16] Update mic/camera toggles api Test: Build Bug: 181681375 Change-Id: I8c2cdc76490424e1bcaac93daefb3676e51de8ca --- .../android/settings/development/qstile/DevelopmentTiles.java | 4 ++-- .../display/AdaptiveSleepCameraStatePreferenceController.java | 2 +- src/com/android/settings/display/ScreenTimeoutSettings.java | 4 +--- .../display/SmartAutoRotateCameraStateController.java | 2 +- .../android/settings/display/SmartAutoRotateController.java | 3 ++- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java index 16084c080ce..c55d0cb354d 100644 --- a/src/com/android/settings/development/qstile/DevelopmentTiles.java +++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java @@ -371,7 +371,7 @@ public abstract class DevelopmentTiles extends TileService { mContext = getApplicationContext(); mSensorPrivacyManager = (SensorPrivacyManager) mContext.getSystemService( Context.SENSOR_PRIVACY_SERVICE); - mIsEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled(); + mIsEnabled = mSensorPrivacyManager.isAllSensorPrivacyEnabled(); mMetricsFeatureProvider = FeatureFactory.getFactory( mContext).getMetricsFeatureProvider(); mKeyguardManager = (KeyguardManager) mContext.getSystemService( @@ -392,7 +392,7 @@ public abstract class DevelopmentTiles extends TileService { mMetricsFeatureProvider.action(getApplicationContext(), SettingsEnums.QS_SENSOR_PRIVACY, isEnabled); mIsEnabled = isEnabled; - mSensorPrivacyManager.setSensorPrivacy(isEnabled); + mSensorPrivacyManager.setAllSensorPrivacy(isEnabled); } } diff --git a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java index 72a1c66a431..ba7a3aba752 100644 --- a/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepCameraStatePreferenceController.java @@ -43,7 +43,7 @@ public class AdaptiveSleepCameraStatePreferenceController { mPreference.setPositiveButtonText(R.string.allow); mPrivacyManager = SensorPrivacyManager.getInstance(context); mPrivacyManager.addSensorPrivacyListener(CAMERA, - enabled -> updateVisibility()); + (sensor, enabled) -> updateVisibility()); mPreference.setPositiveButtonOnClickListener(p -> { mPrivacyManager.setSensorPrivacy(CAMERA, false); }); diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java index 3c2a4f14e2f..bd4e0f20303 100644 --- a/src/com/android/settings/display/ScreenTimeoutSettings.java +++ b/src/com/android/settings/display/ScreenTimeoutSettings.java @@ -111,9 +111,7 @@ public class ScreenTimeoutSettings extends RadioButtonPickerFragment implements mPrivacyPreference.setLayoutResource(R.layout.preference_footer); mPrivacyManager = SensorPrivacyManager.getInstance(context); mPrivacyManager.addSensorPrivacyListener(CAMERA, - enabled -> { - mAdaptiveSleepController.updatePreference(); - }); + (sensor, enabled) -> mAdaptiveSleepController.updatePreference()); } @Override diff --git a/src/com/android/settings/display/SmartAutoRotateCameraStateController.java b/src/com/android/settings/display/SmartAutoRotateCameraStateController.java index 14807855521..9e2a7848d81 100644 --- a/src/com/android/settings/display/SmartAutoRotateCameraStateController.java +++ b/src/com/android/settings/display/SmartAutoRotateCameraStateController.java @@ -43,7 +43,7 @@ public class SmartAutoRotateCameraStateController extends BasePreferenceControll public SmartAutoRotateCameraStateController(Context context, String key) { super(context, key); mPrivacyManager = SensorPrivacyManager.getInstance(context); - mPrivacyManager.addSensorPrivacyListener(CAMERA, enabled -> { + mPrivacyManager.addSensorPrivacyListener(CAMERA, (sensor, enabled) -> { mPreference.setVisible(enabled); updateState(mPreference); }); diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java index e3b2665195b..cf2a9a60567 100644 --- a/src/com/android/settings/display/SmartAutoRotateController.java +++ b/src/com/android/settings/display/SmartAutoRotateController.java @@ -52,7 +52,8 @@ public class SmartAutoRotateController extends TogglePreferenceController implem super(context, preferenceKey); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); mPrivacyManager = SensorPrivacyManager.getInstance(context); - mPrivacyManager.addSensorPrivacyListener(CAMERA, enabled -> updateState(mPreference)); + mPrivacyManager + .addSensorPrivacyListener(CAMERA, (sensor, enabled) -> updateState(mPreference)); } @Override From 86fd923d6f5f84daf1fbe9035264f02675089627 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Fri, 16 Apr 2021 03:02:34 +0800 Subject: [PATCH 02/16] Update the style for collapsing toolbar The new version of collapsing toolbar has been updated and it needs the edge-to-edge configruation to work smoothly. Added the configuration for Notification history and removed useless styles. This change is also trying to reuse the layout that is from SettingsLib and remove the one from Settings. Bug: 183496853 Test: visual verified Change-Id: Iecfb96fe5ead91b0421050c3dfc1c1ab456aafff --- .../settings_collapsing_base_layout.xml | 68 ------------------- res/values/dimens.xml | 8 --- res/values/styles.xml | 6 +- res/values/themes.xml | 2 + .../settings/core/SettingsBaseActivity.java | 50 +------------- 5 files changed, 4 insertions(+), 130 deletions(-) delete mode 100644 res/layout/settings_collapsing_base_layout.xml diff --git a/res/layout/settings_collapsing_base_layout.xml b/res/layout/settings_collapsing_base_layout.xml deleted file mode 100644 index 97d249c00ac..00000000000 --- a/res/layout/settings_collapsing_base_layout.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 6047092f8d3..304feb82021 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -446,12 +446,4 @@ 2dp 1dp 2dp - - - 226dp - 270dp - 314dp - 174dp - 24dp - 24dp diff --git a/res/values/styles.xml b/res/values/styles.xml index 31f44dd609a..cb0027e2495 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -781,7 +781,7 @@ @*android:string/config_headlineFontFamily - - - diff --git a/src/com/android/settings/core/SettingsBaseActivity.java b/src/com/android/settings/core/SettingsBaseActivity.java index 569e4805b8d..e0e41dee2d2 100644 --- a/src/com/android/settings/core/SettingsBaseActivity.java +++ b/src/com/android/settings/core/SettingsBaseActivity.java @@ -49,8 +49,6 @@ import com.android.settingslib.drawer.Tile; import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.setupcompat.util.WizardManagerHelper; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -61,7 +59,6 @@ public class SettingsBaseActivity extends FragmentActivity { protected static final boolean DEBUG_TIMING = false; private static final String TAG = "SettingsBaseActivity"; private static final String DATA_SCHEME_PKG = "package"; - private static final int TOOLBAR_MAX_LINE_NUMBER = 2; // Serves as a temporary list of tiles to ignore until we heard back from the PM that they // are disabled. @@ -95,7 +92,7 @@ public class SettingsBaseActivity extends FragmentActivity { if (FeatureFlagUtils.isEnabled(this, FeatureFlags.SILKY_HOME) && isToolbarEnabled() && !isAnySetupWizard) { - super.setContentView(R.layout.settings_collapsing_base_layout); + super.setContentView(R.layout.collapsing_toolbar_base_layout); mCollapsingToolbarLayout = findViewById(R.id.collapsing_toolbar); } else { super.setContentView(R.layout.settings_base_layout); @@ -108,7 +105,6 @@ public class SettingsBaseActivity extends FragmentActivity { return; } setActionBar(toolbar); - initCollapsingToolbar(); if (DEBUG_TIMING) { Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime) + " ms"); @@ -207,50 +203,6 @@ public class SettingsBaseActivity extends FragmentActivity { return true; } - private void initCollapsingToolbar() { - if (mCollapsingToolbarLayout == null) { - return; - } - mCollapsingToolbarLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, - int oldLeft, int oldTop, int oldRight, int oldBottom) { - v.removeOnLayoutChangeListener(this); - final int count = getLineCount(); - if (count > TOOLBAR_MAX_LINE_NUMBER) { - ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams(); - lp.height = getResources() - .getDimensionPixelSize(R.dimen.toolbar_three_lines_height); - mCollapsingToolbarLayout.setLayoutParams(lp); - } else if (count == TOOLBAR_MAX_LINE_NUMBER) { - ViewGroup.LayoutParams lp = mCollapsingToolbarLayout.getLayoutParams(); - lp.height = - getResources().getDimensionPixelSize(R.dimen.toolbar_two_lines_height); - mCollapsingToolbarLayout.setLayoutParams(lp); - } - } - }); - } - - private int getLineCount() { - try { - final Class toolbarClazz = mCollapsingToolbarLayout.getClass(); - final Field textHelperField = toolbarClazz.getDeclaredField("collapsingTextHelper"); - textHelperField.setAccessible(true); - final Object textHelperObj = textHelperField.get(mCollapsingToolbarLayout); - - final Field layoutField = textHelperObj.getClass().getDeclaredField("textLayout"); - layoutField.setAccessible(true); - final Object layoutObj = layoutField.get(textHelperObj); - - final Method method = layoutObj.getClass().getDeclaredMethod("getLineCount"); - return (int) method.invoke(layoutObj); - } catch (Exception e) { - return 0; - } - } - - private void onCategoriesChanged(Set categories) { final int N = mCategoryListeners.size(); for (int i = 0; i < N; i++) { From 0d444129198b01b7312c0fe49bbde480edac5375 Mon Sep 17 00:00:00 2001 From: Jeremy Goldman Date: Tue, 20 Apr 2021 13:21:37 +0800 Subject: [PATCH 03/16] Make gear symbol in "Mobile Data Usage" RTL friendly replace toRightOf with toEndOf screenshot: https://screenshot.googleplex.com/76WVetFfqD69ffA bug: 182826851 Test: atest -c SettingsUnitTests Change-Id: I5ab886d9bcfc10b76bcf666852c1a29e7372efea --- res/layout/apps_filter_spinner.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/layout/apps_filter_spinner.xml b/res/layout/apps_filter_spinner.xml index 13d80786db2..1de570528be 100644 --- a/res/layout/apps_filter_spinner.xml +++ b/res/layout/apps_filter_spinner.xml @@ -36,7 +36,7 @@ android:layout_width="56dp" android:layout_height="56dp" android:layout_marginTop="12dp" - android:layout_toRightOf="@id/filter_spinner" + android:layout_toEndOf="@id/filter_spinner" android:contentDescription="@string/configure" android:scaleType="center" android:src="@drawable/ic_apps_filter_settings_24dp" From d758022916ce5ec69a287d53eb6cdb4cea783e05 Mon Sep 17 00:00:00 2001 From: Curtis Belmonte Date: Tue, 20 Apr 2021 16:52:23 -0700 Subject: [PATCH 04/16] Log new auth-related framework atoms for Android 12 Adds logging to Settings for new authentication and biometric atoms introduced as part of ag/13856328. Test: Manually trigger each case and verify log statements are called. Bug: 185136248 Change-Id: Ic41a89da4f148dc94864f140e85b55f63643681b --- .../biometrics/BiometricEnrollActivity.java | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index cede6a02351..0a2e5fe804d 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -16,6 +16,9 @@ package com.android.settings.biometrics; +import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL; +import static android.provider.Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED; + import android.annotation.NonNull; import android.app.admin.DevicePolicyManager; import android.app.settings.SettingsEnums; @@ -24,6 +27,7 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricManager.Authenticators; +import android.hardware.biometrics.BiometricManager.BiometricError; import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintManager; @@ -31,11 +35,11 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; -import android.provider.Settings; import android.util.Log; import androidx.annotation.Nullable; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; import com.android.settings.SetupWizardUtils; @@ -68,12 +72,14 @@ public class BiometricEnrollActivity extends InstrumentedActivity { public static final String EXTRA_SKIP_INTRO = "skip_intro"; private static final String SAVED_STATE_CONFIRMING_CREDENTIALS = "confirming_credentials"; + private static final String SAVED_STATE_ENROLL_ACTION_LOGGED = "enroll_action_logged"; private static final String SAVED_STATE_GK_PW_HANDLE = "gk_pw_handle"; public static final class InternalActivity extends BiometricEnrollActivity {} private int mUserId = UserHandle.myUserId(); private boolean mConfirmingCredentials; + private boolean mIsEnrollActionLogged; private boolean mIsFaceEnrollable; private boolean mIsFingerprintEnrollable; @Nullable private Long mGkPwHandle; @@ -91,15 +97,44 @@ public class BiometricEnrollActivity extends InstrumentedActivity { } if (savedInstanceState != null) { - mConfirmingCredentials = savedInstanceState - .getBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, false); + mConfirmingCredentials = savedInstanceState.getBoolean( + SAVED_STATE_CONFIRMING_CREDENTIALS, false); + mIsEnrollActionLogged = savedInstanceState.getBoolean( + SAVED_STATE_ENROLL_ACTION_LOGGED, false); if (savedInstanceState.containsKey(SAVED_STATE_GK_PW_HANDLE)) { mGkPwHandle = savedInstanceState.getLong(SAVED_STATE_GK_PW_HANDLE); } } - // Put the theme in the intent so it gets propagated to other activities in the flow + // Log a framework stats event if this activity was launched via intent action. final Intent intent = getIntent(); + if (!mIsEnrollActionLogged && ACTION_BIOMETRIC_ENROLL.equals(intent.getAction())) { + mIsEnrollActionLogged = true; + + // Get the current status for each authenticator type. + @BiometricError final int strongBiometricStatus; + @BiometricError final int weakBiometricStatus; + @BiometricError final int deviceCredentialStatus; + final BiometricManager bm = getSystemService(BiometricManager.class); + if (bm != null) { + strongBiometricStatus = bm.canAuthenticate(Authenticators.BIOMETRIC_STRONG); + weakBiometricStatus = bm.canAuthenticate(Authenticators.BIOMETRIC_WEAK); + deviceCredentialStatus = bm.canAuthenticate(Authenticators.DEVICE_CREDENTIAL); + } else { + strongBiometricStatus = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE; + weakBiometricStatus = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE; + deviceCredentialStatus = BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE; + } + + FrameworkStatsLog.write(FrameworkStatsLog.AUTH_ENROLL_ACTION_INVOKED, + strongBiometricStatus == BiometricManager.BIOMETRIC_SUCCESS, + weakBiometricStatus == BiometricManager.BIOMETRIC_SUCCESS, + deviceCredentialStatus == BiometricManager.BIOMETRIC_SUCCESS, + intent.hasExtra(EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED), + intent.getIntExtra(EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, 0)); + } + + // Put the theme in the intent so it gets propagated to other activities in the flow if (intent.getStringExtra(WizardManagerHelper.EXTRA_THEME) == null) { intent.putExtra( WizardManagerHelper.EXTRA_THEME, @@ -108,7 +143,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { // Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL. final int authenticators = intent.getIntExtra( - Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK); + EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK); Log.d(TAG, "Authenticators: " + authenticators); @@ -132,7 +167,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { } else { // If the caller is not setup wizard, and the user has something enrolled, finish. final BiometricManager bm = getSystemService(BiometricManager.class); - final @BiometricManager.BiometricError int result = bm.canAuthenticate(authenticators); + final @BiometricError int result = bm.canAuthenticate(authenticators); if (result != BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) { Log.e(TAG, "Unexpected result: " + result); finish(); @@ -159,6 +194,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity { protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(SAVED_STATE_CONFIRMING_CREDENTIALS, mConfirmingCredentials); + outState.putBoolean(SAVED_STATE_ENROLL_ACTION_LOGGED, mIsEnrollActionLogged); if (mGkPwHandle != null) { outState.putLong(SAVED_STATE_GK_PW_HANDLE, mGkPwHandle); } From f06f289a85a487eba50eed5cf2784c03b690c25c Mon Sep 17 00:00:00 2001 From: Chloris Kuo Date: Tue, 20 Apr 2021 19:03:56 -0700 Subject: [PATCH 05/16] NAS setting migration Cancel onboarding notification when user migrates from settings Test: make RunSettingsRoboTests Bug: 185428329 Change-Id: I8b6b2eb8340442907c363e686bbd0b32b62d0db0 --- .../NotificationAssistantPreferenceController.java | 6 +----- .../settings/notification/NotificationBackend.java | 4 ++-- ...otificationAssistantPreferenceControllerTest.java | 12 ++++++------ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java index 6237326f4e4..a46f1646113 100644 --- a/src/com/android/settings/notification/NotificationAssistantPreferenceController.java +++ b/src/com/android/settings/notification/NotificationAssistantPreferenceController.java @@ -77,11 +77,7 @@ public class NotificationAssistantPreferenceController extends TogglePreferenceC protected void setNotificationAssistantGranted(ComponentName cn) { if (Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NAS_SETTINGS_UPDATED, 0, mUserId) == 0) { - for (int profileId : mUserManager.getProfileIds(mUserId, false)) { - Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.NAS_SETTINGS_UPDATED, 1, profileId); - } - mNotificationBackend.resetDefaultNotificationAssistant(cn != null); + mNotificationBackend.setNASMigrationDoneAndResetDefault(mUserId, cn != null); } mNotificationBackend.setNotificationAssistantGranted(cn); } diff --git a/src/com/android/settings/notification/NotificationBackend.java b/src/com/android/settings/notification/NotificationBackend.java index b08d02cef26..e448dda20aa 100644 --- a/src/com/android/settings/notification/NotificationBackend.java +++ b/src/com/android/settings/notification/NotificationBackend.java @@ -570,9 +570,9 @@ public class NotificationBackend { } } - public void resetDefaultNotificationAssistant(boolean loadFromConfig) { + public void setNASMigrationDoneAndResetDefault(int userId, boolean loadFromConfig) { try { - sINM.resetDefaultNotificationAssistant(loadFromConfig); + sINM.setNASMigrationDoneAndResetDefault(userId, loadFromConfig); } catch (Exception e) { Log.w(TAG, "Error calling NoMan", e); } diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java index f6b72d963bc..9b45a9808eb 100644 --- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java @@ -122,13 +122,13 @@ public class NotificationAssistantPreferenceControllerTest { assertEquals(1, Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NAS_SETTINGS_UPDATED, 0, 10)); verify(mBackend, times(1)) - .resetDefaultNotificationAssistant(eq(true)); + .setNASMigrationDoneAndResetDefault(eq(0), eq(true)); //Test user enable again, migration should not happen mPreferenceController.setNotificationAssistantGranted(mNASComponent); //Number of invocations should not increase verify(mBackend, times(1)) - .resetDefaultNotificationAssistant(eq(true)); + .setNASMigrationDoneAndResetDefault(eq(0), eq(true)); } @Test @@ -146,13 +146,13 @@ public class NotificationAssistantPreferenceControllerTest { assertEquals(0, Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NAS_SETTINGS_UPDATED, 0, 20)); verify(mBackend, times(1)) - .resetDefaultNotificationAssistant(eq(true)); + .setNASMigrationDoneAndResetDefault(eq(0), eq(true)); //Test user enable again, migration should not happen mPreferenceController.setNotificationAssistantGranted(mNASComponent); //Number of invocations should not increase verify(mBackend, times(1)) - .resetDefaultNotificationAssistant(eq(true)); + .setNASMigrationDoneAndResetDefault(eq(0), eq(true)); } @Test @@ -170,13 +170,13 @@ public class NotificationAssistantPreferenceControllerTest { assertEquals(1, Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.NAS_SETTINGS_UPDATED, 0, 10)); verify(mBackend, times(1)) - .resetDefaultNotificationAssistant(eq(false)); + .setNASMigrationDoneAndResetDefault(eq(0), eq(false)); //Test user disable again, migration should not happen mPreferenceController.setChecked(false); //Number of invocations should not increase verify(mBackend, times(1)) - .resetDefaultNotificationAssistant(eq(false)); + .setNASMigrationDoneAndResetDefault(eq(0), eq(false)); } } From 54ded4cb5e717051b070eeaf177cb941e30e97a7 Mon Sep 17 00:00:00 2001 From: menghanli Date: Wed, 21 Apr 2021 13:10:14 +0800 Subject: [PATCH 06/16] [FAB] Improve the shortcut dialog ux after change accessibility button mode Problem: The "Customize accessibility button" link only exists when the user selects the FAB location, which may confuse and disorient the user Solution: It is hard to back to floating menu mode if we turns to navigation bar from "Customize accessibility button" setting. Added the link in the "navigation bar mode" can help on this problem. Fix: 183342563 Test: manual test Change-Id: Ife572b0962f3a57c34af56cd930a487c9d813c0c --- .../accessibility/AccessibilityEditDialogUtils.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java index 5402a9bc9e9..26c23137729 100644 --- a/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java +++ b/src/com/android/settings/accessibility/AccessibilityEditDialogUtils.java @@ -26,6 +26,7 @@ import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.style.ImageSpan; @@ -320,8 +321,13 @@ public class AccessibilityEditDialogUtils { } private static CharSequence retrieveSummary(Context context, int lineHeight) { - return AccessibilityUtil.isFloatingMenuEnabled(context) - ? getSummaryStringWithLink(context) : getSummaryStringWithIcon(context, lineHeight); + final SpannableStringBuilder sb = new SpannableStringBuilder(); + if (!AccessibilityUtil.isFloatingMenuEnabled(context)) { + sb.append(getSummaryStringWithIcon(context, lineHeight)); + sb.append("\n\n"); + } + sb.append(getCustomizeAccessibilityButtonLink(context)); + return sb; } private static int retrieveSoftwareShortcutImageResId(Context context) { @@ -330,7 +336,7 @@ public class AccessibilityEditDialogUtils { : R.drawable.accessibility_shortcut_type_software; } - private static CharSequence getSummaryStringWithLink(Context context) { + private static CharSequence getCustomizeAccessibilityButtonLink(Context context) { final View.OnClickListener linkListener = v -> new SubSettingLauncher(context) .setDestination(AccessibilityButtonFragment.class.getName()) .setSourceMetricsCategory( From 2cc7431fa34e9f3812885f221280be00a4ce0073 Mon Sep 17 00:00:00 2001 From: "Wesley.CW Wang" Date: Wed, 21 Apr 2021 20:13:55 +0800 Subject: [PATCH 07/16] Update app usage page active time format - Make the text of active time support different states like foreground or background usage time less than one minutes Bug: 178197718 Test: make SettingsRoboTests Change-Id: I20be88e5b23a679c15f97bac4b9d400557685463 --- res/values/strings.xml | 31 +++++ .../fuelgauge/AdvancedPowerUsageDetail.java | 66 +++++++--- .../AdvancedPowerUsageDetailTest.java | 114 +++++++++++++++++- 3 files changed, 194 insertions(+), 17 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 1ca471f3af6..cf712e07a26 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6255,8 +6255,39 @@ Since full charge Manage battery usage + ^1 total • ^2 background for past 24 hr + + ^1 total • ^2 background for ^3 + + + Total less than a minute for past 24 hr + + Total less than a minute for ^1 + + + Background less than a minute for past 24 hr + + Background less than a minute for ^1 + + + ^1 total for past 24 hr + + ^1 total for ^2 + + + ^1 background for past 24 hr + + ^1 background for ^2 + + + ^1 total • background less than a minute for past 24 hr + + ^1 total • background less than a minute for ^2 + + + No usage for past 24 hr Battery left estimate is based on your device usage diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 432224d537a..3ef7c455302 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -27,6 +27,7 @@ import android.os.Bundle; import android.os.UserHandle; import android.text.Html; import android.text.TextUtils; +import android.text.format.DateUtils; import android.util.Log; import android.view.View; @@ -282,20 +283,8 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements final long foregroundTimeMs = bundle.getLong(EXTRA_FOREGROUND_TIME); final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME); - final long totalTimeMs = foregroundTimeMs + backgroundTimeMs; - //TODO(b/178197718) Refine the layout - controller.setSummary(TextUtils.expandTemplate( - getText(R.string.battery_total_and_background_usage), - StringUtil.formatElapsedTime( - getContext(), - totalTimeMs, - /* withSeconds */ false, - /* collapseTimeUnit */ false), - StringUtil.formatElapsedTime( - getContext(), - backgroundTimeMs, - /* withSeconds */ false, - /* collapseTimeUnit */ false))); + //TODO(b/178197718) Update layout to support multiple lines + controller.setSummary(getAppActiveTime(foregroundTimeMs, backgroundTimeMs)); controller.done(context, true /* rebindActions */); } @@ -388,4 +377,53 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements private void updatePreferenceState(RadioButtonPreference preference, String selectedKey) { preference.setChecked(selectedKey.equals(preference.getKey())); } + + //TODO(b/178197718) Update method to support time period + private CharSequence getAppActiveTime(long foregroundTimeMs, long backgroundTimeMs) { + final long totalTimeMs = foregroundTimeMs + backgroundTimeMs; + final CharSequence usageTimeSummary; + + if (totalTimeMs == 0) { + usageTimeSummary = getText(R.string.battery_not_usage); + // Shows background summary only if we don't have foreground usage time. + } else if (foregroundTimeMs == 0 && backgroundTimeMs != 0) { + usageTimeSummary = backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS ? + getText(R.string.battery_background_usage_less_minute) : + TextUtils.expandTemplate(getText(R.string.battery_background_usage), + StringUtil.formatElapsedTime( + getContext(), + backgroundTimeMs, + /* withSeconds */ false, + /* collapseTimeUnit */ false)); + // Shows total usage summary only if total usage time is small. + } else if (totalTimeMs < DateUtils.MINUTE_IN_MILLIS) { + usageTimeSummary = getText(R.string.battery_total_usage_less_minute); + // Shows different total usage summary when background usage time is small. + } else if (backgroundTimeMs < DateUtils.MINUTE_IN_MILLIS) { + usageTimeSummary = TextUtils.expandTemplate( + getText(backgroundTimeMs == 0 ? + R.string.battery_total_usage : + R.string.battery_total_usage_and_background_less_minute_usage), + StringUtil.formatElapsedTime( + getContext(), + totalTimeMs, + /* withSeconds */ false, + /* collapseTimeUnit */ false)); + // Shows default summary. + } else { + usageTimeSummary = TextUtils.expandTemplate( + getText(R.string.battery_total_and_background_usage), + StringUtil.formatElapsedTime( + getContext(), + totalTimeMs, + /* withSeconds */ false, + /* collapseTimeUnit */ false), + StringUtil.formatElapsedTime( + getContext(), + backgroundTimeMs, + /* withSeconds */ false, + /* collapseTimeUnit */ false)); + } + return usageTimeSummary; + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index a288c3a84c2..dd10a9e1556 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -249,14 +249,122 @@ public class AdvancedPowerUsageDetailTest { } @Test - public void testInitHeader_hasCorrectSummary() { - mFragment.mAppEntry = null; + public void testInitHeader_noUsageTime_hasCorrectSummary() { + Bundle bundle = new Bundle(2); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, /* value */ 0); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, /* value */ 0); + when(mFragment.getArguments()).thenReturn(bundle); + mFragment.initHeader(); ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); verify(mEntityHeaderController).setSummary(captor.capture()); assertThat(captor.getValue().toString()) - .isEqualTo("0 min total • 0 min background for past 24 hr"); + .isEqualTo("No usage for past 24 hr"); + } + + @Test + public void testInitHeader_backgroundTwoMinutesForegroundZero_hasCorrectSummary() { + final long backgroundTimeTwoMinutes = 120000; + final long foregroundTimeZero = 0; + Bundle bundle = new Bundle(2); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeTwoMinutes); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero); + when(mFragment.getArguments()).thenReturn(bundle); + + mFragment.initHeader(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); + verify(mEntityHeaderController).setSummary(captor.capture()); + assertThat(captor.getValue().toString()) + .isEqualTo("2 min background for past 24 hr"); + } + + @Test + public void testInitHeader_backgroundLessThanAMinutesForegroundZero_hasCorrectSummary() { + final long backgroundTimeLessThanAMinute = 59999; + final long foregroundTimeZero = 0; + Bundle bundle = new Bundle(2); + bundle.putLong( + AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanAMinute); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeZero); + when(mFragment.getArguments()).thenReturn(bundle); + + mFragment.initHeader(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); + verify(mEntityHeaderController).setSummary(captor.capture()); + assertThat(captor.getValue().toString()) + .isEqualTo("Background less than a minute for past 24 hr"); + } + + @Test + public void testInitHeader_totalUsageLessThanAMinutes_hasCorrectSummary() { + final long backgroundTimeLessThanHalfMinute = 20000; + final long foregroundTimeLessThanHalfMinute = 20000; + Bundle bundle = new Bundle(2); + bundle.putLong( + AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeLessThanHalfMinute); + bundle.putLong( + AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeLessThanHalfMinute); + when(mFragment.getArguments()).thenReturn(bundle); + + mFragment.initHeader(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); + verify(mEntityHeaderController).setSummary(captor.capture()); + assertThat(captor.getValue().toString()) + .isEqualTo("Total less than a minute for past 24 hr"); + } + + @Test + public void testInitHeader_TotalAMinutesBackgroundLessThanAMinutes_hasCorrectSummary() { + final long backgroundTimeZero = 59999; + final long foregroundTimeTwoMinutes = 1; + Bundle bundle = new Bundle(2); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes); + when(mFragment.getArguments()).thenReturn(bundle); + + mFragment.initHeader(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); + verify(mEntityHeaderController).setSummary(captor.capture()); + assertThat(captor.getValue().toString()) + .isEqualTo("1 min total • background less than a minute for past 24 hr"); + } + + @Test + public void testInitHeader_TotalAMinutesBackgroundZero_hasCorrectSummary() { + final long backgroundTimeZero = 0; + final long foregroundTimeAMinutes = 60000; + Bundle bundle = new Bundle(2); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeZero); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeAMinutes); + when(mFragment.getArguments()).thenReturn(bundle); + + mFragment.initHeader(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); + verify(mEntityHeaderController).setSummary(captor.capture()); + assertThat(captor.getValue().toString()) + .isEqualTo("1 min total for past 24 hr"); + } + + @Test + public void testInitHeader_foregroundTwoMinutesBackgroundFourMinutes_hasCorrectSummary() { + final long backgroundTimeFourMinute = 240000; + final long foregroundTimeTwoMinutes = 120000; + Bundle bundle = new Bundle(2); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_BACKGROUND_TIME, backgroundTimeFourMinute); + bundle.putLong(AdvancedPowerUsageDetail.EXTRA_FOREGROUND_TIME, foregroundTimeTwoMinutes); + when(mFragment.getArguments()).thenReturn(bundle); + mFragment.initHeader(); + + ArgumentCaptor captor = ArgumentCaptor.forClass(CharSequence.class); + verify(mEntityHeaderController).setSummary(captor.capture()); + assertThat(captor.getValue().toString()) + .isEqualTo("6 min total • 4 min background for past 24 hr"); } @Test From d2658b57d8c4ff0b79e985b7e68cbd67d0103815 Mon Sep 17 00:00:00 2001 From: Peter_Liang Date: Wed, 21 Apr 2021 22:08:45 +0800 Subject: [PATCH 08/16] Fix the entire text is aligned middle of the Vision setting screen. Root cause: The preferenceStyle attribute was overridden in the PreferenceTheme.SetupWizard style. Solution: Remove the overriden preferenceStyle. Bug: 183086481 Test: manual test Change-Id: I60d127baef9274170a31eaf3cfbd210312334311 --- res/values/styles_preference.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml index c162fc46b5b..5ad553a4ee4 100644 --- a/res/values/styles_preference.xml +++ b/res/values/styles_preference.xml @@ -30,7 +30,6 @@