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