From ae84ac3530477f0db1f8e2312d7ac5836594384d Mon Sep 17 00:00:00 2001 From: Ahan Wu Date: Wed, 15 Mar 2023 15:54:16 +0000 Subject: [PATCH 1/5] Use GlifLayout#setDescriptionText in SetupChooseLockGenericFragment 1. Use GlifLayout#setDescriptionText to align UX. 2. Remove redundant layout resources. 3. Add two new robotests. Bug: 236948821 Test: make RunSettingsRoboTests ROBOTEST_FILTER=SetupChooseLockGenericTest Test: Check UI manually Change-Id: I85cc984527fcc746e835d8fa508e78c96dfdcb94 --- ..._choose_lock_generic_biometrics_header.xml | 26 ---------- .../setup_choose_lock_generic_header.xml | 26 ---------- .../password/SetupChooseLockGeneric.java | 15 ++++-- .../password/SetupChooseLockGenericTest.java | 50 ++++++++++++++++++- 4 files changed, 58 insertions(+), 59 deletions(-) delete mode 100644 res/layout/setup_choose_lock_generic_biometrics_header.xml delete mode 100644 res/layout/setup_choose_lock_generic_header.xml diff --git a/res/layout/setup_choose_lock_generic_biometrics_header.xml b/res/layout/setup_choose_lock_generic_biometrics_header.xml deleted file mode 100644 index daeeedd845d..00000000000 --- a/res/layout/setup_choose_lock_generic_biometrics_header.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - diff --git a/res/layout/setup_choose_lock_generic_header.xml b/res/layout/setup_choose_lock_generic_header.xml deleted file mode 100644 index 7ec16d2c420..00000000000 --- a/res/layout/setup_choose_lock_generic_header.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java index 2f136e68f4c..551789d3ff2 100644 --- a/src/com/android/settings/password/SetupChooseLockGeneric.java +++ b/src/com/android/settings/password/SetupChooseLockGeneric.java @@ -109,6 +109,7 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { super.onViewCreated(view, savedInstanceState); GlifPreferenceLayout layout = (GlifPreferenceLayout) view; + layout.setDescriptionText(loadDescriptionText()); layout.setDividerItemDecoration(new SettingsDividerItemDecoration(getContext())); layout.setDividerInset(getContext().getResources().getDimensionPixelSize( R.dimen.sud_items_glif_text_divider_inset)); @@ -129,11 +130,9 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { @Override protected void addHeaderView() { - if (isForBiometric()) { - setHeaderView(R.layout.setup_choose_lock_generic_biometrics_header); - } else { - setHeaderView(R.layout.setup_choose_lock_generic_header); - } + // The original logic has been moved to onViewCreated and + // uses GlifLayout#setDescriptionText instead, + // keep empty body here since we won't call super method. } @Override @@ -239,6 +238,12 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { private boolean isForBiometric() { return mForFingerprint || mForFace || mForBiometrics; } + + String loadDescriptionText() { + return getString(isForBiometric() + ? R.string.lock_settings_picker_biometrics_added_security_message + : R.string.setup_lock_settings_picker_message); + } } public static class InternalActivity extends ChooseLockGeneric.InternalActivity { diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java index cd79f58ee31..494d3f0671b 100644 --- a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java @@ -23,15 +23,20 @@ import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_R import static com.google.common.truth.Truth.assertThat; -import static org.robolectric.Shadows.shadowOf; - import android.content.Intent; +import android.text.TextUtils; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; + +import com.android.settings.password.SetupChooseLockGeneric.SetupChooseLockGenericFragment; import com.android.settings.testutils.shadow.ShadowLockPatternUtils; import com.android.settings.testutils.shadow.ShadowPasswordUtils; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUtils; +import com.google.android.setupdesign.GlifPreferenceLayout; + import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,6 +46,8 @@ import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowActivity; +import java.util.List; + @RunWith(RobolectricTestRunner.class) @Config(shadows = { ShadowUserManager.class, @@ -78,4 +85,43 @@ public class SetupChooseLockGenericTest { ShadowActivity shadowActivity = Shadows.shadowOf(activity); assertThat(shadowActivity.isFinishing()).isFalse(); } + + @Test + public void setupChooseLockGenericUsingDescriptionTextOfGlifLayout() { + SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(false); + GlifPreferenceLayout view = getViewOfSetupChooseLockGenericFragment(fragment); + assertThat(TextUtils.isEmpty(view.getDescriptionText())).isFalse(); + assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText()); + } + + @Test + public void setupChooseLockGenericUsingDescriptionTextOfGlifLayoutForBiometric() { + SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true); + GlifPreferenceLayout view = getViewOfSetupChooseLockGenericFragment(fragment); + assertThat(TextUtils.isEmpty(view.getDescriptionText())).isFalse(); + assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText()); + } + + private SetupChooseLockGenericFragment getFragmentOfSetupChooseLockGeneric(boolean biometric) { + ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY); + Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN"); + intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, biometric); + SetupChooseLockGeneric activity = + Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).setup().get(); + + List fragments = activity.getSupportFragmentManager().getFragments(); + assertThat(fragments).isNotNull(); + assertThat(fragments.size()).isEqualTo(1); + assertThat(fragments.get(0)).isInstanceOf(SetupChooseLockGenericFragment.class); + + return (SetupChooseLockGenericFragment) fragments.get(0); + } + private GlifPreferenceLayout getViewOfSetupChooseLockGenericFragment( + @NonNull SetupChooseLockGenericFragment fragment) { + assertThat(fragment.getView()).isNotNull(); + assertThat(fragment.getView()).isInstanceOf(GlifPreferenceLayout.class); + + return (GlifPreferenceLayout) fragment.getView(); + } } From 07394b0fdc874cc9ac01ee96232e397ec3549a58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Hern=C3=A1ndez?= Date: Tue, 21 Mar 2023 11:56:16 +0100 Subject: [PATCH 2/5] Fix icons of DND timelapse/event schedule types in Dark Mode Instead of a fixed white color, use a theme-dependent one. Also renamed the drawables themselves since they are no longer "_white". Fixes: 214789556 Test: Manual Change-Id: I94d7d0308a339385988d3bb39182b2e2d2f0c3a1 --- res/drawable/ic_event.xml | 2 +- res/drawable/{ic_event_white.xml => ic_event_shape.xml} | 2 +- res/drawable/ic_timelapse.xml | 2 +- res/drawable/{ic_timelapse_white.xml => ic_timelapse_shape.xml} | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename res/drawable/{ic_event_white.xml => ic_event_shape.xml} (95%) rename res/drawable/{ic_timelapse_white.xml => ic_timelapse_shape.xml} (95%) diff --git a/res/drawable/ic_event.xml b/res/drawable/ic_event.xml index a82d7544985..1bc8f2c4579 100644 --- a/res/drawable/ic_event.xml +++ b/res/drawable/ic_event.xml @@ -30,5 +30,5 @@ Copyright (C) 2018 The Android Open Source Project android:height="@dimen/dashboard_tile_foreground_image_size" android:start="@dimen/dashboard_tile_foreground_image_inset" android:top="@dimen/dashboard_tile_foreground_image_inset" - android:drawable="@drawable/ic_event_white" /> + android:drawable="@drawable/ic_event_shape" /> diff --git a/res/drawable/ic_event_white.xml b/res/drawable/ic_event_shape.xml similarity index 95% rename from res/drawable/ic_event_white.xml rename to res/drawable/ic_event_shape.xml index d80429b7ec0..25a8ded136e 100644 --- a/res/drawable/ic_event_white.xml +++ b/res/drawable/ic_event_shape.xml @@ -20,6 +20,6 @@ Copyright (C) 2018 The Android Open Source Project android:viewportHeight="24.0"> diff --git a/res/drawable/ic_timelapse.xml b/res/drawable/ic_timelapse.xml index ba97bae8c90..8bf148845d8 100644 --- a/res/drawable/ic_timelapse.xml +++ b/res/drawable/ic_timelapse.xml @@ -30,5 +30,5 @@ Copyright (C) 2018 The Android Open Source Project android:height="@dimen/dashboard_tile_foreground_image_size" android:start="@dimen/dashboard_tile_foreground_image_inset" android:top="@dimen/dashboard_tile_foreground_image_inset" - android:drawable="@drawable/ic_timelapse_white" /> + android:drawable="@drawable/ic_timelapse_shape" /> diff --git a/res/drawable/ic_timelapse_white.xml b/res/drawable/ic_timelapse_shape.xml similarity index 95% rename from res/drawable/ic_timelapse_white.xml rename to res/drawable/ic_timelapse_shape.xml index f287747d2bc..6475e0bdc25 100644 --- a/res/drawable/ic_timelapse_white.xml +++ b/res/drawable/ic_timelapse_shape.xml @@ -20,6 +20,6 @@ Copyright (C) 2018 The Android Open Source Project android:viewportHeight="24.0"> From 38df174bbab7ba46116cc4fae88991d264e23850 Mon Sep 17 00:00:00 2001 From: Josh Hou Date: Tue, 21 Mar 2023 10:49:35 +0000 Subject: [PATCH 3/5] [Panlingual] Can't set per-app languages for apps on work profile page Use startActivityAsUser instead of startActivity API to start the AppLocalePickerActivity of different users Bug: 274378136 Test: 1. Perform AppLocalePickerActivityTest robolectric test 2. Perform the manual test by switching different users 3. Perform the manual test by switching different profiles Change-Id: I4405b3b7e832b71b9ef66fa71d9e42ce12da167c --- .../AppLocalePreferenceController.java | 2 -- .../ManageApplications.java | 4 +-- .../localepicker/AppLocalePickerActivity.java | 24 +++++------------ .../spa/system/AppLanguagesListModel.kt | 5 ++-- .../AppLocalePickerActivityTest.java | 26 ------------------- 5 files changed, 11 insertions(+), 50 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java index d58607fa66f..f1a6d363b20 100644 --- a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java @@ -28,7 +28,6 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.applications.AppInfoBase; import com.android.settings.applications.AppLocaleUtil; import com.android.settings.localepicker.AppLocalePickerActivity; @@ -72,7 +71,6 @@ public class AppLocalePreferenceController extends AppInfoPreferenceControllerBa if (mParent != null) { Intent intent = new Intent(mContext, AppLocalePickerActivity.class); intent.setData(Uri.parse("package:" + mParent.getAppEntry().info.packageName)); - intent.putExtra(AppInfoBase.ARG_PACKAGE_UID, mParent.getAppEntry().info.uid); mContext.startActivity(intent); return true; } else { diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index cb1009a941d..0fbbf18f0a5 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -709,8 +709,8 @@ public class ManageApplications extends InstrumentedFragment case LIST_TYPE_APPS_LOCALE: Intent intent = new Intent(getContext(), AppLocalePickerActivity.class); intent.setData(Uri.parse("package:" + mCurrentPkgName)); - intent.putExtra(AppInfoBase.ARG_PACKAGE_UID, mCurrentUid); - startActivity(intent); + getContext().startActivityAsUser(intent, + UserHandle.getUserHandleForUid(mCurrentUid)); break; case LIST_TYPE_BATTERY_OPTIMIZATION: AdvancedPowerUsageDetail.startBatteryDetailPage( diff --git a/src/com/android/settings/localepicker/AppLocalePickerActivity.java b/src/com/android/settings/localepicker/AppLocalePickerActivity.java index 6dab5cf8bdc..9efaf63c687 100644 --- a/src/com/android/settings/localepicker/AppLocalePickerActivity.java +++ b/src/com/android/settings/localepicker/AppLocalePickerActivity.java @@ -18,12 +18,10 @@ package com.android.settings.localepicker; import android.app.FragmentTransaction; import android.app.LocaleManager; -import android.content.Context; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.os.LocaleList; -import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.view.MenuItem; @@ -34,7 +32,6 @@ import android.widget.ListView; import com.android.internal.app.LocalePickerWithRegion; import com.android.internal.app.LocaleStore; import com.android.settings.R; -import com.android.settings.applications.AppInfoBase; import com.android.settings.applications.AppLocaleUtil; import com.android.settings.applications.appinfo.AppLocaleDetails; import com.android.settings.core.SettingsBaseActivity; @@ -46,7 +43,6 @@ public class AppLocalePickerActivity extends SettingsBaseActivity private String mPackageName; private LocalePickerWithRegion mLocalePickerWithRegion; private AppLocaleDetails mAppLocaleDetails; - private Context mContextAsUser; private View mAppLocaleDetailContainer; @Override @@ -64,16 +60,8 @@ public class AppLocalePickerActivity extends SettingsBaseActivity finish(); return; } - mContextAsUser = this; - if (getIntent().hasExtra(AppInfoBase.ARG_PACKAGE_UID)) { - int uid = getIntent().getIntExtra(AppInfoBase.ARG_PACKAGE_UID, -1); - if (uid != -1) { - UserHandle userHandle = UserHandle.getUserHandleForUid(uid); - mContextAsUser = createContextAsUser(userHandle, 0); - } - } - if (!canDisplayLocaleUi() || mContextAsUser.getUserId() != UserHandle.myUserId()) { + if (!canDisplayLocaleUi()) { Log.w(TAG, "Not allow to display Locale Settings UI."); finish(); return; @@ -83,13 +71,13 @@ public class AppLocalePickerActivity extends SettingsBaseActivity getActionBar().setDisplayHomeAsUpEnabled(true); mLocalePickerWithRegion = LocalePickerWithRegion.createLanguagePicker( - mContextAsUser, + this, this, false /* translate only */, null, mPackageName, this); - mAppLocaleDetails = AppLocaleDetails.newInstance(mPackageName, mContextAsUser.getUserId()); + mAppLocaleDetails = AppLocaleDetails.newInstance(mPackageName, getUserId()); mAppLocaleDetailContainer = launchAppLocaleDetailsPage(); // Launch Locale picker part. launchLocalePickerPage(); @@ -129,7 +117,7 @@ public class AppLocalePickerActivity extends SettingsBaseActivity /** Sets the app's locale to the supplied language tag */ private void setAppDefaultLocale(String languageTag) { Log.d(TAG, "setAppDefaultLocale: " + languageTag); - LocaleManager localeManager = mContextAsUser.getSystemService(LocaleManager.class); + LocaleManager localeManager = getSystemService(LocaleManager.class); if (localeManager == null) { Log.w(TAG, "LocaleManager is null, cannot set default app locale"); return; @@ -172,8 +160,8 @@ public class AppLocalePickerActivity extends SettingsBaseActivity private boolean canDisplayLocaleUi() { try { - PackageManager packageManager = mContextAsUser.getPackageManager(); - return AppLocaleUtil.canDisplayLocaleUi(mContextAsUser, + PackageManager packageManager = getPackageManager(); + return AppLocaleUtil.canDisplayLocaleUi(this, packageManager.getApplicationInfo(mPackageName, 0), packageManager.queryIntentActivities(AppLocaleUtil.LAUNCHER_ENTRY_INTENT, PackageManager.GET_META_DATA)); diff --git a/src/com/android/settings/spa/system/AppLanguagesListModel.kt b/src/com/android/settings/spa/system/AppLanguagesListModel.kt index 4aa4c7a5700..3141d68c94f 100644 --- a/src/com/android/settings/spa/system/AppLanguagesListModel.kt +++ b/src/com/android/settings/spa/system/AppLanguagesListModel.kt @@ -21,6 +21,7 @@ import android.content.Intent import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.net.Uri +import android.os.UserHandle import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.remember @@ -94,9 +95,9 @@ class AppLanguagesListModel(private val context: Context) : AppListModel controller = - initActivityController(true); - controller.create(); - - assertThat(controller.get().isFinishing()).isTrue(); - } - @Test public void launchAppLocalePickerActivity_intentWithoutPackageName_failed() { ActivityController controller = @@ -292,17 +279,4 @@ public class AppLocalePickerActivityTest { sDisAllowPackage = disAllowPackage; } } - - @Implements(UserHandle.class) - public static class ShadowUserHandle { - private static int sUserId = 0; - private static void setUserId(int userId) { - sUserId = userId; - } - - @Implementation - public static int getUserId(int userId) { - return sUserId; - } - } } From c7dd729a43a7b9278b0a45912a74739633bbbb90 Mon Sep 17 00:00:00 2001 From: lbill Date: Sat, 4 Feb 2023 04:02:35 +0000 Subject: [PATCH 4/5] Launch Face Settings when device enrolled face MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In legacy flow FaceEnrollIntroduction check maxFacesEnrolled() then update introduction description and prevent user go to next enroll step, the CUJ was not good to user, instead bring user to Face Settings and let user decide the next action(Delete face or change config) is more make sense. As any applications could broadcast intent(android.settings.FACE_ENROLL) to bring FaceEnrollIntroduction up, we add a check in onCreate() and check if device has been enrolled max face, launch FaceSettingsInternalActivity. In addition, skip to register any posture change callback when maxFacesEnrolled() during activity onStart(). Test: atest SettingsGoogleUnitTests Test: m -j SettingsGoogleRoboTests RunSettingsGoogleRoboTests Test: m RunSettingsRoboTests ROBOTEST_FILTER= \       "FaceEnrollIntroductionTest" Test: m RunSettingsRoboTests ROBOTEST_FILTER= \       "FingerprintEnrollIntroductionTest" Test: Manual enrolled face, unfold device, launch Tips Security page and click "Set up Face Unlock", device launch Face Settings insteand of posture guidance page. Bug: 263830403 Change-Id: Ied8b92259810f954ce6b2daaa9b87fc996ad752a --- .../BiometricEnrollIntroduction.java | 4 +- .../face/FaceEnrollIntroduction.java | 49 ++++++++- .../face/FaceEnrollIntroductionTest.java | 101 +++++++++++++++++- .../shadow/ShadowLockPatternUtils.java | 12 ++- 4 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index 730e0496774..cdd2d8b88d9 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -183,7 +183,9 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase mUserManager = UserManager.get(this); updatePasswordQuality(); - if (!mConfirmingCredentials) { + // Check isFinishing() because FaceEnrollIntroduction may finish self to launch + // FaceSettings during onCreate() + if (!mConfirmingCredentials && !isFinishing()) { if (!mHasPassword) { // No password registered, launch into enrollment wizard. mConfirmingCredentials = true; diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index a1233086926..66ed56afc96 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -28,6 +28,7 @@ import android.hardware.SensorPrivacyManager; import android.hardware.biometrics.BiometricAuthenticator; import android.hardware.face.FaceManager; import android.os.Bundle; +import android.os.UserHandle; import android.text.Html; import android.text.method.LinkMovementMethod; import android.util.Log; @@ -42,6 +43,7 @@ import androidx.annotation.StringRes; import androidx.annotation.VisibleForTesting; import com.android.settings.R; +import com.android.settings.Settings; import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollActivity; import com.android.settings.biometrics.BiometricEnrollIntroduction; @@ -110,8 +112,26 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { @Override protected void onCreate(Bundle savedInstanceState) { + mFaceManager = getFaceManager(); + + if (savedInstanceState == null + && !WizardManagerHelper.isAnySetupWizard(getIntent()) + && !getIntent().getBooleanExtra(EXTRA_FROM_SETTINGS_SUMMARY, false) + && maxFacesEnrolled()) { + // from tips && maxEnrolled + Log.d(TAG, "launch face settings"); + launchFaceSettingsActivity(); + finish(); + } + super.onCreate(savedInstanceState); + // Wait super::onCreated() then return because SuperNotCalledExceptio will be thrown + // if we don't wait for it. + if (isFinishing()) { + return; + } + // Apply extracted theme color to icons. final ImageView iconGlasses = findViewById(R.id.icon_glasses); final ImageView iconLooking = findViewById(R.id.icon_looking); @@ -152,8 +172,6 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { infoMessageRequireEyes.setText(getInfoMessageRequireEyes()); } - mFaceManager = getFaceManager(); - // This path is an entry point for SetNewPasswordController, e.g. // adb shell am start -a android.app.action.SET_NEW_PASSWORD if (mToken == null && BiometricUtils.containsGatekeeperPasswordHandle(getIntent())) { @@ -191,6 +209,24 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { Log.v(TAG, "cameraPrivacyEnabled : " + cameraPrivacyEnabled); } + private void launchFaceSettingsActivity() { + final Intent intent = new Intent(this, Settings.FaceSettingsInternalActivity.class); + final byte[] token = getIntent().getByteArrayExtra( + ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + if (token != null) { + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token); + } + final int userId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId()); + if (userId != UserHandle.USER_NULL) { + intent.putExtra(Intent.EXTRA_USER_ID, userId); + } + BiometricUtils.copyMultiBiometricExtras(getIntent(), intent); + intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, true); + intent.putExtra(EXTRA_KEY_CHALLENGE, getIntent().getLongExtra(EXTRA_KEY_CHALLENGE, -1L)); + intent.putExtra(EXTRA_KEY_SENSOR_ID, getIntent().getIntExtra(EXTRA_KEY_SENSOR_ID, -1)); + startActivity(intent); + } + @VisibleForTesting @Nullable protected FaceManager getFaceManager() { @@ -232,6 +268,15 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { @Override protected void onStart() { super.onStart(); + listenFoldEventForPostureGuidance(); + } + + private void listenFoldEventForPostureGuidance() { + if (maxFacesEnrolled()) { + Log.d(TAG, "Device has enrolled face, do not show posture guidance"); + return; + } + if (getPostureGuidanceIntent() == null) { Log.d(TAG, "Device do not support posture guidance"); return; diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java index 6c04add9261..9d588557199 100644 --- a/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceEnrollIntroductionTest.java @@ -51,6 +51,8 @@ import androidx.test.core.app.ApplicationProvider; import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; +import com.android.settings.Settings; +import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricUtils; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.testutils.FakeFeatureFactory; @@ -62,6 +64,7 @@ import com.android.settings.testutils.shadow.ShadowUtils; import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.GlifLayout; import com.google.android.setupdesign.view.BottomScrollView; @@ -168,6 +171,7 @@ public class FaceEnrollIntroductionTest { @After public void tearDown() { ShadowUtils.reset(); + ShadowLockPatternUtils.reset(); } private void setupActivity() { @@ -315,7 +319,7 @@ public class FaceEnrollIntroductionTest { } @Test - public void testFaceEnrollEducation_hasBottomScrollView() { + public void testFaceEnrollIntroduction_hasBottomScrollView() { setupActivity(); BottomScrollView scrollView = getGlifLayout(mActivity).findViewById(R.id.sud_scroll_view); @@ -387,7 +391,7 @@ public class FaceEnrollIntroductionTest { } @Test - public void testFaceEnrollEducation_onFoldedUpdated_folded() { + public void testFaceEnrollIntroduction_onFoldedUpdated_folded() { final Configuration newConfig = new Configuration(); newConfig.smallestScreenWidthDp = DENSITY_DEFAULT; setupActivityForPosture(); @@ -400,4 +404,97 @@ public class FaceEnrollIntroductionTest { assertThat(mSpyActivity.getDevicePostureState()).isEqualTo(DEVICE_POSTURE_CLOSED); } + + @Test + public void testFaceEnrollIntroduction_maxFacesEnrolled_launchFaceSettings() { + setFaceManagerToHave(1 /* numEnrollments */); + final Intent intent = new Intent(); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]); + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + mActivity.mOverrideFaceManager = mFaceManager; + + mController.create(); + + ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); + final Intent nextStartedActivity = shadowActivity.getNextStartedActivity(); + assertThat(nextStartedActivity).isNotNull(); + assertThat(nextStartedActivity.getComponent().getClassName()) + .isEqualTo(Settings.FaceSettingsInternalActivity.class.getName()); + } + + @Test + public void testFaceEnrollIntroduction_maxFacesEnrolled_isSuw_notLaunchFaceSettings() { + setFaceManagerToHave(1 /* numEnrollments */); + ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC); + final Intent intent = new Intent(); + intent.putExtra(WizardManagerHelper.EXTRA_IS_SETUP_FLOW, true); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]); + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + mActivity.mOverrideFaceManager = mFaceManager; + + mController.create(); + + ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); + final Intent nextStartedActivity = shadowActivity.getNextStartedActivity(); + assertThat(nextStartedActivity).isNull(); + } + + @Test + public void testFaceEnrollIntroduction_maxFacesEnrolled_fromSettings_notLaunchFaceSettings() { + setFaceManagerToHave(1 /* numEnrollments */); + ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC); + final Intent intent = new Intent(); + intent.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, true); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]); + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + mActivity.mOverrideFaceManager = mFaceManager; + + mController.create(); + + ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); + final Intent nextStartedActivity = shadowActivity.getNextStartedActivity(); + assertThat(nextStartedActivity).isNull(); + } + + @Test + public void testFaceEnrollIntroduction_hasPostureCallback() { + when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())) + .thenReturn(new Intent()); + setFaceManagerToHave(0 /* numEnrollments */); + ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC); + final Intent intent = new Intent(); + intent.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, true); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]); + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + mActivity.mOverrideFaceManager = mFaceManager; + + mController.create(); + mController.start(); + + assertThat(mActivity.getPostureCallback()).isNotNull(); + } + + @Test + public void testFaceEnrollIntroduction_maxFacesEnrolled_noPostureCallback() { + when(mFakeFeatureFactory.mFaceFeatureProvider.getPostureGuidanceIntent(any())) + .thenReturn(new Intent()); + setFaceManagerToHave(1 /* numEnrollments */); + ShadowLockPatternUtils.setActivePasswordQuality(PASSWORD_QUALITY_NUMERIC); + final Intent intent = new Intent(); + intent.putExtra(BiometricEnrollBase.EXTRA_FROM_SETTINGS_SUMMARY, true); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]); + mController = Robolectric.buildActivity(TestFaceEnrollIntroduction.class, intent); + mActivity = (TestFaceEnrollIntroduction) mController.get(); + mActivity.mOverrideFaceManager = mFaceManager; + + mController.create(); + mController.start(); + + assertThat(mActivity.getPostureCallback()).isNull(); + } + } diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java index 74e39715062..9a83b5919ee 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowLockPatternUtils.java @@ -36,6 +36,7 @@ import java.util.Map; public class ShadowLockPatternUtils { private static boolean sDeviceEncryptionEnabled; + private static Map sUserToActivePasswordQualityMap = new HashMap<>(); private static Map sUserToComplexityMap = new HashMap<>(); private static Map sUserToProfileComplexityMap = new HashMap<>(); private static Map sUserToMetricsMap = new HashMap<>(); @@ -44,6 +45,7 @@ public class ShadowLockPatternUtils { @Resetter public static void reset() { + sUserToActivePasswordQualityMap.clear(); sUserToComplexityMap.clear(); sUserToProfileComplexityMap.clear(); sUserToMetricsMap.clear(); @@ -72,7 +74,11 @@ public class ShadowLockPatternUtils { @Implementation protected int getActivePasswordQuality(int userId) { - return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + final Integer activePasswordQuality = sUserToActivePasswordQualityMap.get(userId); + if (activePasswordQuality == null) { + return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + } + return activePasswordQuality; } @Implementation @@ -153,6 +159,10 @@ public class ShadowLockPatternUtils { sUserToProfileMetricsMap.put(UserHandle.myUserId(), metrics); } + public static void setActivePasswordQuality(int quality) { + sUserToActivePasswordQualityMap.put(UserHandle.myUserId(), quality); + } + @Implementation public boolean isLockScreenDisabled(int userId) { return false; From e621a54f0a1494c661cc1b21d3a02811a27fea5e Mon Sep 17 00:00:00 2001 From: jasonwshsu Date: Thu, 23 Mar 2023 01:25:19 +0800 Subject: [PATCH 5/5] Correct the char limit for strings * string: bluetooth_system_sounds_title is too long to fit in one line. Should allow more char limit to two lines. Bug: 270086620 Test: flash rom and check UI Change-Id: I8b0c8ca37fc3b7447da3dba3bca66673b4d05f7a --- 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 a870f5d850d..7fce000328b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -151,7 +151,7 @@ Audio during calls Media - + Notifications and other system sounds By default, audio output is determined by individual apps