diff --git a/aconfig/Android.bp b/aconfig/Android.bp index c1afd6a2476..8be93f04c56 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -9,6 +9,7 @@ aconfig_declarations { container: "system", srcs: [ "*.aconfig", + "catalyst/*.aconfig", ], } @@ -77,4 +78,4 @@ aconfig_declarations { java_aconfig_library { name: "keyboard_flags_lib", aconfig_declarations: "keyboard_flags", -} \ No newline at end of file +} diff --git a/aconfig/catalyst/about_phone.aconfig b/aconfig/catalyst/about_phone.aconfig new file mode 100644 index 00000000000..086304193c2 --- /dev/null +++ b/aconfig/catalyst/about_phone.aconfig @@ -0,0 +1,9 @@ +package: "com.android.settings.flags" +container: "system" + +flag { + name: "catalyst_legal_information" + namespace: "android_settings" + description: "Flag for Legal information" + bug: "323791114" +} diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig index b8cb4d9bcdf..a9c7bd59f23 100644 --- a/aconfig/settings_flag_declarations.aconfig +++ b/aconfig/settings_flag_declarations.aconfig @@ -50,16 +50,16 @@ flag { bug: "351884562" } -flag { - name: "catalyst_legal_information" - namespace: "android_settings" - description: "This flag controls the About phone > Legal information page migration" - bug: "323791114" -} - flag { name: "updated_suggestion_card_aosp" namespace: "android_settings" description: "Use updated suggestion card(s) in AOSP Settings" bug: "323258154" } + +flag { + name: "catalyst" + namespace: "android_settings" + description: "Flag for all screens" + bug: "323791114" +} diff --git a/color-check-baseline.xml b/color-check-baseline.xml index 4c47607fe16..75d4aba8304 100644 --- a/color-check-baseline.xml +++ b/color-check-baseline.xml @@ -6973,4 +6973,103 @@ column="5"/> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/biometric_lockout_error_dialog.xml b/res/layout/biometric_lockout_error_dialog.xml new file mode 100644 index 00000000000..8d4275b6aaa --- /dev/null +++ b/res/layout/biometric_lockout_error_dialog.xml @@ -0,0 +1,54 @@ + + + + + + + + \ No newline at end of file diff --git a/res/layout/modes_set_schedule_layout.xml b/res/layout/modes_set_schedule_layout.xml index d53e2e42a91..e90dc7c5420 100644 --- a/res/layout/modes_set_schedule_layout.xml +++ b/res/layout/modes_set_schedule_layout.xml @@ -73,18 +73,17 @@ android:orientation="vertical" app:layout_constraintGuide_percent="0.5" /> - + diff --git a/res/values/strings.xml b/res/values/strings.xml index f05fdd12b67..cd847f7400e 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -938,6 +938,30 @@ Face, fingerprints, and %s added Identity Check is on and requires a biometric + + Go to Settings + + Identity Check is on and can’t verify it’s you + + Biometrics failed too many times. Lock and unlock your device to retry. + + Biometrics failed too many times. Try again. + + You can manage Identity Check in theft protection settings. Go to Settings + + Biometric required to continue + + Identity Check is on and requires a biometric, but your face or fingerprint sensor is unavailable\n + + Cancel + + OK + + Go to identity check + + Lock screen + + Remote Authenticator Unlock @@ -1739,10 +1763,13 @@ Device admin doesn\'t allow using a recent password - + Ascending, descending, or repeated sequence of digits isn\'t allowed + + Ascending, descending, or repeated sequence of characters isn\'t allowed + Confirm @@ -12102,7 +12129,7 @@ Send and receive text messages by satellite. Included with your account. - Send and receive text messages by satellite. Non included with your account. + Send and receive text messages by satellite. Not included with your account. Satellite messaging diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java index 711d7943ffa..1800a38fd5b 100644 --- a/src/com/android/settings/MainClear.java +++ b/src/com/android/settings/MainClear.java @@ -65,11 +65,13 @@ import android.widget.TextView; import androidx.annotation.VisibleForTesting; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.core.InstrumentedFragment; import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper; import com.android.settings.flags.Flags; import com.android.settings.network.SubscriptionUtil; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.password.ConfirmLockPattern; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -178,6 +180,12 @@ public class MainClear extends InstrumentedFragment implements OnGlobalLayoutLis if (resultCode != Activity.RESULT_OK) { establishInitialState(); + if (requestCode == BIOMETRICS_REQUEST) { + if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(getActivity(), + Utils.BiometricStatus.LOCKOUT, true /* twoFactorAuthentication */); + } + } return; } @@ -192,6 +200,8 @@ public class MainClear extends InstrumentedFragment implements OnGlobalLayoutLis userId, false /* hideBackground */); return; } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { + IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(getActivity(), + biometricAuthStatus, true /* twoFactorAuthentication */); return; } } diff --git a/src/com/android/settings/ResetNetwork.java b/src/com/android/settings/ResetNetwork.java index ad9f35e889b..f86e29f14d1 100644 --- a/src/com/android/settings/ResetNetwork.java +++ b/src/com/android/settings/ResetNetwork.java @@ -18,8 +18,11 @@ package com.android.settings; import android.app.Activity; import android.app.settings.SettingsEnums; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.res.Resources; import android.os.Bundle; import android.provider.Settings; @@ -66,7 +69,7 @@ import java.util.Optional; * prompt, followed by a keyguard pattern trace if the user has defined one, followed by a final * strongly-worded "THIS WILL RESET EVERYTHING" prompt. If at any time the phone is allowed to go * to sleep, is locked, et cetera, then the confirmation sequence is abandoned. - * + *

