diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 6fe6832b76a..5904282dd97 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4868,22 +4868,6 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index b12f390de71..8fc5ed5d651 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -991,6 +991,8 @@ Skip fingerprint setup? You\u2019ve chosen to use your fingerprint as one way to unlock your phone. If you skip now, you\u2019ll need to set this up later. Setup takes only a minute or so. + + Skip setup for %s? Skip PIN setup? @@ -1088,7 +1090,7 @@ Set screen lock - Device has no screen lock + Set a screen lock For added security, set a PIN, pattern, or password for this device. @@ -2275,6 +2277,8 @@ Work profile accounts - %s Personal profile accounts + + Clone profile accounts Work account - %s @@ -12086,7 +12090,4 @@ "This app can only be opened in 1 window" - - - Note shortcut diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java index 8c717f03e77..cdaba207592 100644 --- a/src/com/android/settings/accounts/AccountPreferenceController.java +++ b/src/com/android/settings/accounts/AccountPreferenceController.java @@ -16,8 +16,10 @@ package com.android.settings.accounts; +import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_CLONE; import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_PERSONAL; import static android.app.admin.DevicePolicyResources.Strings.Settings.ACCESSIBILITY_CATEGORY_WORK; +import static android.app.admin.DevicePolicyResources.Strings.Settings.CLONE_CATEGORY_HEADER; import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_BY; import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGED_PROFILE_SETTINGS_TITLE; import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_CATEGORY_HEADER; @@ -349,28 +351,34 @@ public class AccountPreferenceController extends AbstractPreferenceController preferenceGroup.setContentDescription(title); } else if (userInfo.isManagedProfile()) { if (mType == ProfileSelectFragment.ProfileType.ALL) { - preferenceGroup.setTitle( - mDpm.getResources().getString(WORK_CATEGORY_HEADER, - () -> mContext.getString(R.string.category_work))); + setCategoryTitleFromDevicePolicyResource(preferenceGroup, WORK_CATEGORY_HEADER, + R.string.category_work); final String workGroupSummary = getWorkGroupSummary(context, userInfo); preferenceGroup.setSummary(workGroupSummary); - preferenceGroup.setContentDescription( - mDpm.getResources().getString(ACCESSIBILITY_CATEGORY_WORK, () -> - mContext.getString( - R.string.accessibility_category_work, workGroupSummary))); + setContentDescriptionFromDevicePolicyResource(preferenceGroup, + ACCESSIBILITY_CATEGORY_WORK, R.string.accessibility_category_work, + workGroupSummary); } profileData.removeWorkProfilePreference = newRemoveWorkProfilePreference(); mHelper.enforceRestrictionOnPreference(profileData.removeWorkProfilePreference, DISALLOW_REMOVE_MANAGED_PROFILE, UserHandle.myUserId()); profileData.managedProfilePreference = newManagedProfileSettings(); - } else { + } else if (userInfo.isCloneProfile()) { if (mType == ProfileSelectFragment.ProfileType.ALL) { - preferenceGroup.setTitle( - mDpm.getResources().getString(PERSONAL_CATEGORY_HEADER, - () -> mContext.getString(R.string.category_personal))); - preferenceGroup.setContentDescription( - mDpm.getResources().getString(ACCESSIBILITY_CATEGORY_PERSONAL, () -> - mContext.getString(R.string.accessibility_category_personal))); + setCategoryTitleFromDevicePolicyResource(preferenceGroup, CLONE_CATEGORY_HEADER, + R.string.category_clone); + setContentDescriptionFromDevicePolicyResource(preferenceGroup, + ACCESSIBILITY_CATEGORY_CLONE, R.string.accessibility_category_clone, + null); + } + } else { + // Primary Profile + if (mType == ProfileSelectFragment.ProfileType.ALL) { + setCategoryTitleFromDevicePolicyResource(preferenceGroup, PERSONAL_CATEGORY_HEADER, + R.string.category_personal); + setContentDescriptionFromDevicePolicyResource(preferenceGroup, + ACCESSIBILITY_CATEGORY_PERSONAL, R.string.accessibility_category_personal, + null); } } final PreferenceScreen screen = mFragment.getPreferenceScreen(); @@ -381,13 +389,33 @@ public class AccountPreferenceController extends AbstractPreferenceController if (userInfo.isEnabled()) { profileData.authenticatorHelper = new AuthenticatorHelper(context, userInfo.getUserHandle(), this); - profileData.addAccountPreference = newAddAccountPreference(); - mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference, - DISALLOW_MODIFY_ACCOUNTS, userInfo.id); + if (!userInfo.isCloneProfile()) { + profileData.addAccountPreference = newAddAccountPreference(); + mHelper.enforceRestrictionOnPreference(profileData.addAccountPreference, + DISALLOW_MODIFY_ACCOUNTS, userInfo.id); + } } mProfiles.put(userInfo.id, profileData); } + private void setCategoryTitleFromDevicePolicyResource( + AccessiblePreferenceCategory preferenceGroup, String stringId, int resourceIdentifier) { + preferenceGroup.setTitle( + mDpm.getResources().getString(stringId, + () -> mContext.getString(resourceIdentifier))); + } + + private void setContentDescriptionFromDevicePolicyResource( + AccessiblePreferenceCategory preferenceGroup, String stringId, int resourceIdentifier, + String formatArgs) { + preferenceGroup.setContentDescription(mDpm.getResources().getString(stringId, () -> { + if (formatArgs != null) { + return mContext.getString(resourceIdentifier, formatArgs); + } + return mContext.getString(resourceIdentifier); + })); + } + private RestrictedPreference newAddAccountPreference() { RestrictedPreference preference = new RestrictedPreference(mFragment.getPreferenceManager().getContext()); diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java index a8996c35ae0..ed5804f8916 100644 --- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java @@ -620,6 +620,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl completeEnableProviderDialogBox( whichButton, packageName, setActivityResult); } + + @Override + public void onCancel() {} }; return new NewProviderConfirmationDialogFragment(host, packageName, appName); @@ -666,6 +669,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl new DialogHost() { @Override public void onDialogClick(int whichButton) {} + + @Override + public void onCancel() {} }; return new ErrorDialogFragment(host); @@ -689,6 +695,12 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl pref.setChecked(true); } } + + @Override + public void onCancel() { + // If we dismiss the dialog then re-enable. + pref.setChecked(true); + } }; return new ConfirmationDialogFragment(host, packageName, appName); @@ -705,6 +717,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl /** Called when the dialog button is clicked. */ private static interface DialogHost { void onDialogClick(int whichButton); + + void onCancel(); } /** Called to send messages back to the parent fragment. */ @@ -754,6 +768,11 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl public DialogHost getDialogHost() { return mDialogHost; } + + @Override + public void onCancel(@NonNull DialogInterface dialog) { + getDialogHost().onCancel(); + } } /** Dialog showing error when too many providers are selected. */ diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java index 34881ab6703..742faf1758e 100644 --- a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java +++ b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java @@ -156,7 +156,7 @@ public class DefaultCombinedPreferenceController extends DefaultAppPreferenceCon final ServiceInfo serviceInfo = resolveInfo.serviceInfo; // If there are multiple autofill services then pick the first one. - if (mKey.startsWith(serviceInfo.packageName)) { + if (mKey != null && mKey.startsWith(serviceInfo.packageName)) { final String settingsActivity; try { settingsActivity = diff --git a/src/com/android/settings/biometrics/BiometricUtils.java b/src/com/android/settings/biometrics/BiometricUtils.java index 772aec33bfd..3356dfa9322 100644 --- a/src/com/android/settings/biometrics/BiometricUtils.java +++ b/src/com/android/settings/biometrics/BiometricUtils.java @@ -28,6 +28,8 @@ import android.hardware.face.FaceManager; import android.hardware.face.FaceSensorPropertiesInternal; import android.os.Bundle; import android.os.storage.StorageManager; +import android.text.BidiFormatter; +import android.text.SpannableStringBuilder; import android.util.FeatureFlagUtils; import android.util.Log; import android.view.Surface; @@ -38,6 +40,7 @@ import androidx.fragment.app.FragmentActivity; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; +import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.biometrics.face.FaceEnrollIntroduction; import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor; @@ -45,6 +48,7 @@ import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollFindSensor; import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction; import com.android.settings.biometrics2.ui.view.FingerprintEnrollmentActivity; +import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.SetupChooseLockGeneric; @@ -60,6 +64,9 @@ import java.lang.annotation.RetentionPolicy; public class BiometricUtils { private static final String TAG = "BiometricUtils"; + /** The character ' • ' to separate the setup choose options */ + public static final String SEPARATOR = " \u2022 "; + // Note: Theis IntDef must align SystemUI DevicePostureInt @IntDef(prefix = {"DEVICE_POSTURE_"}, value = { DEVICE_POSTURE_UNKNOWN, @@ -496,4 +503,45 @@ public class BiometricUtils { public static boolean isLandscape(@NonNull Context context) { return context.getDisplay().getRotation() == Surface.ROTATION_90; } + + /** + * Returns true if the device supports Face enrollment in SUW flow + */ + public static boolean isFaceSupportedInSuw(Context context) { + return FeatureFactory.getFactory(context).getFaceFeatureProvider().isSetupWizardSupported( + context); + } + + /** + * Returns the combined screen lock options by device biometrics config + * @param context the application context + * @param screenLock the type of screen lock(PIN, Pattern, Password) in string + * @param hasFingerprint device support fingerprint or not + * @param isFaceSupported device support face or not + * @return the options combined with screen lock, face, and fingerprint in String format. + */ + public static String getCombinedScreenLockOptions(Context context, + CharSequence screenLock, boolean hasFingerprint, boolean isFaceSupported) { + final SpannableStringBuilder ssb = new SpannableStringBuilder(); + final BidiFormatter bidi = BidiFormatter.getInstance(); + // Assume the flow is "Screen Lock" + "Face" + "Fingerprint" + ssb.append(bidi.unicodeWrap(screenLock)); + + if (isFaceSupported) { + ssb.append(bidi.unicodeWrap(SEPARATOR)); + ssb.append(bidi.unicodeWrap( + capitalize(context.getString(R.string.keywords_face_settings)))); + } + + if (hasFingerprint) { + ssb.append(bidi.unicodeWrap(SEPARATOR)); + ssb.append(bidi.unicodeWrap( + capitalize(context.getString(R.string.security_settings_fingerprint)))); + } + return ssb.toString(); + } + + private static String capitalize(final String input) { + return Character.toUpperCase(input.charAt(0)) + input.substring(1); + } } diff --git a/src/com/android/settings/datausage/DataUsageList.java b/src/com/android/settings/datausage/DataUsageList.java index 1855c2e44e9..dd8312cccdc 100644 --- a/src/com/android/settings/datausage/DataUsageList.java +++ b/src/com/android/settings/datausage/DataUsageList.java @@ -165,11 +165,7 @@ public class DataUsageList extends DataUsageBaseFragment } processArgument(); - mMobileNetworkRepository = MobileNetworkRepository.getInstance(getContext()); - ThreadUtils.postOnBackgroundThread(() -> { - mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById( - String.valueOf(mSubId)); - }); + updateSubscriptionInfoEntity(); mDataStateListener = new MobileDataEnabledListener(activity, this); } @@ -294,6 +290,15 @@ public class DataUsageList extends DataUsageBaseFragment } } + @VisibleForTesting + void updateSubscriptionInfoEntity() { + mMobileNetworkRepository = MobileNetworkRepository.getInstance(getContext()); + ThreadUtils.postOnBackgroundThread(() -> { + mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById( + String.valueOf(mSubId)); + }); + } + /** * Implementation of {@code MobileDataEnabledListener.Client} */ @@ -503,11 +508,13 @@ public class DataUsageList extends DataUsageBaseFragment Collections.sort(items); final List packageNames = Arrays.asList(getContext().getResources().getStringArray( R.array.datausage_hiding_carrier_service_package_names)); + // When there is no specified SubscriptionInfo, Wi-Fi data usage will be displayed. + // In this case, the carrier service package also needs to be hidden. boolean shouldHidePackageName = mSubscriptionInfoEntity != null ? Arrays.stream(getContext().getResources().getIntArray( R.array.datausage_hiding_carrier_service_carrier_id)) .anyMatch(carrierId -> (carrierId == mSubscriptionInfoEntity.carrierId)) - : false; + : true; for (int i = 0; i < items.size(); i++) { UidDetail detail = mUidDetailProvider.getUidDetail(items.get(i).key, true); diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 7fe180d0343..777e4281764 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -291,7 +291,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements BatteryHistoricalLogUtil.writeLog( getContext().getApplicationContext(), - Action.MANUAL, + Action.LEAVE, BatteryHistoricalLogUtil.getPackageNameWithUserId( mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()), mLogStringBuilder.toString()); diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java index bf874bb6ed5..0558d46c3b8 100644 --- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java +++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java @@ -24,7 +24,6 @@ import android.app.backup.BackupHelper; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; -import android.os.Build; import android.os.IDeviceIdleController; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -48,7 +47,6 @@ public final class BatteryBackupHelper implements BackupHelper { /** An inditifier for {@link BackupHelper}. */ public static final String TAG = "BatteryBackupHelper"; private static final String DEVICE_IDLE_SERVICE = "deviceidle"; - private static final boolean DEBUG = Build.TYPE.equals("userdebug"); static final String DELIMITER = ","; static final String DELIMITER_MODE = ":"; @@ -119,7 +117,7 @@ public final class BatteryBackupHelper implements BackupHelper { Log.e(TAG, "backupFullPowerList() failed", e); return null; } - // Ignores unexpected emptty result case. + // Ignores unexpected empty result case. if (allowlistedApps == null || allowlistedApps.length == 0) { Log.w(TAG, "no data found in the getFullPowerList()"); return new ArrayList<>(); @@ -145,8 +143,7 @@ public final class BatteryBackupHelper implements BackupHelper { final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); // Converts application into the AppUsageState. for (ApplicationInfo info : applications) { - final int mode = appOps.checkOpNoThrow( - AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName); + final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName); @BatteryOptimizeUtils.OptimizationMode final int optimizationMode = BatteryOptimizeUtils.getAppOptimizationMode( mode, allowlistedApps.contains(info.packageName)); @@ -159,7 +156,7 @@ public final class BatteryBackupHelper implements BackupHelper { final String packageOptimizeMode = info.packageName + DELIMITER_MODE + optimizationMode; builder.append(packageOptimizeMode + DELIMITER); - debugLog(packageOptimizeMode); + Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode); backupCount++; } @@ -255,9 +252,8 @@ public final class BatteryBackupHelper implements BackupHelper { } private boolean isSystemOrDefaultApp(String packageName, int uid) { - final PowerAllowlistBackend powerAllowlistBackend = getPowerAllowlistBackend(); - return powerAllowlistBackend.isSysAllowlisted(packageName) - || powerAllowlistBackend.isDefaultActiveApp(packageName, uid); + return BatteryOptimizeUtils.isSystemOrDefaultApp( + getPowerAllowlistBackend(), packageName, uid); } private ArraySet getInstalledApplications() { @@ -267,10 +263,6 @@ public final class BatteryBackupHelper implements BackupHelper { return BatteryOptimizeUtils.getInstalledApplications(mContext, getIPackageManager()); } - private void debugLog(String debugContent) { - if (DEBUG) Log.d(TAG, debugContent); - } - private static void writeBackupData( BackupDataOutput data, String dataKey, String dataContent) { final byte[] dataContentBytes = dataContent.getBytes(); @@ -283,6 +275,6 @@ public final class BatteryBackupHelper implements BackupHelper { } private static boolean isOwner() { - return UserHandle.myUserId() == UserHandle.USER_OWNER; + return UserHandle.myUserId() == UserHandle.USER_SYSTEM; } } diff --git a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java b/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java index 68a8bfbfbe6..a827e6df74a 100644 --- a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java +++ b/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java @@ -21,6 +21,7 @@ import android.content.SharedPreferences; import android.util.Base64; import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action; +import com.android.settings.fuelgauge.batteryusage.ConvertUtils; import com.google.common.annotations.VisibleForTesting; @@ -49,6 +50,7 @@ public final class BatteryHistoricalLogUtil { .setPackageName(pkg) .setAction(action) .setActionDescription(actionDescription) + .setTimestamp(System.currentTimeMillis()) .build()); } @@ -89,6 +91,7 @@ public final class BatteryHistoricalLogUtil { if (logEntryList.isEmpty()) { writer.println("\tNo past logs."); } else { + writer.println("0:RESTRICTED 1:UNRESTRICTED 2:OPTIMIZED 3:UNKNOWN"); logEntryList.forEach(entry -> writer.println(toString(entry))); } } @@ -101,8 +104,9 @@ public final class BatteryHistoricalLogUtil { } private static String toString(BatteryOptimizeHistoricalLogEntry entry) { - return String.format("%s\tAction:%s\tEvent:%s", - entry.getPackageName(), entry.getAction(), entry.getActionDescription()); + return String.format("%s\tAction:%s\tEvent:%s\tTimestamp:%s", entry.getPackageName(), + entry.getAction(), entry.getActionDescription(), + ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp())); } @VisibleForTesting diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java index 6354f3b6f65..b9ac64dd781 100644 --- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java +++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java @@ -83,8 +83,7 @@ public class BatteryOptimizeUtils { mAppOpsManager = context.getSystemService(AppOpsManager.class); mBatteryUtils = BatteryUtils.getInstance(context); mPowerAllowListBackend = PowerAllowlistBackend.getInstance(context); - mMode = mAppOpsManager - .checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName); + mMode = getMode(mAppOpsManager, mUid, mPackageName); mAllowListed = mPowerAllowListBackend.isAllowlisted(mPackageName, mUid); } @@ -204,7 +203,12 @@ public class BatteryOptimizeUtils { return mPackageName == null ? UNKNOWN_PACKAGE : mPackageName; } - private static boolean isSystemOrDefaultApp( + static int getMode(AppOpsManager appOpsManager, int uid, String packageName) { + return appOpsManager.checkOpNoThrow( + AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName); + } + + static boolean isSystemOrDefaultApp( PowerAllowlistBackend powerAllowlistBackend, String packageName, int uid) { return powerAllowlistBackend.isSysAllowlisted(packageName) || powerAllowlistBackend.isDefaultActiveApp(packageName, uid); diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java index 8e9d4852b1b..34c431a846c 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java @@ -67,9 +67,6 @@ public class BatteryTipLoader extends AsyncLoaderCompat> { tips.add(new LowBatteryDetector(context, policy, batteryInfo, isPowerSaveMode).detect()); tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect()); - tips.add(new SmartBatteryDetector( - context, policy, batteryInfo, context.getContentResolver(), isPowerSaveMode) - .detect()); tips.add(new BatteryDefenderDetector(batteryInfo, context).detect()); tips.add(new DockDefenderDetector(batteryInfo, context).detect()); tips.add(new IncompatibleChargerDetector(context).detect()); diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java index 054ce610944..08b8fd09f25 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java @@ -169,9 +169,11 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment private void mapLanguageWithLayout(InputMethodInfo info, InputMethodSubtype subtype) { CharSequence subtypeLabel = getSubtypeLabel(mContext, info, subtype); - KeyboardLayout[] keyboardLayouts = getKeyboardLayouts(info, subtype); - String layout = getKeyboardLayout(info, subtype); - + KeyboardLayout[] keyboardLayouts = + NewKeyboardSettingsUtils.getKeyboardLayouts( + mIm, mUserId, mInputDeviceIdentifier, info, subtype); + String layout = NewKeyboardSettingsUtils.getKeyboardLayout( + mIm, mUserId, mInputDeviceIdentifier, info, subtype); if (layout != null) { for (int i = 0; i < keyboardLayouts.length; i++) { if (keyboardLayouts[i].getDescriptor().equals(layout)) { @@ -220,7 +222,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment preference -> { showKeyboardLayoutPicker( keyboardInfo.getSubtypeLabel(), - keyboardInfo.getLayout(), mInputDeviceIdentifier, mUserId, keyboardInfo.getInputMethodInfo(), @@ -267,7 +268,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment private void showKeyboardLayoutPicker( CharSequence subtypeLabel, - String layout, InputDeviceIdentifier inputDeviceIdentifier, int userId, InputMethodInfo inputMethodInfo, @@ -281,7 +281,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE, inputMethodSubtype); arguments.putInt(NewKeyboardSettingsUtils.EXTRA_USER_ID, userId); arguments.putCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE, subtypeLabel); - arguments.putString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT, layout); new SubSettingLauncher(mContext) .setSourceMetricsCategory(getMetricsCategory()) .setDestination(NewKeyboardLayoutPickerFragment.class.getName()) @@ -289,16 +288,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment .launch(); } - private KeyboardLayout[] getKeyboardLayouts(InputMethodInfo info, InputMethodSubtype subtype) { - return mIm.getKeyboardLayoutListForInputDevice( - mInputDeviceIdentifier, mUserId, info, subtype); - } - - private String getKeyboardLayout(InputMethodInfo info, InputMethodSubtype subtype) { - return mIm.getKeyboardLayoutForInputDevice( - mInputDeviceIdentifier, mUserId, info, subtype); - } - private CharSequence getSubtypeLabel( Context context, InputMethodInfo info, InputMethodSubtype subtype) { return subtype.getDisplayName( diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java index 110147a4a68..1af001bda31 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutPickerContent.java @@ -20,6 +20,7 @@ import android.app.settings.SettingsEnums; import android.content.Context; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; +import android.hardware.input.KeyboardLayout; import android.os.Bundle; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; @@ -31,28 +32,50 @@ public class NewKeyboardLayoutPickerContent extends DashboardFragment { private static final String TAG = "KeyboardLayoutPicker"; + private InputManager mIm; + private int mUserId; + private InputDeviceIdentifier mIdentifier; + private InputMethodInfo mInputMethodInfo; + private InputMethodSubtype mInputMethodSubtype; + @Override public void onAttach(Context context) { super.onAttach(context); - InputManager inputManager = getContext().getSystemService(InputManager.class); + mIm = getContext().getSystemService(InputManager.class); Bundle arguments = getArguments(); final CharSequence title = arguments.getCharSequence(NewKeyboardSettingsUtils.EXTRA_TITLE); - final String layout = arguments.getString(NewKeyboardSettingsUtils.EXTRA_KEYBOARD_LAYOUT); - final int userId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID); - final InputDeviceIdentifier identifier = + mUserId = arguments.getInt(NewKeyboardSettingsUtils.EXTRA_USER_ID); + mIdentifier = arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER); - final InputMethodInfo inputMethodInfo = + mInputMethodInfo = arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_INFO); - final InputMethodSubtype inputMethodSubtype = + mInputMethodSubtype = arguments.getParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_METHOD_SUBTYPE); - if (identifier == null - || NewKeyboardSettingsUtils.getInputDevice(inputManager, identifier) == null) { + if (mIdentifier == null + || NewKeyboardSettingsUtils.getInputDevice(mIm, mIdentifier) == null) { getActivity().finish(); return; } getActivity().setTitle(title); - use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, userId, - identifier, inputMethodInfo, inputMethodSubtype, layout); + use(NewKeyboardLayoutPickerController.class).initialize(this /*parent*/, mUserId, + mIdentifier, mInputMethodInfo, mInputMethodSubtype, getSelectedLayoutLabel()); + } + + private String getSelectedLayoutLabel() { + String label = getContext().getString(R.string.keyboard_default_layout); + String layout = NewKeyboardSettingsUtils.getKeyboardLayout( + mIm, mUserId, mIdentifier, mInputMethodInfo, mInputMethodSubtype); + KeyboardLayout[] keyboardLayouts = NewKeyboardSettingsUtils.getKeyboardLayouts( + mIm, mUserId, mIdentifier, mInputMethodInfo, mInputMethodSubtype); + if (layout != null) { + for (int i = 0; i < keyboardLayouts.length; i++) { + if (keyboardLayouts[i].getDescriptor().equals(layout)) { + label = keyboardLayouts[i].getLabel(); + break; + } + } + } + return label; } @Override diff --git a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java index fe0c9d4f977..697c0f09f62 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java +++ b/src/com/android/settings/inputmethod/NewKeyboardSettingsUtils.java @@ -19,6 +19,7 @@ package com.android.settings.inputmethod; import android.content.Context; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; +import android.hardware.input.KeyboardLayout; import android.view.InputDevice; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; @@ -39,7 +40,6 @@ public class NewKeyboardSettingsUtils { "com.android.settings.inputmethod.EXTRA_INTENT_FROM"; static final String EXTRA_TITLE = "keyboard_layout_picker_title"; - static final String EXTRA_KEYBOARD_LAYOUT = "keyboard_layout"; static final String EXTRA_USER_ID = "user_id"; static final String EXTRA_INPUT_DEVICE_IDENTIFIER = "input_device_identifier"; static final String EXTRA_INPUT_METHOD_INFO = "input_method_info"; @@ -117,4 +117,14 @@ public class NewKeyboardSettingsUtils { static InputDevice getInputDevice(InputManager im, InputDeviceIdentifier identifier) { return im.getInputDeviceByDescriptor(identifier.getDescriptor()); } + + static KeyboardLayout[] getKeyboardLayouts(InputManager inputManager, int userId, + InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) { + return inputManager.getKeyboardLayoutListForInputDevice(identifier, userId, info, subtype); + } + + static String getKeyboardLayout(InputManager inputManager, int userId, + InputDeviceIdentifier identifier, InputMethodInfo info, InputMethodSubtype subtype) { + return inputManager.getKeyboardLayoutForInputDevice(identifier, userId, info, subtype); + } } diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java index 22f5b65306e..936de38ecac 100644 --- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java +++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java @@ -67,12 +67,14 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment private static final String SHOW_VIRTUAL_KEYBOARD_SWITCH = "show_virtual_keyboard_switch"; private static final String KEYBOARD_SHORTCUTS_HELPER = "keyboard_shortcuts_helper"; private static final String MODIFIER_KEYS_SETTINGS = "modifier_keys_settings"; + private static final String EXTRA_AUTO_SELECTION = "auto_selection"; @NonNull private final ArrayList mLastHardKeyboards = new ArrayList<>(); private InputManager mIm; private InputMethodManager mImm; + private InputDeviceIdentifier mAutoInputDeviceIdentifier; @NonNull private PreferenceCategory mKeyboardAssistanceCategory; @NonNull @@ -84,6 +86,12 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment static final String EXTRA_BT_ADDRESS = "extra_bt_address"; private String mBluetoothAddress; + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putParcelable(EXTRA_AUTO_SELECTION, mAutoInputDeviceIdentifier); + super.onSaveInstanceState(outState); + } + @Override public void onCreatePreferences(Bundle bundle, String s) { Activity activity = Preconditions.checkNotNull(getActivity()); @@ -107,15 +115,19 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment KeyboardLayoutPickerFragment.EXTRA_INPUT_DEVICE_IDENTIFIER); // TODO (b/271391879): The EXTRA_INTENT_FROM is used for the future metrics. if (inputDeviceIdentifier != null) { - Bundle arguments = new Bundle(); - arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, - inputDeviceIdentifier); - new SubSettingLauncher(getContext()) - .setSourceMetricsCategory(getMetricsCategory()) - .setDestination(NewKeyboardLayoutEnabledLocalesFragment.class.getName()) - .setArguments(arguments) - .launch(); + mAutoInputDeviceIdentifier = inputDeviceIdentifier; } + // Don't repeat the autoselection. + if (isAutoSelection(bundle, inputDeviceIdentifier)) { + showEnabledLocalesKeyboardLayoutList(inputDeviceIdentifier); + } + } + + private static boolean isAutoSelection(Bundle bundle, InputDeviceIdentifier identifier) { + if (bundle != null && bundle.getParcelable(EXTRA_AUTO_SELECTION) != null) { + return false; + } + return identifier != null; } @Override @@ -220,7 +232,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment pref.setOnPreferenceClickListener( preference -> { showEnabledLocalesKeyboardLayoutList( - hardKeyboardDeviceInfo.mDeviceName, hardKeyboardDeviceInfo.mDeviceIdentifier); return true; }); @@ -246,8 +257,7 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment fragment.show(getActivity().getSupportFragmentManager(), "keyboardLayout"); } - private void showEnabledLocalesKeyboardLayoutList(String keyboardName, - InputDeviceIdentifier inputDeviceIdentifier) { + private void showEnabledLocalesKeyboardLayoutList(InputDeviceIdentifier inputDeviceIdentifier) { Bundle arguments = new Bundle(); arguments.putParcelable(NewKeyboardSettingsUtils.EXTRA_INPUT_DEVICE_IDENTIFIER, inputDeviceIdentifier); diff --git a/src/com/android/settings/network/telephony/ConfirmDialogFragment.java b/src/com/android/settings/network/telephony/ConfirmDialogFragment.java index dceaf1cc878..d262a0e79ab 100644 --- a/src/com/android/settings/network/telephony/ConfirmDialogFragment.java +++ b/src/com/android/settings/network/telephony/ConfirmDialogFragment.java @@ -17,24 +17,27 @@ package com.android.settings.network.telephony; import android.app.Dialog; +import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; -import android.widget.AdapterView; +import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentActivity; import com.android.settings.R; import java.util.ArrayList; +import java.util.List; /** Fragment to show a confirm dialog. The caller should implement onConfirmListener. */ public class ConfirmDialogFragment extends BaseDialogFragment @@ -136,28 +139,10 @@ public class ConfirmDialogFragment extends BaseDialogFragment dialogMessage.setVisibility(View.VISIBLE); } - final ArrayAdapter arrayAdapterItems = new ArrayAdapter( - getContext(), - R.layout.sim_confirm_dialog_item_multiple_enabled_profiles_supported, list); final ListView lvItems = content.findViewById(R.id.carrier_list); if (lvItems != null) { lvItems.setVisibility(View.VISIBLE); - lvItems.setAdapter(arrayAdapterItems); - lvItems.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, - long id) { - Log.i(TAG, "list onClick =" + position); - Log.i(TAG, "list item =" + list.get(position)); - - if (position == list.size() - 1) { - // user select the "cancel" item; - informCaller(false, -1); - } else { - informCaller(true, position); - } - } - }); + lvItems.setAdapter(new ButtonArrayAdapter(getContext(), list)); } final LinearLayout infoOutline = content.findViewById(R.id.info_outline_layout); if (infoOutline != null) { @@ -197,4 +182,32 @@ public class ConfirmDialogFragment extends BaseDialogFragment } listener.onConfirm(getTagInCaller(), confirmed, itemPosition); } + + private class ButtonArrayAdapter extends ArrayAdapter { + private final List mList; + + ButtonArrayAdapter(Context context, List list) { + super(context, R.layout.sim_confirm_dialog_item_multiple_enabled_profiles_supported, + list); + mList = list; + } + + @NonNull + @Override + public View getView(int position, View convertView, @NonNull ViewGroup parent) { + View view = super.getView(position, convertView, parent); + view.setOnClickListener(v -> { + Log.i(TAG, "list onClick =" + position); + Log.i(TAG, "list item =" + mList.get(position)); + + if (position == mList.size() - 1) { + // user select the "cancel" item; + informCaller(false, -1); + } else { + informCaller(true, position); + } + }); + return view; + } + } } diff --git a/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt b/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt deleted file mode 100644 index d3d751063b3..00000000000 --- a/src/com/android/settings/notetask/shortcut/CreateNoteTaskShortcutActivity.kt +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2023 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.notetask.shortcut - -import android.app.Activity -import android.app.role.RoleManager -import android.app.role.RoleManager.ROLE_NOTES -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.pm.ShortcutInfo -import android.content.pm.ShortcutManager -import android.graphics.drawable.Icon -import android.os.Bundle -import android.os.PersistableBundle -import android.os.UserHandle -import androidx.activity.ComponentActivity -import androidx.core.content.getSystemService -import com.android.settings.R - -/** - * Activity responsible for create a shortcut for notes action. If the shortcut is enabled, a new - * shortcut will appear in the widget picker. If the shortcut is selected, the Activity here will be - * launched, creating a new shortcut for [CreateNoteTaskShortcutActivity], and will finish. - * - * IMPORTANT! The shortcut package name and class should be synchronized with SystemUI controller: - * [com.android.systemui.notetask.NoteTaskController#SETTINGS_CREATE_NOTE_TASK_SHORTCUT_COMPONENT]. - * - * Changing the package name or class is a breaking change. - * - * @see Creating - * a custom shortcut activity - */ -internal class CreateNoteTaskShortcutActivity : ComponentActivity() { - - override fun onCreate(savedInstanceState: Bundle?) { - val roleManager = requireNotNull(getSystemService()) - val shortcutManager = requireNotNull(getSystemService()) - - super.onCreate(savedInstanceState) - - val shortcutInfo = roleManager.createNoteShortcutInfoAsUser(context = this, user) - val shortcutIntent = shortcutManager.createShortcutResultIntent(shortcutInfo) - setResult(Activity.RESULT_OK, shortcutIntent) - - finish() - } - - private companion object { - - private const val SHORTCUT_ID = "note_task_shortcut_id" - private const val EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE = - "extra_shortcut_badge_override_package" - private const val ACTION_LAUNCH_NOTE_TASK = "com.android.systemui.action.LAUNCH_NOTE_TASK" - - private fun RoleManager.createNoteShortcutInfoAsUser( - context: Context, - user: UserHandle, - ): ShortcutInfo? { - val systemUiComponent = context.getSystemUiComponent() ?: return null - - val extras = PersistableBundle() - getDefaultRoleHolderAsUser(ROLE_NOTES, user)?.let { packageName -> - // Set custom app badge using the icon from ROLES_NOTES default app. - extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, packageName) - } - - val icon = Icon.createWithResource(context, R.drawable.ic_note_task_shortcut_widget) - - val intent = Intent(ACTION_LAUNCH_NOTE_TASK).apply { - setPackage(systemUiComponent.packageName) - } - - // Creates a System UI context. That will let the ownership with SystemUI and allows it - // to perform updates such as enabling or updating the badge override package. - val systemUiContext = context.createPackageContext( - systemUiComponent.packageName, - /* flags */ 0, - ) - - return ShortcutInfo.Builder(systemUiContext, SHORTCUT_ID) - .setIntent(intent) - .setShortLabel(context.getString(R.string.note_task_shortcut_label)) - .setLongLived(true) - .setIcon(icon) - .setExtras(extras) - .build() - } - - private fun RoleManager.getDefaultRoleHolderAsUser( - role: String, - user: UserHandle, - ): String? = getRoleHoldersAsUser(role, user).firstOrNull() - - private fun Context.getSystemUiComponent(): ComponentName? { - val flattenName = getString( - com.android.internal.R.string.config_systemUIServiceComponent) - check(flattenName.isNotEmpty()) { - "No 'com.android.internal.R.string.config_systemUIServiceComponent' resource" - } - return try { - ComponentName.unflattenFromString(flattenName) - } catch (e: RuntimeException) { - val message = "Invalid component name defined by 'com.android.internal.R.string." + - "config_systemUIServiceComponent' resource: $flattenName" - throw IllegalStateException(message, e) - } - } - } -} diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 0bf13b15c0c..4c4795cbd84 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -48,8 +48,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.service.persistentdata.PersistentDataBlockManager; -import android.text.BidiFormatter; -import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; @@ -77,9 +75,9 @@ import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollActivity; import com.android.settings.biometrics.BiometricEnrollBase; +import com.android.settings.biometrics.BiometricUtils; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; -import com.android.settings.overlay.FeatureFactory; import com.android.settings.safetycenter.LockScreenSafetySource; import com.android.settings.search.SearchFeatureProvider; import com.android.settingslib.RestrictedPreference; @@ -143,9 +141,6 @@ public class ChooseLockGeneric extends SettingsActivity { */ public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras"; - /** The character ' • ' to separate the setup choose options */ - public static final String SEPARATOR = " \u2022 "; - @VisibleForTesting static final int CONFIRM_EXISTING_REQUEST = 100; @VisibleForTesting @@ -662,32 +657,20 @@ public class ChooseLockGeneric extends SettingsActivity { @VisibleForTesting String getBiometricsPreferenceTitle(@NonNull ScreenLockType secureType) { - SpannableStringBuilder ssb = new SpannableStringBuilder(); - BidiFormatter bidi = BidiFormatter.getInstance(); + final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext()); + final boolean hasFace = Utils.hasFaceHardware(getContext()); + final boolean isSuw = WizardManagerHelper.isAnySetupWizard(getIntent()); + final boolean isFaceSupported = + hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw(getContext())); + // Assume the flow is "Screen Lock" + "Face" + "Fingerprint" if (mController != null) { - ssb.append(bidi.unicodeWrap(mController.getTitle(secureType))); + return BiometricUtils.getCombinedScreenLockOptions(getContext(), + mController.getTitle(secureType), hasFingerprint, isFaceSupported); } else { Log.e(TAG, "ChooseLockGenericController is null!"); + return getResources().getString(R.string.error_title); } - - if (mFaceManager != null && mFaceManager.isHardwareDetected() && isFaceSupported()) { - ssb.append(bidi.unicodeWrap(SEPARATOR)); - ssb.append(bidi.unicodeWrap( - getResources().getString(R.string.keywords_face_settings))); - } - if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) { - ssb.append(bidi.unicodeWrap(SEPARATOR)); - ssb.append(bidi.unicodeWrap( - getResources().getString(R.string.security_settings_fingerprint))); - } - return ssb.toString(); - } - - private boolean isFaceSupported() { - return FeatureFactory.getFactory(getContext().getApplicationContext()) - .getFaceFeatureProvider() - .isSetupWizardSupported(getContext().getApplicationContext()); } private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) { diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 9657175c2e5..216f7db1ac1 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -64,6 +64,8 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_FOR_FACE = "for_face"; // For the paths where multiple biometric sensors exist public static final String EXTRA_KEY_FOR_BIOMETRICS = "for_biometrics"; + // For the paths where setup biometrics in suw flow + public static final String EXTRA_KEY_IS_SUW = "is_suw"; public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only"; public static final String EXTRA_KEY_REQUEST_GK_PW_HANDLE = "request_gk_pw_handle"; // Gatekeeper password handle, which can subsequently be used to generate Gatekeeper diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java index 17d83b30b88..bc6c5129968 100644 --- a/src/com/android/settings/password/SetupChooseLockGeneric.java +++ b/src/com/android/settings/password/SetupChooseLockGeneric.java @@ -19,6 +19,7 @@ package com.android.settings.password; import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.app.admin.DevicePolicyManager.EXTRA_PASSWORD_COMPLEXITY; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; import android.app.RemoteServiceException.MissingRequestPasswordComplexityPermissionException; @@ -43,6 +44,7 @@ import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.utils.SettingsDividerItemDecoration; +import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.GlifPreferenceLayout; import com.google.android.setupdesign.util.ThemeHelper; @@ -187,14 +189,14 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { final String key = preference.getKey(); if (KEY_UNLOCK_SET_DO_LATER.equals(key)) { // show warning. + final Intent intent = getActivity().getIntent(); SetupSkipDialog dialog = SetupSkipDialog.newInstance( - getActivity().getIntent() - .getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false), - /* isPatternMode= */ false, - /* isAlphaMode= */ false, + CREDENTIAL_TYPE_NONE, + intent.getBooleanExtra(SetupSkipDialog.EXTRA_FRP_SUPPORTED, false), /* forFingerprint= */ false, /* forFace= */ false, - /* forBiometrics= */ false + /* forBiometrics= */ false, + WizardManagerHelper.isAnySetupWizard(intent) ); dialog.show(getFragmentManager()); return true; diff --git a/src/com/android/settings/password/SetupChooseLockPassword.java b/src/com/android/settings/password/SetupChooseLockPassword.java index 74cb2718b00..0101aa5c29f 100644 --- a/src/com/android/settings/password/SetupChooseLockPassword.java +++ b/src/com/android/settings/password/SetupChooseLockPassword.java @@ -16,6 +16,9 @@ package com.android.settings.password; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -31,6 +34,8 @@ import com.android.settings.R; import com.android.settings.SetupRedactionInterstitial; import com.android.settings.password.ChooseLockTypeDialogFragment.OnLockTypeSelectedListener; +import com.google.android.setupcompat.util.WizardManagerHelper; + /** * Setup Wizard's version of ChooseLockPassword screen. It inherits the logic and basic structure * from ChooseLockPassword class, and should remain similar to that behaviorally. This class should @@ -113,12 +118,12 @@ public class SetupChooseLockPassword extends ChooseLockPassword { final boolean forBiometrics = intent .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false); final SetupSkipDialog dialog = SetupSkipDialog.newInstance( + mIsAlphaMode ? CREDENTIAL_TYPE_PASSWORD : CREDENTIAL_TYPE_PIN, frpSupported, - /* isPatternMode= */ false, - mIsAlphaMode, forFingerprint, forFace, - forBiometrics); + forBiometrics, + WizardManagerHelper.isAnySetupWizard(intent)); ConfirmDeviceCredentialUtils.hideImeImmediately( getActivity().getWindow().getDecorView()); diff --git a/src/com/android/settings/password/SetupChooseLockPattern.java b/src/com/android/settings/password/SetupChooseLockPattern.java index 09ecda48ee5..2cad1813568 100644 --- a/src/com/android/settings/password/SetupChooseLockPattern.java +++ b/src/com/android/settings/password/SetupChooseLockPattern.java @@ -18,6 +18,8 @@ package com.android.settings.password; import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; + import android.content.Context; import android.content.Intent; import android.os.Bundle; @@ -32,6 +34,8 @@ import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.SetupRedactionInterstitial; +import com.google.android.setupcompat.util.WizardManagerHelper; + /** * Setup Wizard's version of ChooseLockPattern screen. It inherits the logic and basic structure * from ChooseLockPattern class, and should remain similar to that behaviorally. This class should @@ -101,14 +105,13 @@ public class SetupChooseLockPattern extends ChooseLockPattern { .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false); final boolean forBiometrics = intent .getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false); - final SetupSkipDialog dialog = SetupSkipDialog.newInstance( + CREDENTIAL_TYPE_PATTERN, frpSupported, - /* isPatternMode= */ true, - /* isAlphaMode= */ false, forFingerprint, forFace, - forBiometrics); + forBiometrics, + WizardManagerHelper.isAnySetupWizard(intent)); dialog.show(getFragmentManager()); return; } diff --git a/src/com/android/settings/password/SetupSkipDialog.java b/src/com/android/settings/password/SetupSkipDialog.java index 2dac3d655dd..9049da7348e 100644 --- a/src/com/android/settings/password/SetupSkipDialog.java +++ b/src/com/android/settings/password/SetupSkipDialog.java @@ -16,6 +16,14 @@ package com.android.settings.password; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS; +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_IS_SUW; + import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -29,7 +37,10 @@ import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.fragment.app.FragmentManager; +import com.android.internal.widget.LockPatternUtils; import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.biometrics.BiometricUtils; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; public class SetupSkipDialog extends InstrumentedDialogFragment @@ -38,24 +49,23 @@ public class SetupSkipDialog extends InstrumentedDialogFragment public static final String EXTRA_FRP_SUPPORTED = ":settings:frp_supported"; private static final String ARG_FRP_SUPPORTED = "frp_supported"; - // The key indicates type of lock screen is pattern setup. - private static final String ARG_LOCK_TYPE_PATTERN = "lock_type_pattern"; + // The key indicates type of screen lock credential types(PIN/Pattern/Password) + private static final String ARG_LOCK_CREDENTIAL_TYPE = "lock_credential_type"; // The key indicates type of lock screen setup is alphanumeric for password setup. - private static final String ARG_LOCK_TYPE_ALPHANUMERIC = "lock_type_alphanumeric"; private static final String TAG_SKIP_DIALOG = "skip_dialog"; public static final int RESULT_SKIP = Activity.RESULT_FIRST_USER + 10; - public static SetupSkipDialog newInstance(boolean isFrpSupported, boolean isPatternMode, - boolean isAlphanumericMode, boolean forFingerprint, boolean forFace, - boolean forBiometrics) { + public static SetupSkipDialog newInstance(@LockPatternUtils.CredentialType int credentialType, + boolean isFrpSupported, boolean forFingerprint, boolean forFace, + boolean forBiometrics, boolean isSuw) { SetupSkipDialog dialog = new SetupSkipDialog(); Bundle args = new Bundle(); + args.putInt(ARG_LOCK_CREDENTIAL_TYPE, credentialType); args.putBoolean(ARG_FRP_SUPPORTED, isFrpSupported); - args.putBoolean(ARG_LOCK_TYPE_PATTERN, isPatternMode); - args.putBoolean(ARG_LOCK_TYPE_ALPHANUMERIC, isAlphanumericMode); - args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint); - args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace); - args.putBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometrics); + args.putBoolean(EXTRA_KEY_FOR_FINGERPRINT, forFingerprint); + args.putBoolean(EXTRA_KEY_FOR_FACE, forFace); + args.putBoolean(EXTRA_KEY_FOR_BIOMETRICS, forBiometrics); + args.putBoolean(EXTRA_KEY_IS_SUW, isSuw); dialog.setArguments(args); return dialog; } @@ -70,59 +80,59 @@ public class SetupSkipDialog extends InstrumentedDialogFragment return onCreateDialogBuilder().create(); } + private AlertDialog.Builder getBiometricsBuilder( + @LockPatternUtils.CredentialType int credentialType, boolean isSuw, boolean hasFace, + boolean hasFingerprint) { + final boolean isFaceSupported = hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw( + getContext())); + final int msgResId; + final int screenLockResId; + switch (credentialType) { + case CREDENTIAL_TYPE_PATTERN: + screenLockResId = R.string.unlock_set_unlock_pattern_title; + msgResId = getPatternSkipMessageRes(hasFace && isFaceSupported, hasFingerprint); + break; + case CREDENTIAL_TYPE_PASSWORD: + screenLockResId = R.string.unlock_set_unlock_password_title; + msgResId = getPasswordSkipMessageRes(hasFace && isFaceSupported, hasFingerprint); + break; + case CREDENTIAL_TYPE_PIN: + default: + screenLockResId = R.string.unlock_set_unlock_pin_title; + msgResId = getPinSkipMessageRes(hasFace && isFaceSupported, hasFingerprint); + break; + } + return new AlertDialog.Builder(getContext()) + .setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this) + .setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this) + .setTitle(getSkipSetupTitle(screenLockResId, hasFingerprint, + hasFace && isFaceSupported)) + .setMessage(msgResId); + } + @NonNull public AlertDialog.Builder onCreateDialogBuilder() { Bundle args = getArguments(); - final boolean forFace = - args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE); - final boolean forFingerprint = - args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT); - final boolean forBiometrics = - args.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS); + final boolean isSuw = args.getBoolean(EXTRA_KEY_IS_SUW); + final boolean forBiometrics = args.getBoolean(EXTRA_KEY_FOR_BIOMETRICS); + final boolean forFace = args.getBoolean(EXTRA_KEY_FOR_FACE); + final boolean forFingerprint = args.getBoolean(EXTRA_KEY_FOR_FINGERPRINT); + @LockPatternUtils.CredentialType + final int credentialType = args.getInt(ARG_LOCK_CREDENTIAL_TYPE); + if (forFace || forFingerprint || forBiometrics) { - final boolean hasFace = forFace || forBiometrics; - final boolean hasFingerprint = forFingerprint || forBiometrics; - - final int titleId; - final int msgResId; - if (args.getBoolean(ARG_LOCK_TYPE_PATTERN)) { - titleId = getPatternSkipTitleRes(hasFace, hasFingerprint); - msgResId = getPatternSkipMessageRes(hasFace, hasFingerprint); - } else if (args.getBoolean(ARG_LOCK_TYPE_ALPHANUMERIC)) { - titleId = getPasswordSkipTitleRes(hasFace, hasFingerprint); - msgResId = getPasswordSkipMessageRes(hasFace, hasFingerprint); - } else { - titleId = getPinSkipTitleRes(hasFace, hasFingerprint); - msgResId = getPinSkipMessageRes(hasFace, hasFingerprint); - } - - return new AlertDialog.Builder(getContext()) - .setPositiveButton(R.string.skip_lock_screen_dialog_button_label, this) - .setNegativeButton(R.string.cancel_lock_screen_dialog_button_label, this) - .setTitle(titleId) - .setMessage(msgResId); - } else { - return new AlertDialog.Builder(getContext()) - .setPositiveButton(R.string.skip_anyway_button_label, this) - .setNegativeButton(R.string.go_back_button_label, this) - .setTitle(R.string.lock_screen_intro_skip_title) - .setMessage(args.getBoolean(ARG_FRP_SUPPORTED) ? - R.string.lock_screen_intro_skip_dialog_text_frp : - R.string.lock_screen_intro_skip_dialog_text); + final boolean hasFace = Utils.hasFaceHardware(getContext()); + final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext()); + return getBiometricsBuilder(credentialType, isSuw, hasFace, hasFingerprint); } - } - @StringRes - private int getPatternSkipTitleRes(boolean hasFace, boolean hasFingerprint) { - if (hasFace && hasFingerprint) { - return R.string.lock_screen_pattern_skip_biometrics_title; - } else if (hasFace) { - return R.string.lock_screen_pattern_skip_face_title; - } else if (hasFingerprint) { - return R.string.lock_screen_pattern_skip_fingerprint_title; - } else { - return R.string.lock_screen_pattern_skip_title; - } + return new AlertDialog.Builder(getContext()) + .setPositiveButton(R.string.skip_anyway_button_label, this) + .setNegativeButton(R.string.go_back_button_label, this) + .setTitle(R.string.lock_screen_intro_skip_title) + .setMessage(args.getBoolean(ARG_FRP_SUPPORTED) ? + R.string.lock_screen_intro_skip_dialog_text_frp : + R.string.lock_screen_intro_skip_dialog_text); } @StringRes @@ -138,19 +148,6 @@ public class SetupSkipDialog extends InstrumentedDialogFragment } } - @StringRes - private int getPasswordSkipTitleRes(boolean hasFace, boolean hasFingerprint) { - if (hasFace && hasFingerprint) { - return R.string.lock_screen_password_skip_biometrics_title; - } else if (hasFace) { - return R.string.lock_screen_password_skip_face_title; - } else if (hasFingerprint) { - return R.string.lock_screen_password_skip_fingerprint_title; - } else { - return R.string.lock_screen_password_skip_title; - } - } - @StringRes private int getPasswordSkipMessageRes(boolean hasFace, boolean hasFingerprint) { if (hasFace && hasFingerprint) { @@ -164,19 +161,6 @@ public class SetupSkipDialog extends InstrumentedDialogFragment } } - @StringRes - private int getPinSkipTitleRes(boolean hasFace, boolean hasFingerprint) { - if (hasFace && hasFingerprint) { - return R.string.lock_screen_pin_skip_biometrics_title; - } else if (hasFace) { - return R.string.lock_screen_pin_skip_face_title; - } else if (hasFingerprint) { - return R.string.lock_screen_pin_skip_fingerprint_title; - } else { - return R.string.lock_screen_pin_skip_title; - } - } - @StringRes private int getPinSkipMessageRes(boolean hasFace, boolean hasFingerprint) { if (hasFace && hasFingerprint) { @@ -190,6 +174,13 @@ public class SetupSkipDialog extends InstrumentedDialogFragment } } + private String getSkipSetupTitle(int screenTypeResId, boolean hasFingerprint, + boolean hasFace) { + return getString(R.string.lock_screen_skip_setup_title, + BiometricUtils.getCombinedScreenLockOptions(getContext(), + getString(screenTypeResId), hasFingerprint, hasFace)); + } + @Override public void onClick(DialogInterface dialog, int button) { Activity activity = getActivity(); diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java index 9cedba9e318..762fbf8bacc 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java @@ -106,6 +106,7 @@ public class DataUsageListTest { ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices); doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager(); mDataUsageList.mLoadingViewController = mock(LoadingViewController.class); + doNothing().when(mDataUsageList).updateSubscriptionInfoEntity(); } @Test diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java index 05bd2a70b8c..052f705263e 100644 --- a/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java +++ b/tests/robotests/src/com/android/settings/development/DevelopmentMemtagPageTest.java @@ -41,11 +41,10 @@ public class DevelopmentMemtagPageTest { mContext = RuntimeEnvironment.application; } - @Ignore @Test - public void getMetricsCategory_isSETTINGS_MEMTAG_CATEGORY() { + public void getMetricsCategory_isSETTINGS_DEVELOPMENT_MEMTAG_CATEGORY() { assertThat(mMemtagPage.getMetricsCategory()) - .isEqualTo(SettingsEnums.SETTINGS_MEMTAG_CATEGORY); + .isEqualTo(SettingsEnums.SETTINGS_DEVELOPMENT_MEMTAG_CATEGORY); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java index 844285e239b..74f62ad936d 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java @@ -57,17 +57,18 @@ public final class BatteryHistoricalLogUtilTest { BatteryHistoricalLogUtil.writeLog(mContext, Action.APPLY, "pkg1", "logs"); BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); - assertThat(mTestStringWriter.toString()).contains("pkg1\tAction:APPLY\tEvent:logs"); + assertThat(mTestStringWriter.toString()).contains( + "pkg1\tAction:APPLY\tEvent:logs\tTimestamp:"); } @Test public void writeLog_multipleLogs_withCorrectCounts() { for (int i = 0; i < BatteryHistoricalLogUtil.MAX_ENTRIES; i++) { - BatteryHistoricalLogUtil.writeLog(mContext, Action.MANUAL, "pkg" + i, "logs"); + BatteryHistoricalLogUtil.writeLog(mContext, Action.LEAVE, "pkg" + i, "logs"); } BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter); - assertThat(mTestStringWriter.toString().split("MANUAL").length).isEqualTo(41); + assertThat(mTestStringWriter.toString().split("LEAVE").length).isEqualTo(41); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java index 5b0ae046c5b..e13dcc03161 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java @@ -54,8 +54,7 @@ public class BatteryTipLoaderTest { BatteryTip.TipType.BATTERY_DEFENDER, BatteryTip.TipType.DOCK_DEFENDER, BatteryTip.TipType.INCOMPATIBLE_CHARGER, - BatteryTip.TipType.HIGH_DEVICE_USAGE, - BatteryTip.TipType.SMART_BATTERY_MANAGER}; + BatteryTip.TipType.HIGH_DEVICE_USAGE}; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private BatteryUsageStats mBatteryUsageStats; @Mock diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java index f2894cc20e2..dbc60dce731 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java @@ -79,6 +79,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import org.robolectric.android.controller.ActivityController; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowPersistentDataBlockManager; @@ -98,6 +99,8 @@ public class ChooseLockGenericTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + private ActivityController mActivityController; private FakeFeatureFactory mFakeFeatureFactory; private ChooseLockGenericFragment mFragment; private ChooseLockGeneric mActivity; @@ -109,7 +112,8 @@ public class ChooseLockGenericTest { @Before public void setUp() { mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); - mActivity = Robolectric.buildActivity(ChooseLockGeneric.class) + mActivityController = Robolectric.buildActivity(ChooseLockGeneric.class); + mActivity = mActivityController .create() .start() .postCreate(null) @@ -314,6 +318,20 @@ public class ChooseLockGenericTest { assertThat(mActivity.isFinishing()).isTrue(); } + @Test + public void securedScreenLock_notChangingConfig_notWaitForConfirmation_onStopFinishSelf() { + Intent intent = new Intent().putExtra( + LockPatternUtils.PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + intent.putExtra("waiting_for_confirmation", true); + initActivity(intent); + + mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */); + mActivityController.configurationChange(); + mActivityController.stop(); + + assertThat(mActivity.isFinishing()).isTrue(); + } + @Test public void onPreferenceTreeClick_fingerprintPassesMinComplexityInfoOntoNextActivity() { Intent intent = new Intent(ACTION_SET_NEW_PASSWORD) @@ -534,10 +552,10 @@ public class ChooseLockGenericTest { assertThat(passwordIntent.getIntExtra(ChooseLockPassword.EXTRA_KEY_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_LOW); - final String supportFingerprint = mActivity.getResources().getString( - R.string.security_settings_fingerprint); - final String supportFace = mActivity.getResources().getString( - R.string.keywords_face_settings); + final String supportFingerprint = capitalize(mActivity.getResources().getString( + R.string.security_settings_fingerprint)); + final String supportFace = capitalize(mActivity.getResources().getString( + R.string.keywords_face_settings)); assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains( supportFingerprint); @@ -563,4 +581,8 @@ public class ChooseLockGenericTest { .create().start().postCreate(null).resume().get(); mActivity.getSupportFragmentManager().beginTransaction().add(mFragment, null).commitNow(); } + + private static String capitalize(final String input) { + return Character.toUpperCase(input.charAt(0)) + input.substring(1); + } } diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java index 8db3fd75154..b04a71821c0 100644 --- a/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockGenericTest.java @@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; +import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -43,6 +44,7 @@ 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.android.settings.utils.ActivityControllerWrapper; import com.google.android.setupdesign.GlifPreferenceLayout; @@ -100,6 +102,7 @@ public class SetupChooseLockGenericTest { @Test public void setupChooseLockGenericPasswordComplexityExtraWithoutPermission() { Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN"); + intent.putExtra(EXTRA_IS_SETUP_FLOW, true); intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH); SetupChooseLockGeneric activity = Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get(); @@ -114,6 +117,7 @@ public class SetupChooseLockGenericTest { ShadowPasswordUtils.addGrantedPermission(REQUEST_PASSWORD_COMPLEXITY); Intent intent = new Intent("com.android.settings.SETUP_LOCK_SCREEN"); + intent.putExtra(EXTRA_IS_SETUP_FLOW, true); intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH); SetupChooseLockGeneric activity = Robolectric.buildActivity(SetupChooseLockGeneric.class, intent).create().get(); @@ -124,7 +128,8 @@ public class SetupChooseLockGenericTest { @Test public void setupChooseLockGenericUsingDescriptionTextOfGlifLayout() { - SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(false); + SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true, true, + false); GlifPreferenceLayout view = getViewOfSetupChooseLockGenericFragment(fragment); assertThat(TextUtils.isEmpty(view.getDescriptionText())).isFalse(); assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText()); @@ -132,47 +137,24 @@ public class SetupChooseLockGenericTest { @Test public void setupChooseLockGenericUsingDescriptionTextOfGlifLayoutForBiometric() { - SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true); + SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true, true, + true); GlifPreferenceLayout view = getViewOfSetupChooseLockGenericFragment(fragment); assertThat(TextUtils.isEmpty(view.getDescriptionText())).isFalse(); assertThat(view.getDescriptionText().toString()).isEqualTo(fragment.loadDescriptionText()); } - @Test - public void updatePreferenceTextShowScreenLockAndFingerprint() { - when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn( - false); - SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true); - - final String supportFingerprint = fragment.getResources().getString( - R.string.security_settings_fingerprint); - final String supportFace = fragment.getResources().getString( - R.string.keywords_face_settings); - - assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains( - supportFingerprint); - assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).doesNotContain( - supportFace); - assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains( - supportFingerprint); - assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).doesNotContain( - supportFace); - assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains( - supportFingerprint); - assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).doesNotContain( - supportFace); - } - @Test public void updatePreferenceTextShowScreenLockAndShowFaceAndShowFingerprint() { when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn( true); - SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true); + SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true, true, + true); - final String supportFingerprint = fragment.getResources().getString( - R.string.security_settings_fingerprint); - final String supportFace = fragment.getResources().getString( - R.string.keywords_face_settings); + final String supportFingerprint = capitalize(fragment.getResources().getString( + R.string.security_settings_fingerprint)); + final String supportFace = capitalize(fragment.getResources().getString( + R.string.keywords_face_settings)); assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains( supportFingerprint); @@ -192,12 +174,13 @@ public class SetupChooseLockGenericTest { public void updatePreferenceTextShowScreenLockAndShowFingerprint() { when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn( false); - SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(true); + SetupChooseLockGenericFragment fragment = getFragmentOfSetupChooseLockGeneric(false, false, + true); - final String supportFingerprint = fragment.getResources().getString( - R.string.security_settings_fingerprint); - final String supportFace = fragment.getResources().getString( - R.string.keywords_face_settings); + final String supportFingerprint = capitalize(fragment.getResources().getString( + R.string.security_settings_fingerprint)); + final String supportFace = capitalize(fragment.getResources().getString( + R.string.keywords_face_settings)); assertThat(fragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains( supportFingerprint); @@ -213,16 +196,18 @@ public class SetupChooseLockGenericTest { supportFace); } - private SetupChooseLockGenericFragment getFragmentOfSetupChooseLockGeneric(boolean biometric) { + private SetupChooseLockGenericFragment getFragmentOfSetupChooseLockGeneric( + boolean forFingerprint, boolean forFace, boolean forBiometric) { 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); - intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, biometric); - // TODO(b/275023433) This presents the activity from being made 'visible` is workaround - SetupChooseLockGeneric activity = - Robolectric.buildActivity(SetupChooseLockGeneric.class, - intent).create().start().postCreate(null).resume().get(); + intent.putExtra(EXTRA_IS_SETUP_FLOW, true); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, forFingerprint); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, forFace); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, forBiometric); + + SetupChooseLockGeneric activity = (SetupChooseLockGeneric) ActivityControllerWrapper.setup( + Robolectric.buildActivity(SetupChooseLockGeneric.class, intent)).get(); List fragments = activity.getSupportFragmentManager().getFragments(); assertThat(fragments).isNotNull(); @@ -238,4 +223,8 @@ public class SetupChooseLockGenericTest { return (GlifPreferenceLayout) fragment.getView(); } + + private static String capitalize(final String input) { + return Character.toUpperCase(input.charAt(0)) + input.substring(1); + } } diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java index abc7400b466..a3e2ed49591 100644 --- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPasswordTest.java @@ -30,7 +30,6 @@ import android.widget.Button; import androidx.appcompat.app.AlertDialog; import com.android.settings.R; -import com.android.settings.utils.ActivityControllerWrapper; import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; import com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.Stage; import com.android.settings.password.ChooseLockPassword.IntentBuilder; @@ -40,6 +39,7 @@ import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowDevicePolicyManager; import com.android.settings.testutils.shadow.ShadowLockPatternUtils; import com.android.settings.testutils.shadow.ShadowUtils; +import com.android.settings.utils.ActivityControllerWrapper; import com.android.settings.widget.ScrollToParentEditText; import com.google.android.setupcompat.PartnerCustomizationLayout; @@ -93,7 +93,6 @@ public class SetupChooseLockPasswordTest { application, new IntentBuilder(application).build()); - //ActivityController.of(new SetupChooseLockPassword(), intent).setup().get(); ActivityControllerWrapper.setup( Robolectric.buildActivity(SetupChooseLockPassword.class, intent)).get(); } @@ -204,7 +203,6 @@ public class SetupChooseLockPasswordTest { intent.putExtra(ChooseLockGenericFragment.EXTRA_SHOW_OPTIONS_BUTTON, true); return (SetupChooseLockPassword) ActivityControllerWrapper.setup( Robolectric.buildActivity(SetupChooseLockPassword.class, intent)).get(); - //return ActivityController.of(new SetupChooseLockPassword(), intent).setup().get(); } @Implements(ChooseLockGenericController.class) diff --git a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java index 1512ee564b3..c5e08137863 100644 --- a/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupChooseLockPatternTest.java @@ -38,10 +38,10 @@ import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView.Cell; import com.android.internal.widget.LockPatternView.DisplayMode; -import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment; -import com.android.settings.password.ChooseLockPattern.IntentBuilder; import com.android.settings.R; import com.android.settings.SetupRedactionInterstitial; +import com.android.settings.password.ChooseLockPattern.ChooseLockPatternFragment; +import com.android.settings.password.ChooseLockPattern.IntentBuilder; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowLockPatternUtils; import com.android.settings.testutils.shadow.ShadowUtils; @@ -84,7 +84,7 @@ public class SetupChooseLockPatternTest { new IntentBuilder(application) .setUserId(UserHandle.myUserId()) .build()); - //mActivity = ActivityController.of(new SetupChooseLockPattern(), intent).setup().get(); + mActivity = (SetupChooseLockPattern) ActivityControllerWrapper.setup( Robolectric.buildActivity(SetupChooseLockPattern.class, intent)).get(); } diff --git a/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java b/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java index ae360e528f6..813efe9f1b5 100644 --- a/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java +++ b/tests/robotests/src/com/android/settings/password/SetupSkipDialogTest.java @@ -16,18 +16,34 @@ package com.android.settings.password; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import android.hardware.face.FaceManager; +import android.hardware.fingerprint.FingerprintManager; + import androidx.fragment.app.FragmentActivity; import androidx.test.core.app.ApplicationProvider; import com.android.settings.R; +import com.android.settings.biometrics.BiometricUtils; +import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.utils.ActivityControllerWrapper; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; @@ -39,12 +55,25 @@ import org.robolectric.shadows.ShadowApplication; @Config(shadows = {ShadowUtils.class, ShadowAlertDialog.class}) public class SetupSkipDialogTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Mock + private FingerprintManager mFingerprintManager; + @Mock + private FaceManager mFaceManager; private FragmentActivity mActivity; + private FakeFeatureFactory mFakeFeatureFactory; @Before public void setUp() { + ShadowUtils.setFingerprintManager(mFingerprintManager); + ShadowUtils.setFaceManager(mFaceManager); + mFakeFeatureFactory = FakeFeatureFactory.setupForTest(); mActivity = (FragmentActivity) ActivityControllerWrapper.setup( Robolectric.buildActivity(FragmentActivity.class)).get(); + + when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn( + true); } private ShadowAlertDialog getShadowAlertDialog() { @@ -55,10 +84,33 @@ public class SetupSkipDialogTest { return shadowAlertDialog; } + private String getSkipSetupTitle(int credentialType, boolean hasFingerprint, + boolean hasFace) { + final int screenLockResId; + switch (credentialType) { + case CREDENTIAL_TYPE_PATTERN: + screenLockResId = R.string.unlock_set_unlock_pattern_title; + break; + case CREDENTIAL_TYPE_PASSWORD: + screenLockResId = R.string.unlock_set_unlock_password_title; + break; + case CREDENTIAL_TYPE_PIN: + default: + screenLockResId = R.string.unlock_set_unlock_pin_title; + break; + } + return mActivity.getString(R.string.lock_screen_skip_setup_title, + BiometricUtils.getCombinedScreenLockOptions(mActivity, + mActivity.getString(screenLockResId), hasFingerprint, hasFace)); + } + @Test public void frpMessages_areShownCorrectly_whenNotSupported() { + when(mFaceManager.isHardwareDetected()).thenReturn(false); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(false, false, false, false, false, false); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, false, false, false, false, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); @@ -70,8 +122,11 @@ public class SetupSkipDialogTest { @Test public void frpMessages_areShownCorrectly_whenSupported() { + when(mFaceManager.isHardwareDetected()).thenReturn(false); + when(mFingerprintManager.isHardwareDetected()).thenReturn(false); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, false, false, false, false); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, true, false, false, false, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); @@ -83,117 +138,175 @@ public class SetupSkipDialogTest { @Test public void dialogMessage_whenSkipPinSetupForFace_shouldShownCorrectly() { - SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, false, false, true, false); + final boolean hasFace = true; + final boolean hasFingerprint = false; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + + SetupSkipDialog setupSkipDialog = SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, false, + false, true, false, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_pin_skip_face_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PIN, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_pin_skip_face_message)); } @Test public void dialogMessage_whenSkipPasswordSetupForFace_shouldShownCorrectly() { - SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, true, false, true, false); + final boolean hasFace = true; + final boolean hasFingerprint = false; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + + SetupSkipDialog setupSkipDialog = SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PASSWORD, + false, hasFingerprint, hasFace, false, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_password_skip_face_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PASSWORD, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_password_skip_face_message)); } @Test public void dialogMessage_whenSkipPatternSetupForFace_shouldShownCorrectly() { + final boolean hasFace = true; + final boolean hasFingerprint = false; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, true, false, false, true, false); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PATTERN, true, false, true, false, + true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_pattern_skip_face_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PATTERN, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_pattern_skip_face_message)); } @Test public void dialogMessage_whenSkipPinSetupForFingerprint_shouldShownCorrectly() { + final boolean hasFace = false; + final boolean hasFingerprint = true; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, false, true, false, false); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, true, true, false, false, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_pin_skip_fingerprint_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PIN, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_pin_skip_fingerprint_message)); } @Test public void dialogMessage_whenSkipPasswordSetupForFingerprint_shouldShownCorrectly() { + final boolean hasFace = false; + final boolean hasFingerprint = true; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, true, true, false, false); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PASSWORD, true, true, false, false, + true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_password_skip_fingerprint_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PASSWORD, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_password_skip_fingerprint_message)); } @Test public void dialogMessage_whenSkipPatternSetupForFingerprint_shouldShownCorrectly() { - SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, true, false, true, false, false); + final boolean hasFace = false; + final boolean hasFingerprint = true; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + + SetupSkipDialog setupSkipDialog = SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PATTERN, true, + true, false, false, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_pattern_skip_fingerprint_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PATTERN, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_pattern_skip_fingerprint_message)); } @Test public void dialogMessage_whenSkipPinSetupForBiometrics_shouldShownCorrectly() { + final boolean hasFace = true; + final boolean hasFingerprint = true; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, false, false, false, true); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PIN, true, false, false, true, true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_pin_skip_biometrics_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PIN, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_pin_skip_biometrics_message)); } @Test public void dialogMessage_whenSkipPasswordSetupForBiometrics_shouldShownCorrectly() { + final boolean hasFace = true; + final boolean hasFingerprint = true; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, false, true, false, false, true); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PASSWORD, true, false, false, true, + true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_password_skip_biometrics_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PASSWORD, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_password_skip_biometrics_message)); } @Test public void dialogMessage_whenSkipPatternSetupForBiometrics_shouldShownCorrectly() { + final boolean hasFace = true; + final boolean hasFingerprint = true; + + when(mFaceManager.isHardwareDetected()).thenReturn(hasFace); + when(mFingerprintManager.isHardwareDetected()).thenReturn(hasFingerprint); + SetupSkipDialog setupSkipDialog = - SetupSkipDialog.newInstance(true, true, false, false, false, true); + SetupSkipDialog.newInstance(CREDENTIAL_TYPE_PATTERN, true, false, false, true, + true); setupSkipDialog.show(mActivity.getSupportFragmentManager()); ShadowAlertDialog shadowAlertDialog = getShadowAlertDialog(); assertThat(shadowAlertDialog.getTitle().toString()).isEqualTo( - mActivity.getString(R.string.lock_screen_pattern_skip_biometrics_title)); + getSkipSetupTitle(CREDENTIAL_TYPE_PATTERN, hasFingerprint, hasFace)); assertThat(shadowAlertDialog.getMessage().toString()).isEqualTo( mActivity.getString(R.string.lock_screen_pattern_skip_biometrics_message)); }