• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.password;
18 
19 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
20 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
21 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
22 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
23 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
24 import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
25 import static android.app.admin.DevicePolicyResources.Strings.Settings.LOCK_SETTINGS_NEW_PROFILE_LOCK_TITLE;
26 import static android.app.admin.DevicePolicyResources.Strings.Settings.LOCK_SETTINGS_UPDATE_PROFILE_LOCK_TITLE;
27 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK;
28 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK_ACTION;
29 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE;
30 
31 import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
32 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
33 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY;
34 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
35 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
36 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW;
37 
38 import android.app.Activity;
39 import android.app.Dialog;
40 import android.app.admin.DevicePolicyManager;
41 import android.app.admin.DevicePolicyManager.PasswordComplexity;
42 import android.app.settings.SettingsEnums;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.hardware.face.FaceManager;
46 import android.hardware.fingerprint.FingerprintManager;
47 import android.os.Bundle;
48 import android.os.UserHandle;
49 import android.os.UserManager;
50 import android.os.storage.StorageManager;
51 import android.service.persistentdata.PersistentDataBlockManager;
52 import android.text.TextUtils;
53 import android.util.EventLog;
54 import android.util.Log;
55 import android.view.LayoutInflater;
56 import android.view.View;
57 import android.view.ViewGroup;
58 import android.widget.TextView;
59 
60 import androidx.annotation.NonNull;
61 import androidx.annotation.StringRes;
62 import androidx.annotation.VisibleForTesting;
63 import androidx.appcompat.app.AlertDialog;
64 import androidx.fragment.app.Fragment;
65 import androidx.fragment.app.FragmentManager;
66 import androidx.preference.Preference;
67 import androidx.preference.PreferenceScreen;
68 
69 import com.android.internal.widget.LockPatternUtils;
70 import com.android.internal.widget.LockscreenCredential;
71 import com.android.settings.EventLogTags;
72 import com.android.settings.R;
73 import com.android.settings.SettingsActivity;
74 import com.android.settings.SettingsPreferenceFragment;
75 import com.android.settings.SetupWizardUtils;
76 import com.android.settings.Utils;
77 import com.android.settings.biometrics.BiometricEnrollActivity;
78 import com.android.settings.biometrics.BiometricEnrollBase;
79 import com.android.settings.biometrics.BiometricUtils;
80 import com.android.settings.core.SubSettingLauncher;
81 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
82 import com.android.settings.safetycenter.LockScreenSafetySource;
83 import com.android.settings.search.SearchFeatureProvider;
84 import com.android.settingslib.RestrictedPreference;
85 import com.android.settingslib.widget.FooterPreference;
86 
87 import com.google.android.setupcompat.util.WizardManagerHelper;
88 
89 public class ChooseLockGeneric extends SettingsActivity {
90     public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
91 
92     @Override
getIntent()93     public Intent getIntent() {
94         Intent modIntent = new Intent(super.getIntent());
95         modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
96         return modIntent;
97     }
98 
99     @Override
isValidFragment(String fragmentName)100     protected boolean isValidFragment(String fragmentName) {
101         if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
102         return false;
103     }
104 
getFragmentClass()105     /* package */ Class<? extends Fragment> getFragmentClass() {
106         return ChooseLockGenericFragment.class;
107     }
108 
109     public static class InternalActivity extends ChooseLockGeneric {
110     }
111 
112     public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
113 
114         private static final String TAG = "ChooseLockGenericFragment";
115         private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint";
116         private static final String KEY_SKIP_FACE = "unlock_skip_face";
117         private static final String KEY_SKIP_BIOMETRICS = "unlock_skip_biometrics";
118         private static final String PASSWORD_CONFIRMED = "password_confirmed";
119         private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
120         public static final String HIDE_INSECURE_OPTIONS = "hide_insecure_options";
121         public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
122         public static final String KEY_LOCK_SETTINGS_FOOTER ="lock_settings_footer";
123 
124         /**
125          * Boolean extra determining whether a "screen lock options" button should be shown. This
126          * extra is both sent and received by ChooseLockGeneric.
127          *
128          * When this extra is false, nothing will be done.
129          * When ChooseLockGeneric receives this extra set as true, and if ChooseLockGeneric is
130          * starting ChooseLockPassword or ChooseLockPattern automatically without user interaction,
131          * ChooseLockGeneric will set this extra to true when starting ChooseLockPassword/Pattern.
132          *
133          * This gives the user the choice to select a different screen lock type, even if
134          * ChooseLockGeneric selected a default.
135          */
136         public static final String EXTRA_SHOW_OPTIONS_BUTTON = "show_options_button";
137 
138         /**
139          * Original intent extras used to start this activity. This is passed to ChooseLockPassword
140          * when the "screen lock options" button is shown, so that when that button is clicked,
141          * ChooseLockGeneric can be relaunched with the same extras.
142          */
143         public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras";
144 
145         @VisibleForTesting
146         static final int CONFIRM_EXISTING_REQUEST = 100;
147         @VisibleForTesting
148         static final int CHOOSE_LOCK_REQUEST = 102;
149         @VisibleForTesting
150         static final int CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST = 103;
151         @VisibleForTesting
152         static final int SKIP_FINGERPRINT_REQUEST = 104;
153 
154         private LockPatternUtils mLockPatternUtils;
155         private DevicePolicyManager mDpm;
156         private boolean mRequestGatekeeperPasswordHandle = false;
157         private boolean mPasswordConfirmed = false;
158         private boolean mWaitingForConfirmation = false;
159         private LockscreenCredential mUserPassword;
160         private FingerprintManager mFingerprintManager;
161         private FaceManager mFaceManager;
162         private int mUserId;
163         private boolean mIsManagedProfile;
164         private ManagedLockPasswordProvider mManagedPasswordProvider;
165         /**
166          * Whether the activity is launched by admins via
167          * {@link DevicePolicyManager#ACTION_SET_NEW_PASSWORD} or
168          * {@link DevicePolicyManager#ACTION_SET_NEW_PARENT_PROFILE_PASSWORD}
169          */
170         private boolean mIsSetNewPassword = false;
171         private UserManager mUserManager;
172         private ChooseLockGenericController mController;
173         private int mUnificationProfileId = UserHandle.USER_NULL;
174         private LockscreenCredential mUnificationProfileCredential;
175 
176         /**
177          * From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}.
178          * Only contains complexity requested by calling app, not complexity enforced by device
179          * admins.
180          */
181         @PasswordComplexity private int mRequestedMinComplexity;
182 
183         /** From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_CALLER_APP_NAME}. */
184         private String mCallerAppName = null;
185 
186         /**
187          * The value from the intent extra {@link
188          * ChooseLockSettingsHelper#EXTRA_KEY_IS_CALLING_APP_ADMIN}.
189          */
190         private boolean mIsCallingAppAdmin;
191 
192         protected boolean mForFingerprint = false;
193         protected boolean mForFace = false;
194         protected boolean mForBiometrics = false;
195 
196         private boolean mOnlyEnforceDevicePasswordRequirement = false;
197 
198         @Override
getMetricsCategory()199         public int getMetricsCategory() {
200             return SettingsEnums.CHOOSE_LOCK_GENERIC;
201         }
202 
203         @Override
onCreate(Bundle savedInstanceState)204         public void onCreate(Bundle savedInstanceState) {
205             super.onCreate(savedInstanceState);
206             final Activity activity = getActivity();
207             final Bundle arguments = getArguments();
208             if (!WizardManagerHelper.isDeviceProvisioned(activity)
209                     && !canRunBeforeDeviceProvisioned()) {
210                 Log.i(TAG, "Refusing to start because device is not provisioned");
211                 activity.finish();
212                 return;
213             }
214             final Intent intent = activity.getIntent();
215             String chooseLockAction = intent.getAction();
216             mFingerprintManager = Utils.getFingerprintManagerOrNull(activity);
217             mFaceManager = Utils.getFaceManagerOrNull(activity);
218             mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
219             mLockPatternUtils = new LockPatternUtils(activity);
220             mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
221                     || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction);
222 
223             // Defaults to needing to confirm credentials
224             final boolean confirmCredentials = intent
225                 .getBooleanExtra(CONFIRM_CREDENTIALS, true);
226             if (activity instanceof ChooseLockGeneric.InternalActivity) {
227                 mPasswordConfirmed = !confirmCredentials;
228                 mUserPassword = intent.getParcelableExtra(
229                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
230             } else if (arguments != null) {
231                 mUserPassword = (LockscreenCredential) arguments.getParcelable(
232                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
233                 mPasswordConfirmed = mUserPassword != null;
234             }
235 
236             mRequestGatekeeperPasswordHandle = intent.getBooleanExtra(
237                     ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, false);
238             mForFingerprint = intent.getBooleanExtra(
239                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
240             mForFace = intent.getBooleanExtra(
241                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
242             mForBiometrics = intent.getBooleanExtra(
243                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS, false);
244 
245             mRequestedMinComplexity = intent.getIntExtra(
246                     EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
247             mOnlyEnforceDevicePasswordRequirement = intent.getBooleanExtra(
248                     ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY, false);
249 
250             mIsCallingAppAdmin = intent
251                     .getBooleanExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, /* defValue= */ false);
252             mUserManager = UserManager.get(activity);
253 
254             if (arguments != null) {
255                 mUnificationProfileCredential = (LockscreenCredential) arguments.getParcelable(
256                         ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL);
257                 mUnificationProfileId = arguments.getInt(
258                         ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID,
259                         UserHandle.USER_NULL);
260             }
261 
262             if (savedInstanceState != null) {
263                 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
264                 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
265                 mUserPassword = savedInstanceState.getParcelable(
266                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
267             }
268 
269             // a) If this is started from other user, use that user id.
270             // b) If this is started from the same user, read the extra if this is launched
271             //    from Settings app itself.
272             // c) Otherwise, use UserHandle.myUserId().
273             mUserId = Utils.getSecureTargetUser(
274                     activity.getActivityToken(),
275                     UserManager.get(activity),
276                     arguments,
277                     intent.getExtras()).getIdentifier();
278             mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
279             mController = new ChooseLockGenericController.Builder(
280                     getContext(), mUserId, mLockPatternUtils)
281                     .setAppRequestedMinComplexity(mRequestedMinComplexity)
282                     .setEnforceDevicePasswordRequirementOnly(mOnlyEnforceDevicePasswordRequirement)
283                     .setProfileToUnify(mUnificationProfileId)
284                     .setHideInsecureScreenLockTypes(alwaysHideInsecureScreenLockTypes()
285                             || intent.getBooleanExtra(HIDE_INSECURE_OPTIONS, false))
286                     .build();
287 
288             // If the complexity is provided by the admin, do not get the caller app's name.
289             // If the app requires, for example, low complexity, and the admin requires high
290             // complexity, it does not make sense to show a footer telling the user it's the app
291             // requesting a particular complexity because the admin-set complexity will override it.
292             mCallerAppName = mController.isComplexityProvidedByAdmin() ? null :
293                     intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
294 
295             mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId);
296 
297             if (mPasswordConfirmed) {
298                 updatePreferencesOrFinish(savedInstanceState != null);
299             } else if (!mWaitingForConfirmation) {
300                 final ChooseLockSettingsHelper.Builder builder =
301                         new ChooseLockSettingsHelper.Builder(activity, this);
302                 builder.setRequestCode(CONFIRM_EXISTING_REQUEST)
303                         .setTitle(getString(R.string.unlock_set_unlock_launch_picker_title))
304                         .setReturnCredentials(true)
305                         .setUserId(mUserId);
306                 boolean managedProfileWithUnifiedLock =
307                         mIsManagedProfile
308                         && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
309                 boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword;
310                 if (skipConfirmation || !builder.show()) {
311                     mPasswordConfirmed = true; // no password set, so no need to confirm
312                     updatePreferencesOrFinish(savedInstanceState != null);
313                 } else {
314                     mWaitingForConfirmation = true;
315                 }
316             }
317             addHeaderView();
318         }
319 
320         @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)321         public View onCreateView(LayoutInflater inflater, ViewGroup container,
322                 Bundle savedInstanceState) {
323             updateActivityTitle();
324             return super.onCreateView(inflater, container, savedInstanceState);
325         }
326 
alwaysHideInsecureScreenLockTypes()327         protected boolean alwaysHideInsecureScreenLockTypes() {
328             return false;
329         }
330 
updateActivityTitle()331         private void updateActivityTitle() {
332             if (mLockPatternUtils == null) {
333                 // mLockPatternUtils will be uninitialized if ChooseLockGenericFragment.onCreate()
334                 // finishes early.
335                 return;
336             }
337             final boolean updateExistingLock;
338             if (mIsManagedProfile) {
339                 // Going from unified challenge -> separate challenge is considered as adding
340                 // a new lock to the profile, while if the profile already has a separate challenge
341                 // it's an update.
342                 updateExistingLock = mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
343                 if (updateExistingLock) {
344                     getActivity().setTitle(mDpm.getResources().getString(
345                             LOCK_SETTINGS_UPDATE_PROFILE_LOCK_TITLE,
346                             () -> getString(
347                                     R.string.lock_settings_picker_update_profile_lock_title)));
348                 } else {
349                     getActivity().setTitle(mDpm.getResources().getString(
350                             LOCK_SETTINGS_NEW_PROFILE_LOCK_TITLE,
351                             () -> getString(R.string.lock_settings_picker_new_profile_lock_title)));
352                 }
353             } else {
354                 updateExistingLock = mLockPatternUtils.isSecure(mUserId);
355                 if (updateExistingLock) {
356                     getActivity().setTitle(R.string.lock_settings_picker_update_lock_title);
357                 } else {
358                     getActivity().setTitle(R.string.lock_settings_picker_new_lock_title);
359                 }
360             }
361         }
362 
canRunBeforeDeviceProvisioned()363         protected boolean canRunBeforeDeviceProvisioned() {
364             PersistentDataBlockManager pdbm = (PersistentDataBlockManager)
365                     getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
366 
367             // Can only run during setup if factory reset protection has already been cleared
368             // or if the device does not support FRP.
369             return (pdbm == null || pdbm.getDataBlockSize() == 0);
370         }
371 
getInternalActivityClass()372         protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
373             return ChooseLockGeneric.InternalActivity.class;
374         }
375 
addHeaderView()376         protected void addHeaderView() {
377             setHeaderView(R.layout.choose_lock_generic_biometric_header);
378             TextView textView = getHeaderView().findViewById(R.id.biometric_header_description);
379 
380             if (mForFingerprint) {
381                 if (mIsSetNewPassword) {
382                     textView.setText(R.string.fingerprint_unlock_title);
383                 } else {
384                     textView.setText(R.string.lock_settings_picker_biometric_message);
385                 }
386             } else if (mForFace) {
387                 if (mIsSetNewPassword) {
388                     textView.setText(R.string.face_unlock_title);
389                 } else {
390                     textView.setText(R.string.lock_settings_picker_biometric_message);
391                 }
392             } else if (mForBiometrics) {
393                 if (mIsSetNewPassword) {
394                     textView.setText(R.string.biometrics_unlock_title);
395                 } else {
396                     textView.setText(R.string.lock_settings_picker_biometric_message);
397                 }
398             } else {
399                 if (mIsManagedProfile) {
400                     textView.setText(mDpm.getResources().getString(
401                             WORK_PROFILE_SCREEN_LOCK_SETUP_MESSAGE,
402                             () -> getString(R.string.lock_settings_picker_profile_message)));
403                 } else {
404                     textView.setText("");
405                 }
406             }
407         }
408 
409         @Override
onPreferenceTreeClick(Preference preference)410         public boolean onPreferenceTreeClick(Preference preference) {
411             writePreferenceClickMetric(preference);
412 
413             final String key = preference.getKey();
414             if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
415                 // Show the disabling FRP warning only when the user is switching from a secure
416                 // unlock method to an insecure one
417                 showFactoryResetProtectionWarningDialog(key);
418                 return true;
419             } else if (KEY_SKIP_FINGERPRINT.equals(key) || KEY_SKIP_FACE.equals(key)
420                     || KEY_SKIP_BIOMETRICS.equals(key)) {
421                 Intent chooseLockGenericIntent = new Intent(getActivity(),
422                     getInternalActivityClass());
423                 chooseLockGenericIntent.setAction(getIntent().getAction());
424                 if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
425                     SetupWizardUtils.copySetupExtras(getIntent(), chooseLockGenericIntent);
426                 }
427                 // Forward the target user id to  ChooseLockGeneric.
428                 chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
429                 chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
430                 chooseLockGenericIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
431                         mRequestedMinComplexity);
432                 chooseLockGenericIntent.putExtra(EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY,
433                         mOnlyEnforceDevicePasswordRequirement);
434                 chooseLockGenericIntent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
435                 if (mUserPassword != null) {
436                     chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
437                             mUserPassword);
438                 }
439                 startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
440                 return true;
441             } else {
442                 return setUnlockMethod(key);
443             }
444         }
445 
446         @Override
onActivityResult(int requestCode, int resultCode, Intent data)447         public void onActivityResult(int requestCode, int resultCode, Intent data) {
448             super.onActivityResult(requestCode, resultCode, data);
449             mWaitingForConfirmation = false;
450             if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
451                 mPasswordConfirmed = true;
452                 mUserPassword = data != null
453                     ? data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
454                     : null;
455                 updatePreferencesOrFinish(false /* isRecreatingActivity */);
456             } else if (requestCode == CHOOSE_LOCK_REQUEST) {
457                 if (resultCode != RESULT_CANCELED) {
458                     getActivity().setResult(resultCode, data);
459                     finish();
460                 } else {
461                     // If PASSWORD_TYPE_KEY is set, this activity is used as a trampoline to start
462                     // the actual password enrollment. If the result is canceled, which means the
463                     // user pressed back, finish the activity with result canceled.
464                     int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
465                     if (quality != -1) {
466                         getActivity().setResult(RESULT_CANCELED, data);
467                         finish();
468                     }
469                 }
470             } else if (requestCode == CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
471                     && resultCode == BiometricEnrollBase.RESULT_FINISHED) {
472                 Intent intent = getBiometricEnrollIntent(getActivity());
473                 if (data != null) {
474                     // ChooseLockGeneric should have requested for a Gatekeeper Password Handle to
475                     // be returned, so that biometric enrollment(s) can subsequently request
476                     // Gatekeeper to create HardwareAuthToken(s) wrapping biometric-specific
477                     // challenges. Send the extras (including the GK Password) to the enrollment
478                     // activity.
479                     intent.putExtras(data.getExtras());
480                 }
481                 // Forward the target user id to fingerprint setup page.
482                 intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
483                 startActivity(intent);
484                 finish();
485             } else if (requestCode == SKIP_FINGERPRINT_REQUEST) {
486                 if (resultCode != RESULT_CANCELED) {
487                     getActivity().setResult(
488                             resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data);
489                     finish();
490                 }
491             } else if (requestCode == SearchFeatureProvider.REQUEST_CODE) {
492                 return;
493             } else {
494                 getActivity().setResult(Activity.RESULT_CANCELED);
495                 finish();
496             }
497         }
498 
getBiometricEnrollIntent(Context context)499         protected Intent getBiometricEnrollIntent(Context context) {
500             final Intent intent =
501                     new Intent(context, BiometricEnrollActivity.InternalActivity.class);
502             intent.putExtra(BiometricEnrollActivity.EXTRA_SKIP_INTRO, true);
503             return intent;
504         }
505 
506         @Override
onSaveInstanceState(Bundle outState)507         public void onSaveInstanceState(Bundle outState) {
508             super.onSaveInstanceState(outState);
509             // Saved so we don't force user to re-enter their password if configuration changes
510             outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
511             outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
512             if (mUserPassword != null) {
513                 outState.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
514                         mUserPassword.duplicate());
515             }
516         }
517 
518         @VisibleForTesting
updatePreferencesOrFinish(boolean isRecreatingActivity)519         void updatePreferencesOrFinish(boolean isRecreatingActivity) {
520             Intent intent = getActivity().getIntent();
521             int quality = -1;
522             if (StorageManager.isFileEncrypted()) {
523                 quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
524             } else {
525                 // For unencrypted devices, always show the lock type picker and ignore
526                 // PASSWORD_TYPE_KEY.
527                 Log.i(TAG, "Ignoring PASSWORD_TYPE_KEY because device is not file encrypted");
528             }
529             if (quality == -1) {
530                 // If caller didn't specify password quality, show UI and allow the user to choose.
531                 final PreferenceScreen prefScreen = getPreferenceScreen();
532                 if (prefScreen != null) {
533                     prefScreen.removeAll();
534                 }
535                 addPreferences();
536                 disableUnusablePreferences();
537                 updatePreferenceText();
538                 updateCurrentPreference();
539             } else if (!isRecreatingActivity) {
540                 // Don't start the activity again if we are recreated for configuration change
541                 updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */);
542             }
543         }
544 
addPreferences()545         protected void addPreferences() {
546             addPreferencesFromResource(R.xml.security_settings_picker);
547 
548             int profileUserId = Utils.getManagedProfileId(mUserManager, mUserId);
549             final FooterPreference footer = findPreference(KEY_LOCK_SETTINGS_FOOTER);
550             if (!TextUtils.isEmpty(mCallerAppName) && !mIsCallingAppAdmin) {
551                 footer.setVisible(true);
552                 footer.setTitle(getFooterString());
553             } else if (!mForFace && !mForBiometrics && !mForFingerprint && !mIsManagedProfile
554                     && mController.isScreenLockRestrictedByAdmin()
555                     && profileUserId != UserHandle.USER_NULL) {
556                 final StringBuilder description = new StringBuilder(
557                         mDpm.getResources().getString(
558                                 WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK,
559                                 () -> getString(
560                                 R.string.lock_settings_picker_admin_restricted_personal_message)));
561                 footer.setVisible(true);
562                 footer.setTitle(description);
563 
564                 final StringBuilder setLockText = new StringBuilder(
565                         mDpm.getResources().getString(
566                                 WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK_ACTION,
567                                 () -> getString(
568                           R.string.lock_settings_picker_admin_restricted_personal_message_action)));
569                 View.OnClickListener setLockClickListener = (v) -> {
570                     final Bundle extras = new Bundle();
571                     extras.putInt(Intent.EXTRA_USER_ID, profileUserId);
572                     if (mUserPassword != null) {
573                         extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
574                                 mUserPassword);
575                     }
576                     new SubSettingLauncher(getActivity())
577                             .setDestination(ChooseLockGenericFragment.class.getName())
578                             .setSourceMetricsCategory(getMetricsCategory())
579                             .setArguments(extras)
580                             .launch();
581                     finish();
582                 };
583                 footer.setLearnMoreText(setLockText);
584                 footer.setLearnMoreAction(setLockClickListener);
585             } else {
586                 footer.setVisible(false);
587             }
588 
589             // Used for testing purposes
590             findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
591             findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
592             findPreference(KEY_SKIP_FACE).setViewId(R.id.lock_none);
593             findPreference(KEY_SKIP_BIOMETRICS).setViewId(R.id.lock_none);
594             findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin);
595             findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
596         }
597 
getFooterString()598         private String getFooterString() {
599             @StringRes int stringId;
600             switch (mController.getAggregatedPasswordComplexity()) {
601                 case PASSWORD_COMPLEXITY_HIGH:
602                     stringId = R.string.unlock_footer_high_complexity_requested;
603                     break;
604                 case PASSWORD_COMPLEXITY_MEDIUM:
605                     stringId = R.string.unlock_footer_medium_complexity_requested;
606                     break;
607                 case PASSWORD_COMPLEXITY_LOW:
608                     stringId = R.string.unlock_footer_low_complexity_requested;
609                     break;
610                 case PASSWORD_COMPLEXITY_NONE:
611                 default:
612                     stringId = R.string.unlock_footer_none_complexity_requested;
613                     break;
614             }
615 
616             return getResources().getString(stringId, mCallerAppName);
617         }
618 
updatePreferenceText()619         private void updatePreferenceText() {
620             if (mForFingerprint) {
621                 setPreferenceTitle(ScreenLockType.PATTERN,
622                         R.string.fingerprint_unlock_set_unlock_pattern);
623                 setPreferenceTitle(ScreenLockType.PIN, R.string.fingerprint_unlock_set_unlock_pin);
624                 setPreferenceTitle(ScreenLockType.PASSWORD,
625                         R.string.fingerprint_unlock_set_unlock_password);
626             } else if (mForFace) {
627                 setPreferenceTitle(ScreenLockType.PATTERN,
628                         R.string.face_unlock_set_unlock_pattern);
629                 setPreferenceTitle(ScreenLockType.PIN, R.string.face_unlock_set_unlock_pin);
630                 setPreferenceTitle(ScreenLockType.PASSWORD,
631                         R.string.face_unlock_set_unlock_password);
632             } else if (mForBiometrics) {
633                 setPreferenceTitle(ScreenLockType.PATTERN,
634                         getBiometricsPreferenceTitle(ScreenLockType.PATTERN));
635                 setPreferenceTitle(ScreenLockType.PIN,
636                         getBiometricsPreferenceTitle(ScreenLockType.PIN));
637                 setPreferenceTitle(ScreenLockType.PASSWORD,
638                         getBiometricsPreferenceTitle(ScreenLockType.PASSWORD));
639             }
640 
641             if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
642                 setPreferenceTitle(ScreenLockType.MANAGED,
643                         mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
644             } else {
645                 removePreference(ScreenLockType.MANAGED.preferenceKey);
646             }
647 
648             if (!(mForFingerprint && mIsSetNewPassword)) {
649                 removePreference(KEY_SKIP_FINGERPRINT);
650             }
651             if (!(mForFace && mIsSetNewPassword)) {
652                 removePreference(KEY_SKIP_FACE);
653             }
654             if (!(mForBiometrics && mIsSetNewPassword)) {
655                 removePreference(KEY_SKIP_BIOMETRICS);
656             }
657         }
658 
659         @VisibleForTesting
getBiometricsPreferenceTitle(@onNull ScreenLockType secureType)660         String getBiometricsPreferenceTitle(@NonNull ScreenLockType secureType) {
661             final boolean hasFingerprint = Utils.hasFingerprintHardware(getContext());
662             final boolean hasFace = Utils.hasFaceHardware(getContext());
663             final boolean isSuw = WizardManagerHelper.isAnySetupWizard(getIntent());
664             final boolean isFaceSupported =
665                     hasFace && (!isSuw || BiometricUtils.isFaceSupportedInSuw(getContext()));
666 
667             // Assume the flow is "Screen Lock" + "Face" + "Fingerprint"
668             if (mController != null) {
669                 return BiometricUtils.getCombinedScreenLockOptions(getContext(),
670                         mController.getTitle(secureType), hasFingerprint, isFaceSupported);
671             } else {
672                 Log.e(TAG, "ChooseLockGenericController is null!");
673                 return getResources().getString(R.string.error_title);
674             }
675         }
676 
setPreferenceTitle(ScreenLockType lock, @StringRes int title)677         private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
678             Preference preference = findPreference(lock.preferenceKey);
679             if (preference != null) {
680                 preference.setTitle(title);
681             }
682         }
683 
setPreferenceTitle(ScreenLockType lock, CharSequence title)684         private void setPreferenceTitle(ScreenLockType lock, CharSequence title) {
685             Preference preference = findPreference(lock.preferenceKey);
686             if (preference != null) {
687                 preference.setTitle(title);
688             }
689         }
690 
updateCurrentPreference()691         private void updateCurrentPreference() {
692             String currentKey = getKeyForCurrent();
693             Preference preference = findPreference(currentKey);
694             if (preference != null) {
695                 preference.setSummary(R.string.current_screen_lock);
696             }
697         }
698 
getKeyForCurrent()699         private String getKeyForCurrent() {
700             final int credentialOwner = UserManager.get(getContext())
701                     .getCredentialOwnerProfile(mUserId);
702             if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
703                 return ScreenLockType.NONE.preferenceKey;
704             }
705             ScreenLockType lock =
706                     ScreenLockType.fromQuality(
707                             mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner));
708             return lock != null ? lock.preferenceKey : null;
709         }
710 
711         /***
712          * Disables preferences that are less secure than required quality.
713          *
714          */
disableUnusablePreferences()715         private void disableUnusablePreferences() {
716             final PreferenceScreen entries = getPreferenceScreen();
717 
718             for (ScreenLockType lock : ScreenLockType.values()) {
719                 String key = lock.preferenceKey;
720                 Preference pref = findPreference(key);
721                 if (pref instanceof RestrictedPreference) {
722                     boolean visible = mController.isScreenLockVisible(lock);
723                     boolean enabled = mController.isScreenLockEnabled(lock);
724                     if (!visible) {
725                         entries.removePreference(pref);
726                     } else if (!enabled) {
727                         pref.setEnabled(false);
728                     }
729                 }
730             }
731         }
732 
getLockManagedPasswordIntent(LockscreenCredential password)733         protected Intent getLockManagedPasswordIntent(LockscreenCredential password) {
734             return mManagedPasswordProvider.createIntent(false, password);
735         }
736 
getLockPasswordIntent(int quality)737         protected Intent getLockPasswordIntent(int quality) {
738             ChooseLockPassword.IntentBuilder builder =
739                     new ChooseLockPassword.IntentBuilder(getContext())
740                             .setPasswordType(quality)
741                             .setPasswordRequirement(
742                                     mController.getAggregatedPasswordComplexity(),
743                                     mController.getAggregatedPasswordMetrics())
744                             .setForFingerprint(mForFingerprint)
745                             .setForFace(mForFace)
746                             .setForBiometrics(mForBiometrics)
747                             .setUserId(mUserId)
748                             .setRequestGatekeeperPasswordHandle(mRequestGatekeeperPasswordHandle);
749             if (mUserPassword != null) {
750                 builder.setPassword(mUserPassword);
751             }
752             if (mUnificationProfileId != UserHandle.USER_NULL) {
753                 builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential);
754             }
755             return builder.build();
756         }
757 
getLockPatternIntent()758         protected Intent getLockPatternIntent() {
759             ChooseLockPattern.IntentBuilder builder =
760                     new ChooseLockPattern.IntentBuilder(getContext())
761                             .setForFingerprint(mForFingerprint)
762                             .setForFace(mForFace)
763                             .setForBiometrics(mForBiometrics)
764                             .setUserId(mUserId)
765                             .setRequestGatekeeperPasswordHandle(mRequestGatekeeperPasswordHandle);
766             if (mUserPassword != null) {
767                 builder.setPattern(mUserPassword);
768             }
769             if (mUnificationProfileId != UserHandle.USER_NULL) {
770                 builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential);
771             }
772             return builder.build();
773         }
774 
775         /**
776          * Invokes an activity to change the user's pattern, password or PIN based on given quality
777          * and minimum quality specified by DevicePolicyManager. If quality is
778          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
779          *
780          * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
781          * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
782          * @param chooseLockSkipped whether or not this activity is skipped. This is true when this
783          * activity was not shown to the user at all, instead automatically proceeding based on
784          * the given intent extras, typically {@link LockPatternUtils#PASSWORD_TYPE_KEY}.
785          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
786          */
updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped)787         void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) {
788             // We should never get here without confirming user's existing password.
789             if (!mPasswordConfirmed) {
790                 throw new IllegalStateException("Tried to update password without confirming it");
791             }
792 
793             quality = mController.upgradeQuality(quality);
794             Intent intent = getIntentForUnlockMethod(quality);
795             if (intent != null) {
796                 if (getIntent().getBooleanExtra(EXTRA_SHOW_OPTIONS_BUTTON, false)) {
797                     intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped);
798                 }
799                 if (getIntent().getBooleanExtra(EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW, false)) {
800                     intent.putExtra(EXTRA_KEY_REQUEST_WRITE_REPAIR_MODE_PW, true);
801                 }
802                 intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras());
803                 // If the caller requested Gatekeeper Password Handle to be returned, we assume it
804                 // came from biometric enrollment. onActivityResult will put the LockSettingsService
805                 // into the extras and launch biometric enrollment. This should be cleaned up,
806                 // since requesting a Gatekeeper Password Handle should not imply it came from
807                 // biometric setup/settings.
808                 startActivityForResult(intent,
809                         mIsSetNewPassword && mRequestGatekeeperPasswordHandle
810                                 ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
811                                 : CHOOSE_LOCK_REQUEST);
812                 return;
813             }
814 
815             if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
816                 // Clearing of user biometrics when screen lock is cleared is done at
817                 // LockSettingsService.removeBiometricsForUser().
818                 if (mUserPassword != null) {
819                     // No need to call setLockCredential if the user currently doesn't
820                     // have a password
821                     mLockPatternUtils.setLockCredential(
822                             LockscreenCredential.createNone(), mUserPassword, mUserId);
823                 }
824                 mLockPatternUtils.setLockScreenDisabled(disabled, mUserId);
825                 getActivity().setResult(Activity.RESULT_OK);
826                 LockScreenSafetySource.onLockScreenChange(getContext());
827                 finish();
828             }
829         }
830 
getIntentForUnlockMethod(int quality)831         private Intent getIntentForUnlockMethod(int quality) {
832             Intent intent = null;
833             if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
834                 intent = getLockManagedPasswordIntent(mUserPassword);
835             } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
836                 intent = getLockPasswordIntent(quality);
837             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
838                 intent = getLockPatternIntent();
839             }
840             return intent;
841         }
842 
843         @Override
onStop()844         public void onStop() {
845             super.onStop();
846             // hasCredential checks to see if user chooses a password for screen lock. If the
847             // screen lock is None or Swipe, we do not want to call getActivity().finish().
848             // Otherwise, bugs would be caused. (e.g. b/278488549, b/278530059)
849             final boolean hasCredential = mLockPatternUtils.isSecure(mUserId);
850             if (!getActivity().isChangingConfigurations()
851                     && !mWaitingForConfirmation && hasCredential) {
852                 getActivity().finish();
853             }
854         }
855 
856         @Override
onDestroy()857         public void onDestroy() {
858             super.onDestroy();
859             if (mUserPassword != null) {
860                 mUserPassword.zeroize();
861             }
862             // Force a garbage collection immediately to remove remnant of user password shards
863             // from memory.
864             System.gc();
865             System.runFinalization();
866             System.gc();
867         }
868 
869         @Override
getHelpResource()870         public int getHelpResource() {
871             return R.string.help_url_choose_lockscreen;
872         }
873 
getResIdForFactoryResetProtectionWarningTitle()874         private int getResIdForFactoryResetProtectionWarningTitle() {
875             return mIsManagedProfile ? R.string.unlock_disable_frp_warning_title_profile
876                     : R.string.unlock_disable_frp_warning_title;
877         }
878 
getResIdForFactoryResetProtectionWarningMessage()879         private int getResIdForFactoryResetProtectionWarningMessage() {
880             final boolean hasFingerprints;
881             final boolean hasFace;
882             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
883                 hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(mUserId);
884             } else {
885                 hasFingerprints = false;
886             }
887 
888             if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
889                 hasFace = mFaceManager.hasEnrolledTemplates(mUserId);
890             } else {
891                 hasFace = false;
892             }
893 
894             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
895                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
896                     if (hasFingerprints && hasFace) {
897                         return R.string.unlock_disable_frp_warning_content_pattern_face_fingerprint;
898                     } else if (hasFingerprints) {
899                         return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
900                     } else if (hasFace) {
901                         return R.string.unlock_disable_frp_warning_content_pattern_face;
902                     } else {
903                         return R.string.unlock_disable_frp_warning_content_pattern;
904                     }
905                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
906                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
907                     if (hasFingerprints && hasFace) {
908                         return R.string.unlock_disable_frp_warning_content_pin_face_fingerprint;
909                     } else if (hasFingerprints) {
910                         return R.string.unlock_disable_frp_warning_content_pin_fingerprint;
911                     } else if (hasFace) {
912                         return R.string.unlock_disable_frp_warning_content_pin_face;
913                     } else {
914                         return R.string.unlock_disable_frp_warning_content_pin;
915                     }
916                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
917                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
918                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
919                 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
920                     if (hasFingerprints && hasFace) {
921                         return R.string
922                                 .unlock_disable_frp_warning_content_password_face_fingerprint;
923                     } else if (hasFingerprints) {
924                         return R.string.unlock_disable_frp_warning_content_password_fingerprint;
925                     } else if (hasFace) {
926                         return R.string.unlock_disable_frp_warning_content_password_face;
927                     } else {
928                         return R.string.unlock_disable_frp_warning_content_password;
929                     }
930                 default:
931                     if (hasFingerprints && hasFace) {
932                         return R.string.unlock_disable_frp_warning_content_unknown_face_fingerprint;
933                     } else if (hasFingerprints) {
934                         return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
935                     } else if (hasFace) {
936                         return R.string.unlock_disable_frp_warning_content_unknown_face;
937                     } else {
938                         return R.string.unlock_disable_frp_warning_content_unknown;
939                     }
940             }
941         }
942 
isUnlockMethodSecure(String unlockMethod)943         private boolean isUnlockMethodSecure(String unlockMethod) {
944             return !(ScreenLockType.SWIPE.preferenceKey.equals(unlockMethod) ||
945                     ScreenLockType.NONE.preferenceKey.equals(unlockMethod));
946         }
947 
setUnlockMethod(String unlockMethod)948         private boolean setUnlockMethod(String unlockMethod) {
949             EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
950 
951             ScreenLockType lock = ScreenLockType.fromKey(unlockMethod);
952             if (lock != null) {
953                 switch (lock) {
954                     case NONE:
955                     case SWIPE:
956                     case PATTERN:
957                     case PIN:
958                     case PASSWORD:
959                     case MANAGED:
960                         updateUnlockMethodAndFinish(
961                                 lock.defaultQuality,
962                                 lock == ScreenLockType.NONE,
963                                 false /* chooseLockSkipped */);
964                         return true;
965                 }
966             }
967             Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
968             return false;
969         }
970 
showFactoryResetProtectionWarningDialog(String unlockMethodToSet)971         private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
972             int title = getResIdForFactoryResetProtectionWarningTitle();
973             int message = getResIdForFactoryResetProtectionWarningMessage();
974             FactoryResetProtectionWarningDialog dialog =
975                     FactoryResetProtectionWarningDialog.newInstance(
976                             title, message, unlockMethodToSet);
977             dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
978         }
979 
980         public static class FactoryResetProtectionWarningDialog extends InstrumentedDialogFragment {
981 
982             private static final String ARG_TITLE_RES = "titleRes";
983             private static final String ARG_MESSAGE_RES = "messageRes";
984             private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
985 
newInstance( int titleRes, int messageRes, String unlockMethodToSet)986             public static FactoryResetProtectionWarningDialog newInstance(
987                     int titleRes, int messageRes, String unlockMethodToSet) {
988                 FactoryResetProtectionWarningDialog frag =
989                         new FactoryResetProtectionWarningDialog();
990                 Bundle args = new Bundle();
991                 args.putInt(ARG_TITLE_RES, titleRes);
992                 args.putInt(ARG_MESSAGE_RES, messageRes);
993                 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
994                 frag.setArguments(args);
995                 return frag;
996             }
997 
998             @Override
show(FragmentManager manager, String tag)999             public void show(FragmentManager manager, String tag) {
1000                 if (manager.findFragmentByTag(tag) == null) {
1001                     // Prevent opening multiple dialogs if tapped on button quickly
1002                     super.show(manager, tag);
1003                 }
1004             }
1005 
1006             @Override
onCreateDialog(Bundle savedInstanceState)1007             public Dialog onCreateDialog(Bundle savedInstanceState) {
1008                 final Bundle args = getArguments();
1009 
1010                 return new AlertDialog.Builder(getActivity())
1011                         .setTitle(args.getInt(ARG_TITLE_RES))
1012                         .setMessage(args.getInt(ARG_MESSAGE_RES))
1013                         .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
1014                                 (dialog, whichButton) -> {
1015                                     String unlockMethod = args.getString(ARG_UNLOCK_METHOD_TO_SET);
1016                                     ((ChooseLockGenericFragment) getParentFragment())
1017                                             .setUnlockMethod(unlockMethod);
1018                                 })
1019                         .setNegativeButton(R.string.cancel, (dialog, whichButton) -> dismiss())
1020                         .create();
1021             }
1022 
1023             @Override
getMetricsCategory()1024             public int getMetricsCategory() {
1025                 return SettingsEnums.DIALOG_FRP;
1026             }
1027         }
1028     }
1029 }
1030