* This is the initial screen. */ public class ResetNetwork extends InstrumentedFragment { @@ -81,8 +84,20 @@ public class ResetNetwork extends InstrumentedFragment { private View mContentView; private Spinner mSubscriptionSpinner; private Button mInitiateButton; - @VisibleForTesting View mEsimContainer; - @VisibleForTesting CheckBox mEsimCheckbox; + @VisibleForTesting + View mEsimContainer; + @VisibleForTesting + CheckBox mEsimCheckbox; + + private BroadcastReceiver mDefaultSubChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction() != SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED) { + return; + } + establishInitialState(getActiveSubscriptionInfoList()); + } + }; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -97,6 +112,7 @@ public class ResetNetwork extends InstrumentedFragment { /** * Keyguard validation is run using the standard {@link ConfirmLockPattern} * component as a subactivity + * * @param request the request code to be returned once confirmation finishes * @return true if confirmation launched */ @@ -139,7 +155,7 @@ public class ResetNetwork extends InstrumentedFragment { SubscriptionInfo subscription = mSubscriptions.get(selectedIndex); int subId = subscription.getSubscriptionId(); request.setResetTelephonyAndNetworkPolicyManager(subId) - .setResetApn(subId); + .setResetApn(subId); if (Flags.resetMobileNetworkSettings()) { request.setResetImsSubId(subId); } @@ -215,7 +231,6 @@ public class ResetNetwork extends InstrumentedFragment { } int selectedIndex = 0; - int size = mSubscriptions.size(); List subscriptionNames = new ArrayList<>(); for (SubscriptionInfo record : mSubscriptions) { if (record.getSubscriptionId() == defaultSubscription) { @@ -281,6 +296,8 @@ public class ResetNetwork extends InstrumentedFragment { @Override public void onResume() { super.onResume(); + getContext().registerReceiver(mDefaultSubChangeReceiver, + new IntentFilter(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)); if (mContentView == null) { return; @@ -297,6 +314,12 @@ public class ResetNetwork extends InstrumentedFragment { establishInitialState(updatedSubscriptions); } + @Override + public void onPause() { + super.onPause(); + getContext().unregisterReceiver(mDefaultSubChangeReceiver); + } + private boolean showEuiccSettings(Context context) { if (!SubscriptionUtil.isSimHardwareVisible(context)) { return false; diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java index 7e008e43667..b1177dd2d87 100644 --- a/src/com/android/settings/SettingsApplication.java +++ b/src/com/android/settings/SettingsApplication.java @@ -16,8 +16,6 @@ package com.android.settings; -import static com.android.settingslib.flags.Flags.settingsCatalyst; - import android.app.Application; import android.content.Context; import android.content.pm.PackageManager; @@ -73,7 +71,7 @@ public class SettingsApplication extends Application { public void onCreate() { super.onCreate(); - if (settingsCatalyst()) { + if (Flags.catalyst()) { PreferenceScreenRegistry.INSTANCE.setPreferenceScreensSupplier( this::getPreferenceScreens); } diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 62a4ce36753..57a5380e87d 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -1522,6 +1522,7 @@ public final class Utils extends com.android.settingslib.Utils { case BiometricManager.BIOMETRIC_ERROR_LOCKOUT: return BiometricStatus.LOCKOUT; case BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE: + case BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS: return BiometricStatus.NOT_ACTIVE; default: return BiometricStatus.ERROR; diff --git a/src/com/android/settings/biometrics/BiometricEnrollActivity.java b/src/com/android/settings/biometrics/BiometricEnrollActivity.java index dbbe30beaa5..ec215670d0a 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollActivity.java +++ b/src/com/android/settings/biometrics/BiometricEnrollActivity.java @@ -58,6 +58,7 @@ import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockPattern; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.transition.TransitionHelper; @@ -452,7 +453,9 @@ public class BiometricEnrollActivity extends InstrumentedActivity { Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); } else if (biometricStatus != Utils.BiometricStatus.NOT_ACTIVE) { - finish(); + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(this, + biometricStatus); } } } else { @@ -486,7 +489,11 @@ public class BiometricEnrollActivity extends InstrumentedActivity { } break; case BIOMETRIC_AUTH_REQUEST: - if (resultCode != RESULT_OK) { + if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(this, + Utils.BiometricStatus.LOCKOUT); + } else if (resultCode != RESULT_OK) { finish(); } default: diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index 6f9b94a7fba..1f7b3e512b2 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -39,6 +39,7 @@ import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.password.SetupSkipDialog; import com.google.android.setupcompat.template.FooterBarMixin; @@ -425,7 +426,9 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); } else if (biometricStatus != Utils.BiometricStatus.NOT_ACTIVE) { - finish(); + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(this, + biometricStatus); } } else { setResult(resultCode, data); @@ -457,7 +460,13 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase } } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { if (resultCode != RESULT_OK) { - finish(); + if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(this, + Utils.BiometricStatus.LOCKOUT); + } else { + finish(); + } } } super.onActivityResult(requestCode, resultCode, data); diff --git a/src/com/android/settings/biometrics/IdentityCheckBiometricErrorDialog.java b/src/com/android/settings/biometrics/IdentityCheckBiometricErrorDialog.java new file mode 100644 index 00000000000..a4b10fc2e72 --- /dev/null +++ b/src/com/android/settings/biometrics/IdentityCheckBiometricErrorDialog.java @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2024 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.biometrics; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.admin.DevicePolicyManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.provider.Settings; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import androidx.fragment.app.FragmentActivity; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; + +/** Initializes and shows biometric error dialogs related to identity check. */ +public class IdentityCheckBiometricErrorDialog extends InstrumentedDialogFragment { + private static final String TAG = "BiometricErrorDialog"; + + private static final String KEY_ERROR_CODE = "key_error_code"; + private static final String KEY_TWO_FACTOR_AUTHENTICATION = "key_two_factor_authentication"; + private static final String KEY_FINISH_ACTIVITY = "key_finish_activity"; + + private String mActionIdentityCheckSettings = Settings.ACTION_SETTINGS; + @Nullable private BroadcastReceiver mBroadcastReceiver; + private boolean mShouldFinishActivity = false; + + @NonNull + @Override + public Dialog onCreateDialog( + @Nullable Bundle savedInstanceState) { + final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity()); + final LayoutInflater inflater = getActivity().getLayoutInflater(); + final boolean isLockoutError = getArguments().getString(KEY_ERROR_CODE).equals( + Utils.BiometricStatus.LOCKOUT.name()); + final View customView = inflater.inflate(R.layout.biometric_lockout_error_dialog, + null); + final boolean twoFactorAuthentication = getArguments().getBoolean( + KEY_TWO_FACTOR_AUTHENTICATION); + final String identityCheckSettingsAction = getActivity().getString( + R.string.identity_check_settings_action); + mActionIdentityCheckSettings = identityCheckSettingsAction.isEmpty() + ? mActionIdentityCheckSettings : identityCheckSettingsAction; + mShouldFinishActivity = getArguments().getBoolean( + KEY_FINISH_ACTIVITY); + + setTitle(customView, isLockoutError); + setBody(customView, isLockoutError, twoFactorAuthentication); + alertDialogBuilder.setView(customView); + setPositiveButton(alertDialogBuilder, isLockoutError, twoFactorAuthentication); + if (!isLockoutError || !twoFactorAuthentication) { + setNegativeButton(alertDialogBuilder, isLockoutError); + } + if (isLockoutError) { + mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + dismiss(); + } + } + }; + getContext().registerReceiver(mBroadcastReceiver, + new IntentFilter(Intent.ACTION_SCREEN_OFF)); + } + + return alertDialogBuilder.create(); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (mBroadcastReceiver != null) { + getContext().unregisterReceiver(mBroadcastReceiver); + mBroadcastReceiver = null; + } + if (mShouldFinishActivity && getActivity() != null) { + getActivity().finish(); + } + } + + /** + * Shows an error dialog to prompt the user to resolve biometric errors for identity check. + * @param fragmentActivity calling activity + * @param errorCode refers to the biometric error + * @param twoFactorAuthentication if the surface requests LSKF before identity check auth + */ + public static void showBiometricErrorDialog(FragmentActivity fragmentActivity, + Utils.BiometricStatus errorCode, boolean twoFactorAuthentication) { + showBiometricErrorDialog(fragmentActivity, errorCode, twoFactorAuthentication, + false /* finishActivityOnDismiss */); + } + + /** + * Shows an error dialog to prompt the user to resolve biometric errors for identity check. + * Finishes the activity once the dialog is dismissed. + * @param fragmentActivity calling activity + * @param errorCode refers to the biometric error + */ + public static void showBiometricErrorDialogAndFinishActivityOnDismiss( + FragmentActivity fragmentActivity, Utils.BiometricStatus errorCode) { + showBiometricErrorDialog(fragmentActivity, errorCode, true /* twoFactorAuthentication */, + true /* finishActivityOnDismiss */); + } + + private static void showBiometricErrorDialog(FragmentActivity fragmentActivity, + Utils.BiometricStatus errorCode, boolean twoFactorAuthentication, + boolean finishActivityOnDismiss) { + final IdentityCheckBiometricErrorDialog identityCheckBiometricErrorDialog = + new IdentityCheckBiometricErrorDialog(); + final Bundle args = new Bundle(); + args.putCharSequence(KEY_ERROR_CODE, errorCode.name()); + args.putBoolean(KEY_TWO_FACTOR_AUTHENTICATION, twoFactorAuthentication); + args.putBoolean(KEY_FINISH_ACTIVITY, finishActivityOnDismiss); + identityCheckBiometricErrorDialog.setArguments(args); + identityCheckBiometricErrorDialog.show(fragmentActivity.getSupportFragmentManager(), + IdentityCheckBiometricErrorDialog.class.getName()); + } + private void setTitle(View view, boolean lockout) { + final TextView titleTextView = view.findViewById(R.id.title); + if (lockout) { + titleTextView.setText(R.string.identity_check_lockout_error_title); + } else { + titleTextView.setText(R.string.identity_check_general_error_title); + } + } + + private void setBody(View view, boolean lockout, boolean twoFactorAuthentication) { + final TextView textView1 = view.findViewById(R.id.description_1); + final TextView textView2 = view.findViewById(R.id.description_2); + + if (lockout) { + if (twoFactorAuthentication) { + textView1.setText( + R.string.identity_check_lockout_error_two_factor_auth_description_1); + } else { + textView1.setText(R.string.identity_check_lockout_error_description_1); + } + textView2.setText(getClickableDescriptionForLockoutError()); + textView2.setMovementMethod(LinkMovementMethod.getInstance()); + } else { + textView1.setText(R.string.identity_check_general_error_description_1); + textView2.setVisibility(View.GONE); + } + } + + private SpannableString getClickableDescriptionForLockoutError() { + final String description = getResources().getString( + R.string.identity_check_lockout_error_description_2); + final SpannableString spannableString = new SpannableString(description); + final ClickableSpan clickableSpan = new ClickableSpan() { + @Override + public void onClick(View textView) { + dismiss(); + final Intent autoLockSettingsIntent = new Intent(mActionIdentityCheckSettings); + final ResolveInfo autoLockSettingsInfo = getActivity().getPackageManager() + .resolveActivity(autoLockSettingsIntent, 0 /* flags */); + if (autoLockSettingsInfo != null) { + startActivity(autoLockSettingsIntent); + } else { + Log.e(TAG, "Auto lock settings intent could not be resolved."); + } + } + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setUnderlineText(true); + } + }; + final String goToSettings = getActivity().getString(R.string.go_to_settings); + spannableString.setSpan(clickableSpan, description.indexOf(goToSettings), + description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + return spannableString; + } + + private void setPositiveButton(AlertDialog.Builder alertDialogBuilder, boolean lockout, + boolean twoFactorAuthentication) { + if (lockout) { + if (twoFactorAuthentication) { + alertDialogBuilder.setPositiveButton((R.string.okay), + (dialog, which) -> dialog.dismiss()); + } else { + DevicePolicyManager devicePolicyManager = (DevicePolicyManager) + getContext().getSystemService(Context.DEVICE_POLICY_SERVICE); + alertDialogBuilder.setPositiveButton( + R.string.identity_check_lockout_error_lock_screen, + (dialog, which) -> { + dialog.dismiss(); + devicePolicyManager.lockNow(); + }); + } + } else { + alertDialogBuilder.setPositiveButton(R.string.identity_check_biometric_error_ok, + (dialog, which) -> dialog.dismiss()); + } + } + + private void setNegativeButton(AlertDialog.Builder alertDialogBuilder, boolean lockout) { + if (lockout) { + alertDialogBuilder.setNegativeButton(R.string.identity_check_biometric_error_cancel, + (dialog, which) -> dialog.dismiss()); + } else { + alertDialogBuilder.setNegativeButton(R.string.go_to_identity_check, + (dialog, which) -> { + final Intent autoLockSettingsIntent = new Intent( + mActionIdentityCheckSettings); + final ResolveInfo autoLockSettingsInfo = getActivity().getPackageManager() + .resolveActivity(autoLockSettingsIntent, 0 /* flags */); + if (autoLockSettingsInfo != null) { + startActivity(autoLockSettingsIntent); + } else { + Log.e(TAG, "Identity check settings intent could not be resolved."); + } + }); + } + } + + @Override + public int getMetricsCategory() { + return 0; + } +} diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java index 43b5da28044..1d8b7a10a3c 100644 --- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java +++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java @@ -46,10 +46,12 @@ import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricStatusPreferenceController; import com.android.settings.biometrics.BiometricUtils; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.core.SettingsBaseActivity; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.transition.SettingsTransitionHelper; @@ -323,7 +325,9 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { - finish(); + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + biometricAuthStatus); return; } } else { @@ -339,7 +343,13 @@ public abstract class BiometricsSettingsBase extends DashboardFragment { } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { mBiometricsAuthenticationRequested = false; if (resultCode != RESULT_OK) { - finish(); + if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + Utils.BiometricStatus.LOCKOUT); + } else { + finish(); + } } } } diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index d42b570b30d..5a3949b8923 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -45,9 +45,11 @@ import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricUtils; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.core.AbstractPreferenceController; @@ -325,7 +327,9 @@ public class FaceSettings extends DashboardFragment { BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { - finish(); + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + biometricAuthStatus); } } } else if (requestCode == ENROLL_REQUEST) { @@ -336,7 +340,13 @@ public class FaceSettings extends DashboardFragment { } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { mBiometricsAuthenticationRequested = false; if (resultCode != RESULT_OK) { - finish(); + if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + Utils.BiometricStatus.LOCKOUT); + } else { + finish(); + } } } } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 20d453f2ea8..adb6700de9b 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -71,12 +71,14 @@ import com.android.settings.Utils; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricUtils; import com.android.settings.biometrics.GatekeeperPasswordProvider; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.core.SettingsBaseActivity; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockGeneric; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.HelpUtils; import com.android.settingslib.RestrictedLockUtils; @@ -1010,7 +1012,10 @@ public class FingerprintSettings extends SubSettings { BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { - finish(); + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss( + getActivity(), + biometricAuthStatus); } } else { Log.d(TAG, "Data null or GK PW missing"); @@ -1065,7 +1070,13 @@ public class FingerprintSettings extends SubSettings { } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { mBiometricsAuthenticationRequested = false; if (resultCode != RESULT_OK) { - finish(); + if (resultCode == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + Utils.BiometricStatus.LOCKOUT); + } else { + finish(); + } } } } diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java index 220856ae664..6333f22b95b 100644 --- a/src/com/android/settings/dashboard/DashboardFragment.java +++ b/src/com/android/settings/dashboard/DashboardFragment.java @@ -15,8 +15,6 @@ */ package com.android.settings.dashboard; -import static com.android.settingslib.flags.Flags.settingsCatalyst; - import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.ContentResolver; @@ -390,7 +388,7 @@ public abstract class DashboardFragment extends SettingsPreferenceFragment /** Returns if catalyst is enabled on current screen. */ protected final boolean isCatalystEnabled() { - if (!settingsCatalyst()) { + if (!Flags.catalyst()) { return false; } Context context = getContext(); diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 5933015017b..09b7503397e 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -57,6 +57,7 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.RestrictedDashboardFragment; import com.android.settings.development.autofill.AutofillCategoryController; @@ -76,6 +77,7 @@ import com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngle import com.android.settings.development.qstile.DevelopmentTiles; import com.android.settings.development.storage.SharedDataPreferenceController; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.actionbar.SearchMenuController; import com.android.settings.widget.SettingsMainSwitchBar; @@ -377,6 +379,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra userId, false /* hideBackground */); } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { mSwitchBar.setChecked(false); + IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(getActivity(), + biometricAuthStatus, false /* twoFactorAuthentication */); } else { //Reset biometrics once enable dialog is shown mIsBiometricsAuthenticated = false; @@ -559,6 +563,10 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra if (resultCode == RESULT_OK) { mIsBiometricsAuthenticated = true; mSwitchBar.setChecked(true); + } else if (resultCode + == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(getActivity(), + Utils.BiometricStatus.LOCKOUT, false /* twoFactorAuthentication */); } } for (AbstractPreferenceController controller : mPreferenceControllers) { diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java index a9f94b49b45..e8a4e8d2923 100644 --- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java @@ -36,10 +36,12 @@ import androidx.preference.Preference; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.Utils; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -235,10 +237,18 @@ public class BuildNumberPreferenceController extends BasePreferenceController im userId, false /* hideBackground */); } else if (biometricAuthStatus == Utils.BiometricStatus.NOT_ACTIVE) { enableDevelopmentSettings(); + } else { + IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(mFragment.getActivity(), + biometricAuthStatus, true /* twoFactorAuthentication */); + } + } else if (requestCode == REQUEST_IDENTITY_CHECK_FOR_DEV_PREF) { + if (resultCode == Activity.RESULT_OK) { + enableDevelopmentSettings(); + } else if (resultCode + == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog.showBiometricErrorDialog(mFragment.getActivity(), + Utils.BiometricStatus.LOCKOUT, true /* twoFactorAuthentication */); } - } else if (requestCode == REQUEST_IDENTITY_CHECK_FOR_DEV_PREF - && resultCode == Activity.RESULT_OK) { - enableDevelopmentSettings(); } mProcessingLastDevHit = false; return true; diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 09091102f24..ef6a9ad7559 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -84,6 +84,7 @@ 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.biometrics.IdentityCheckBiometricErrorDialog; import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.safetycenter.LockScreenSafetySource; @@ -500,11 +501,18 @@ public class ChooseLockGeneric extends SettingsActivity { BIOMETRIC_AUTH_REQUEST, mUserId, true /* hideBackground */); } else if (biometricAuthStatus != Utils.BiometricStatus.NOT_ACTIVE) { - finish(); + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + biometricAuthStatus); } } else if (requestCode == BIOMETRIC_AUTH_REQUEST) { if (resultCode == Activity.RESULT_OK) { mBiometricsAuthSuccessful = true; + } else if (resultCode + == ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT) { + IdentityCheckBiometricErrorDialog + .showBiometricErrorDialogAndFinishActivityOnDismiss(getActivity(), + Utils.BiometricStatus.LOCKOUT); } else { finish(); } diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index bcf17954c57..aba9eddce21 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -927,7 +927,9 @@ public class ChooseLockPassword extends SettingsActivity { : R.string.lockpassword_pin_too_long)); break; case CONTAINS_SEQUENCE: - messages.add(getString(R.string.lockpassword_pin_no_sequential_digits)); + messages.add(getString(mIsAlphaMode + ? R.string.lockpassword_password_no_sequential_characters + : R.string.lockpassword_pin_no_sequential_digits)); break; case RECENTLY_USED: DevicePolicyManager devicePolicyManager = diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java index e987ebea1cb..d656934a26b 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java @@ -43,6 +43,7 @@ import android.hardware.biometrics.BiometricConstants; import android.hardware.biometrics.BiometricManager; import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback; +import android.hardware.biometrics.Flags; import android.hardware.biometrics.PromptInfo; import android.os.Bundle; import android.os.Handler; @@ -82,6 +83,7 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { "biometric_prompt_negative_button_text"; public static final String BIOMETRIC_PROMPT_HIDE_BACKGROUND = "biometric_prompt_hide_background"; + public static final int BIOMETRIC_LOCKOUT_ERROR_RESULT = 100; public static class InternalActivity extends ConfirmDeviceCredentialActivity { } @@ -129,6 +131,10 @@ public class ConfirmDeviceCredentialActivity extends FragmentActivity { showConfirmCredentials(); } else { Log.i(TAG, "Finishing, device credential not requested"); + if (Flags.mandatoryBiometrics() + && errorCode == BiometricPrompt.BIOMETRIC_ERROR_LOCKOUT_PERMANENT) { + setResult(BIOMETRIC_LOCKOUT_ERROR_RESULT); + } finish(); } } diff --git a/src/com/android/settings/sound/AudioSwitchPreferenceController.java b/src/com/android/settings/sound/AudioSwitchPreferenceController.java index 5938362a14e..e9787a704bc 100644 --- a/src/com/android/settings/sound/AudioSwitchPreferenceController.java +++ b/src/com/android/settings/sound/AudioSwitchPreferenceController.java @@ -45,6 +45,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.bluetooth.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.FeatureFlags; +import com.android.settings.sounde.AudioSwitchUtils; import com.android.settingslib.bluetooth.A2dpProfile; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.CachedBluetoothDevice; @@ -68,7 +69,8 @@ import java.util.concurrent.FutureTask; * updating the current status of switcher entry. Subclasses must overwrite */ public abstract class AudioSwitchPreferenceController extends BasePreferenceController - implements BluetoothCallback, LifecycleObserver, OnStart, OnStop { + implements BluetoothCallback, LifecycleObserver, OnStart, OnStop, + LocalBluetoothProfileManager.ServiceListener { private static final String TAG = "AudioSwitchPrefCtrl"; @@ -149,6 +151,11 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont return; } mLocalBluetoothManager.setForegroundActivity(mContext); + if (!AudioSwitchUtils.isLeAudioProfileReady(mProfileManager)) { + if (mProfileManager != null) { + mProfileManager.addServiceListener(this); + } + } register(); } @@ -159,6 +166,9 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont return; } mLocalBluetoothManager.setForegroundActivity(null); + if (mProfileManager != null) { + mProfileManager.removeServiceListener(this); + } unregister(); } @@ -193,6 +203,20 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont updateState(mPreference); } + @Override + public void onServiceConnected() { + Log.d(TAG, "onServiceConnected"); + if (AudioSwitchUtils.isLeAudioProfileReady(mProfileManager)) { + updateState(mPreference); + } + } + + @Override + public void onServiceDisconnected() { + Log.d(TAG, "onServiceDisconnected()"); + // Do nothing. + } + public void setCallback(AudioSwitchCallback callback) { mAudioSwitchPreferenceCallback = callback; } diff --git a/src/com/android/settings/sound/AudioSwitchUtils.kt b/src/com/android/settings/sound/AudioSwitchUtils.kt new file mode 100644 index 00000000000..de36bb14d31 --- /dev/null +++ b/src/com/android/settings/sound/AudioSwitchUtils.kt @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2024 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.sounde + +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager + +/** + * Utilities class for audio switcher controllers + */ +class AudioSwitchUtils { + companion object { + + /** Check if LE Audio profile is ready. */ + @JvmStatic + fun isLeAudioProfileReady(profileManager: LocalBluetoothProfileManager?): Boolean = + profileManager?.getLeAudioProfile()?.isProfileReady() ?: false + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java index b705ae14cac..0f823d6ab33 100644 --- a/tests/robotests/src/com/android/settings/MainClearTest.java +++ b/tests/robotests/src/com/android/settings/MainClearTest.java @@ -55,7 +55,11 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.development.DevelopmentSettingsEnabler; @@ -114,6 +118,10 @@ public class MainClearTest { @Mock private Intent mMockIntent; + @Mock + private FragmentManager mMockFragmentManager; + @Mock + private FragmentTransaction mMockFragmentTransaction; private MainClear mMainClear; private ShadowActivity mShadowActivity; @@ -391,6 +399,9 @@ public class MainClearTest { @Test @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) public void testOnActivityResultInternal_keyguardRequestNotTriggeringBiometricPrompt_lockoutError() { + final ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(IdentityCheckBiometricErrorDialog.class); + when(mContext.getResources()).thenReturn(mResources); when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager); when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME); @@ -400,12 +411,17 @@ public class MainClearTest { doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST)); doNothing().when(mMainClear).startActivityForResult(any(), anyInt()); doReturn(mMockActivity).when(mMainClear).getActivity(); + doReturn(mMockFragmentManager).when(mMockActivity).getSupportFragmentManager(); + doReturn(mMockFragmentTransaction).when(mMockFragmentManager).beginTransaction(); doReturn(mContext).when(mMainClear).getContext(); mMainClear .onActivityResultInternal(MainClear.KEYGUARD_REQUEST, Activity.RESULT_OK, null); verify(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST)); + verify(mMainClear.getActivity().getSupportFragmentManager().beginTransaction()).add( + argumentCaptor.capture(), any()); + assertThat(argumentCaptor.getValue()).isInstanceOf(IdentityCheckBiometricErrorDialog.class); verify(mMainClear, never()).startActivityForResult(any(), eq(MainClear.BIOMETRICS_REQUEST)); verify(mMainClear, never()).establishInitialState(); verify(mMainClear, never()).getAccountConfirmationIntent(); @@ -427,6 +443,29 @@ public class MainClearTest { verify(mMainClear).showFinalConfirmation(); } + @Test + public void testOnActivityResultInternal_biometricRequestTriggeringBiometricErrorDialog() { + final ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(IdentityCheckBiometricErrorDialog.class); + + doReturn(true).when(mMainClear).isValidRequestCode( + eq(MainClear.BIOMETRICS_REQUEST)); + doNothing().when(mMainClear).establishInitialState(); + doReturn(mMockActivity).when(mMainClear).getActivity(); + doReturn(mMockFragmentManager).when(mMockActivity).getSupportFragmentManager(); + doReturn(mMockFragmentTransaction).when(mMockFragmentManager).beginTransaction(); + doReturn(mContext).when(mMainClear).getContext(); + + mMainClear + .onActivityResultInternal(MainClear.BIOMETRICS_REQUEST, + ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT, null); + + verify(mMainClear).isValidRequestCode(eq(MainClear.BIOMETRICS_REQUEST)); + verify(mMainClear.getActivity().getSupportFragmentManager().beginTransaction()).add( + argumentCaptor.capture(), any()); + verify(mMainClear).establishInitialState(); + } + @Test public void testOnActivityResultInternal_biometricRequestTriggeringInitialState() { doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.BIOMETRICS_REQUEST)); diff --git a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java index 9f45edb4930..9b6896c38e8 100644 --- a/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/development/DevelopmentSettingsDashboardFragmentTest.java @@ -41,6 +41,9 @@ import androidx.fragment.app.FragmentActivity; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.biometrics.IdentityCheckBiometricErrorDialog; +import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.testutils.shadow.ShadowAlertDialogCompat; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.widget.SettingsMainSwitchBar; @@ -233,6 +236,22 @@ public class DevelopmentSettingsDashboardFragmentTest { assertThat(ShadowEnableDevelopmentSettingWarningDialog.mShown).isTrue(); } + @Test + @Config(shadows = ShadowIdentityCheckBiometricErrorDialog.class) + @Ignore("b/354820314") + @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS) + public void onActivityResult_requestBiometricPrompt_showErrorDialog() { + when(mDashboard.getContext()).thenReturn(mContext); + + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0); + mDashboard.onActivityResult(DevelopmentSettingsDashboardFragment.REQUEST_BIOMETRIC_PROMPT, + ConfirmDeviceCredentialActivity.BIOMETRIC_LOCKOUT_ERROR_RESULT, null); + + assertThat(mSwitchBar.isChecked()).isFalse(); + assertThat(ShadowIdentityCheckBiometricErrorDialog.sShown).isTrue(); + } + @Test @Ignore @Config(shadows = ShadowEnableDevelopmentSettingWarningDialog.class) @@ -362,6 +381,16 @@ public class DevelopmentSettingsDashboardFragmentTest { } } + @Implements(IdentityCheckBiometricErrorDialog.class) + public static class ShadowIdentityCheckBiometricErrorDialog { + static boolean sShown; + @Implementation + public static void showBiometricErrorDialog(FragmentActivity fragmentActivity, + Utils.BiometricStatus errorCode) { + sShown = true; + } + } + @Implements(DisableDevSettingsDialogFragment.class) public static class ShadowDisableDevSettingsDialogFragment { diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 1e81ec066d5..2559618d143 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -71,7 +71,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.Shadows; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowDrawable; @@ -314,7 +313,7 @@ public class ChooseLockPasswordTest { /* minComplexity= */ PASSWORD_COMPLEXITY_NONE, /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC, /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"), - "Ascending, descending, or repeated sequence of digits isn't allowed"); + "Ascending, descending, or repeated sequence of characters isn't allowed"); } @Test @@ -356,7 +355,7 @@ public class ChooseLockPasswordTest { /* minComplexity= */ PASSWORD_COMPLEXITY_LOW, /* passwordType= */ PASSWORD_QUALITY_ALPHABETIC, /* userEnteredPassword= */ LockscreenCredential.createPassword("12345678"), - "Ascending, descending, or repeated sequence of digits isn't allowed"); + "Ascending, descending, or repeated sequence of characters isn't allowed"); } @Test diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt index 1910153fb89..60686c91539 100644 --- a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingLabelSimTest.kt @@ -39,6 +39,7 @@ import com.android.settings.R import com.android.settings.network.SimOnboardingService import com.android.settingslib.spa.testutils.waitUntilExists import org.junit.Assert.assertEquals +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -129,6 +130,7 @@ class SimOnboardingLabelSimTest { } @Test + @Ignore fun simOnboardingLabelSimImpl_showItem_show3Items() { preSetupContent() diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt index 385bc420d60..4655a873b76 100644 --- a/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/network/SimOnboardingSelectSimTest.kt @@ -35,6 +35,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.R import com.android.settings.network.SimOnboardingService import com.android.settingslib.spa.testutils.waitUntilExists +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -142,6 +143,7 @@ class SimOnboardingSelectSimTest { } @Test + @Ignore fun simOnboardingSelectSimImpl_showItem_show3Items() { mockSimOnboardingService.stub { on { targetSubId }.doReturn(SUB_ID_1) @@ -168,9 +170,6 @@ class SimOnboardingSelectSimTest { SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) } } -// composeTestRule.setContent { -// SimOnboardingSelectSimImpl(nextAction, cancelAction, mockSimOnboardingService) -// } composeTestRule.onNodeWithText(DISPLAY_NAME_1).assertIsDisplayed() composeTestRule.waitUntilExists(hasText(NUMBER_1)) diff --git a/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java index 34878e1ef2c..7e942d9e94e 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java @@ -246,26 +246,6 @@ public class BuildNumberPreferenceControllerTest { eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF)); } - @Test - @UiThreadTest - @RequiresFlagsEnabled(Flags.FLAG_MANDATORY_BIOMETRICS) - public void onActivityResult_confirmPasswordRequestCompleted_lockoutError() { - when(mUserManager.isAdminUser()).thenReturn(true); - when(mBiometricManager.canAuthenticate(mContext.getUserId(), - BiometricManager.Authenticators.MANDATORY_BIOMETRICS)) - .thenReturn(BiometricManager.BIOMETRIC_ERROR_LOCKOUT); - - final boolean activityResultHandled = mController.onActivityResult( - BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF, - Activity.RESULT_OK, - null); - - assertThat(activityResultHandled).isTrue(); - verify(mFragment, never()).startActivityForResult(any(), - eq(BuildNumberPreferenceController.REQUEST_IDENTITY_CHECK_FOR_DEV_PREF)); - assertThat(DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)).isFalse(); - } - @Test public void onActivityResult_confirmBiometricAuthentication_enableDevPref() { when(mUserManager.isAdminUser()).thenReturn(true);