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 
26 import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
27 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
28 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
29 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
30 
31 import android.accessibilityservice.AccessibilityServiceInfo;
32 import android.app.Activity;
33 import android.app.Dialog;
34 import android.app.admin.DevicePolicyManager;
35 import android.app.admin.DevicePolicyManager.PasswordComplexity;
36 import android.app.settings.SettingsEnums;
37 import android.content.Context;
38 import android.content.Intent;
39 import android.content.pm.UserInfo;
40 import android.hardware.face.Face;
41 import android.hardware.face.FaceManager;
42 import android.hardware.fingerprint.Fingerprint;
43 import android.hardware.fingerprint.FingerprintManager;
44 import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
45 import android.os.Bundle;
46 import android.os.UserHandle;
47 import android.os.UserManager;
48 import android.os.storage.StorageManager;
49 import android.text.TextUtils;
50 import android.util.EventLog;
51 import android.util.Log;
52 import android.view.accessibility.AccessibilityManager;
53 import android.widget.TextView;
54 
55 import androidx.annotation.StringRes;
56 import androidx.annotation.VisibleForTesting;
57 import androidx.appcompat.app.AlertDialog;
58 import androidx.fragment.app.Fragment;
59 import androidx.fragment.app.FragmentManager;
60 import androidx.preference.Preference;
61 import androidx.preference.PreferenceScreen;
62 
63 import com.android.internal.widget.LockPatternUtils;
64 import com.android.settings.EncryptionInterstitial;
65 import com.android.settings.EventLogTags;
66 import com.android.settings.R;
67 import com.android.settings.SettingsActivity;
68 import com.android.settings.SettingsPreferenceFragment;
69 import com.android.settings.Utils;
70 import com.android.settings.biometrics.BiometricEnrollActivity;
71 import com.android.settings.biometrics.BiometricEnrollBase;
72 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
73 import com.android.settings.search.SearchFeatureProvider;
74 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
75 import com.android.settingslib.RestrictedLockUtilsInternal;
76 import com.android.settingslib.RestrictedPreference;
77 import com.android.settingslib.widget.FooterPreference;
78 import com.android.settingslib.widget.FooterPreferenceMixinCompat;
79 
80 import java.util.List;
81 
82 public class ChooseLockGeneric extends SettingsActivity {
83     public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
84 
85     @Override
getIntent()86     public Intent getIntent() {
87         Intent modIntent = new Intent(super.getIntent());
88         modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
89         return modIntent;
90     }
91 
92     @Override
isValidFragment(String fragmentName)93     protected boolean isValidFragment(String fragmentName) {
94         if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
95         return false;
96     }
97 
getFragmentClass()98     /* package */ Class<? extends Fragment> getFragmentClass() {
99         return ChooseLockGenericFragment.class;
100     }
101 
102     public static class InternalActivity extends ChooseLockGeneric {
103     }
104 
105     public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
106 
107         private static final String TAG = "ChooseLockGenericFragment";
108         private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint";
109         private static final String KEY_SKIP_FACE = "unlock_skip_face";
110         private static final String PASSWORD_CONFIRMED = "password_confirmed";
111         private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
112         public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
113         public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
114         public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
115 
116         /**
117          * Boolean extra determining whether a "screen lock options" button should be shown. This
118          * extra is both sent and received by ChooseLockGeneric.
119          *
120          * When this extra is false, nothing will be done.
121          * When ChooseLockGeneric receives this extra set as true, and if ChooseLockGeneric is
122          * starting ChooseLockPassword or ChooseLockPattern automatically without user interaction,
123          * ChooseLockGeneric will set this extra to true when starting ChooseLockPassword/Pattern.
124          *
125          * This gives the user the choice to select a different screen lock type, even if
126          * ChooseLockGeneric selected a default.
127          */
128         public static final String EXTRA_SHOW_OPTIONS_BUTTON = "show_options_button";
129 
130         /**
131          * Original intent extras used to start this activity. This is passed to ChooseLockPassword
132          * when the "screen lock options" button is shown, so that when that button is clicked,
133          * ChooseLockGeneric can be relaunched with the same extras.
134          */
135         public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras";
136 
137         @VisibleForTesting
138         static final int CONFIRM_EXISTING_REQUEST = 100;
139         @VisibleForTesting
140         static final int ENABLE_ENCRYPTION_REQUEST = 101;
141         @VisibleForTesting
142         static final int CHOOSE_LOCK_REQUEST = 102;
143         @VisibleForTesting
144         static final int CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST = 103;
145         @VisibleForTesting
146         static final int SKIP_FINGERPRINT_REQUEST = 104;
147 
148         private ChooseLockSettingsHelper mChooseLockSettingsHelper;
149         private DevicePolicyManager mDPM;
150         private boolean mHasChallenge = false;
151         private long mChallenge;
152         private boolean mPasswordConfirmed = false;
153         private boolean mWaitingForConfirmation = false;
154         private boolean mForChangeCredRequiredForBoot = false;
155         private byte[] mUserPassword;
156         private LockPatternUtils mLockPatternUtils;
157         private FingerprintManager mFingerprintManager;
158         private FaceManager mFaceManager;
159         private int mUserId;
160         private ManagedLockPasswordProvider mManagedPasswordProvider;
161         private boolean mIsSetNewPassword = false;
162         private UserManager mUserManager;
163         private ChooseLockGenericController mController;
164 
165         /**
166          * From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}.
167          */
168         @PasswordComplexity private int mRequestedMinComplexity;
169 
170         /** From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_CALLER_APP_NAME}. */
171         private String mCallerAppName = null;
172 
173         /**
174          * The value from the intent extra {@link
175          * ChooseLockSettingsHelper#EXTRA_KEY_IS_CALLING_APP_ADMIN}.
176          */
177         private boolean mIsCallingAppAdmin;
178 
179         protected boolean mForFingerprint = false;
180         protected boolean mForFace = false;
181 
182         @Override
getMetricsCategory()183         public int getMetricsCategory() {
184             return SettingsEnums.CHOOSE_LOCK_GENERIC;
185         }
186 
187         @Override
onCreate(Bundle savedInstanceState)188         public void onCreate(Bundle savedInstanceState) {
189             super.onCreate(savedInstanceState);
190             final Activity activity = getActivity();
191             if (!Utils.isDeviceProvisioned(activity) && !canRunBeforeDeviceProvisioned()) {
192                 Log.i(TAG, "Refusing to start because device is not provisioned");
193                 activity.finish();
194                 return;
195             }
196 
197             String chooseLockAction = getActivity().getIntent().getAction();
198             mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity());
199             mFaceManager = Utils.getFaceManagerOrNull(getActivity());
200             mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
201             mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
202             mLockPatternUtils = new LockPatternUtils(getActivity());
203             mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
204                     || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction);
205 
206             // Defaults to needing to confirm credentials
207             final boolean confirmCredentials = getActivity().getIntent()
208                 .getBooleanExtra(CONFIRM_CREDENTIALS, true);
209             if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
210                 mPasswordConfirmed = !confirmCredentials;
211                 mUserPassword = getActivity().getIntent().getByteArrayExtra(
212                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
213             }
214 
215             mHasChallenge = getActivity().getIntent().getBooleanExtra(
216                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
217             mChallenge = getActivity().getIntent().getLongExtra(
218                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
219             mForFingerprint = getActivity().getIntent().getBooleanExtra(
220                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
221             mForFace = getActivity().getIntent().getBooleanExtra(
222                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false);
223             mRequestedMinComplexity = getActivity().getIntent()
224                     .getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE);
225             mCallerAppName =
226                     getActivity().getIntent().getStringExtra(EXTRA_KEY_CALLER_APP_NAME);
227             mIsCallingAppAdmin = getActivity().getIntent()
228                     .getBooleanExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, /* defValue= */ false);
229             mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
230                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
231             mUserManager = UserManager.get(getActivity());
232 
233             if (savedInstanceState != null) {
234                 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
235                 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
236                 if (mUserPassword == null) {
237                     mUserPassword = savedInstanceState.getByteArray(
238                             ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
239                 }
240             }
241 
242             // a) If this is started from other user, use that user id.
243             // b) If this is started from the same user, read the extra if this is launched
244             //    from Settings app itself.
245             // c) Otherwise, use UserHandle.myUserId().
246             mUserId = Utils.getSecureTargetUser(
247                     getActivity().getActivityToken(),
248                     UserManager.get(getActivity()),
249                     getArguments(),
250                     getActivity().getIntent().getExtras()).getIdentifier();
251             mController = new ChooseLockGenericController(
252                     getContext(), mUserId, mRequestedMinComplexity, mLockPatternUtils);
253             if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
254                     && UserManager.get(getActivity()).isManagedProfile(mUserId)
255                     && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
256                 getActivity().setTitle(R.string.lock_settings_picker_title_profile);
257             }
258 
259             mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId);
260 
261             if (mPasswordConfirmed) {
262                 updatePreferencesOrFinish(savedInstanceState != null);
263                 if (mForChangeCredRequiredForBoot) {
264                     maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
265                             mUserId), false);
266                 }
267             } else if (!mWaitingForConfirmation) {
268                 ChooseLockSettingsHelper helper =
269                         new ChooseLockSettingsHelper(this.getActivity(), this);
270                 boolean managedProfileWithUnifiedLock =
271                         UserManager.get(getActivity()).isManagedProfile(mUserId)
272                         && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
273                 boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword;
274                 if (skipConfirmation
275                         || !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
276                         getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
277                     mPasswordConfirmed = true; // no password set, so no need to confirm
278                     updatePreferencesOrFinish(savedInstanceState != null);
279                 } else {
280                     mWaitingForConfirmation = true;
281                 }
282             }
283             addHeaderView();
284         }
285 
canRunBeforeDeviceProvisioned()286         protected boolean canRunBeforeDeviceProvisioned() {
287             return false;
288         }
289 
getInternalActivityClass()290         protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
291             return ChooseLockGeneric.InternalActivity.class;
292         }
293 
addHeaderView()294         protected void addHeaderView() {
295             if (mForFingerprint) {
296                 setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
297                 if (mIsSetNewPassword) {
298                     ((TextView) getHeaderView().findViewById(R.id.fingerprint_header_description))
299                             .setText(R.string.fingerprint_unlock_title);
300                 }
301             } else if (mForFace) {
302                 setHeaderView(R.layout.choose_lock_generic_face_header);
303                 if (mIsSetNewPassword) {
304                     ((TextView) getHeaderView().findViewById(R.id.face_header_description))
305                             .setText(R.string.face_unlock_title);
306                 }
307             }
308         }
309 
310         @Override
onPreferenceTreeClick(Preference preference)311         public boolean onPreferenceTreeClick(Preference preference) {
312             final String key = preference.getKey();
313 
314             if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
315                 // Show the disabling FRP warning only when the user is switching from a secure
316                 // unlock method to an insecure one
317                 showFactoryResetProtectionWarningDialog(key);
318                 return true;
319             } else if (KEY_SKIP_FINGERPRINT.equals(key) || KEY_SKIP_FACE.equals(key)) {
320                 Intent chooseLockGenericIntent = new Intent(getActivity(),
321                     getInternalActivityClass());
322                 chooseLockGenericIntent.setAction(getIntent().getAction());
323                 // Forward the target user id to  ChooseLockGeneric.
324                 chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
325                 chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
326                 chooseLockGenericIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
327                         mRequestedMinComplexity);
328                 chooseLockGenericIntent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
329                 if (mUserPassword != null) {
330                     chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
331                             mUserPassword);
332                 }
333                 startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
334                 return true;
335             } else {
336                 return setUnlockMethod(key);
337             }
338         }
339 
340         /**
341          * If the device has encryption already enabled, then ask the user if they
342          * also want to encrypt the phone with this password.
343          *
344          * @param quality
345          * @param disabled
346          */
347         // TODO: why does this take disabled, its always called with a quality higher than
348         // what makes sense with disabled == true
maybeEnableEncryption(int quality, boolean disabled)349         private void maybeEnableEncryption(int quality, boolean disabled) {
350             DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
351             if (UserManager.get(getActivity()).isAdminUser()
352                     && mUserId == UserHandle.myUserId()
353                     && LockPatternUtils.isDeviceEncryptionEnabled()
354                     && !LockPatternUtils.isFileEncryptionEnabled()
355                     && !dpm.getDoNotAskCredentialsOnBoot()) {
356                 // Get the intent that the encryption interstitial should start for creating
357                 // the new unlock method.
358                 Intent unlockMethodIntent = getIntentForUnlockMethod(quality);
359                 unlockMethodIntent.putExtra(
360                         ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
361                         mForChangeCredRequiredForBoot);
362                 final Context context = getActivity();
363                 // If accessibility is enabled and the user hasn't seen this dialog before, set the
364                 // default state to agree with that which is compatible with accessibility
365                 // (password not required).
366                 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
367                 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
368                 Intent intent = getEncryptionInterstitialIntent(context, quality, required,
369                         unlockMethodIntent);
370                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
371                         mForFingerprint);
372                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE,
373                         mForFace);
374                 startActivityForResult(
375                         intent,
376                         mIsSetNewPassword && mHasChallenge
377                                 ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
378                                 : ENABLE_ENCRYPTION_REQUEST);
379             } else {
380                 if (mForChangeCredRequiredForBoot) {
381                     // Welp, couldn't change it. Oh well.
382                     finish();
383                     return;
384                 }
385                 updateUnlockMethodAndFinish(quality, disabled, false /* chooseLockSkipped */);
386             }
387         }
388 
389         @Override
onActivityResult(int requestCode, int resultCode, Intent data)390         public void onActivityResult(int requestCode, int resultCode, Intent data) {
391             super.onActivityResult(requestCode, resultCode, data);
392             mWaitingForConfirmation = false;
393             if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
394                 mPasswordConfirmed = true;
395                 mUserPassword = data != null
396                     ? data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
397                     : null;
398                 updatePreferencesOrFinish(false /* isRecreatingActivity */);
399                 if (mForChangeCredRequiredForBoot) {
400                     if (!(mUserPassword == null || mUserPassword.length == 0)) {
401                         maybeEnableEncryption(
402                                 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
403                     } else {
404                         finish();
405                     }
406                 }
407             } else if (requestCode == CHOOSE_LOCK_REQUEST
408                     || requestCode == ENABLE_ENCRYPTION_REQUEST) {
409                 if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) {
410                     getActivity().setResult(resultCode, data);
411                     finish();
412                 } else {
413                     // If PASSWORD_TYPE_KEY is set, this activity is used as a trampoline to start
414                     // the actual password enrollment. If the result is canceled, which means the
415                     // user pressed back, finish the activity with result canceled.
416                     int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
417                     if (quality != -1) {
418                         getActivity().setResult(RESULT_CANCELED, data);
419                         finish();
420                     }
421                 }
422             } else if (requestCode == CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
423                     && resultCode == BiometricEnrollBase.RESULT_FINISHED) {
424                 Intent intent = getBiometricEnrollIntent(getActivity());
425                 if (data != null) {
426                     intent.putExtras(data.getExtras());
427                 }
428                 // Forward the target user id to fingerprint setup page.
429                 intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
430                 startActivity(intent);
431                 finish();
432             } else if (requestCode == SKIP_FINGERPRINT_REQUEST) {
433                 if (resultCode != RESULT_CANCELED) {
434                     getActivity().setResult(
435                             resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data);
436                     finish();
437                 }
438             } else if (requestCode == SearchFeatureProvider.REQUEST_CODE) {
439                 return;
440             } else {
441                 getActivity().setResult(Activity.RESULT_CANCELED);
442                 finish();
443             }
444             if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
445                 finish();
446             }
447         }
448 
getBiometricEnrollIntent(Context context)449         protected Intent getBiometricEnrollIntent(Context context) {
450             final Intent intent =
451                     new Intent(context, BiometricEnrollActivity.InternalActivity.class);
452             intent.putExtra(BiometricEnrollActivity.EXTRA_SKIP_INTRO, true);
453             return intent;
454         }
455 
456         @Override
onSaveInstanceState(Bundle outState)457         public void onSaveInstanceState(Bundle outState) {
458             super.onSaveInstanceState(outState);
459             // Saved so we don't force user to re-enter their password if configuration changes
460             outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
461             outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
462             if (mUserPassword != null) {
463                 outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
464             }
465         }
466 
467         @VisibleForTesting
updatePreferencesOrFinish(boolean isRecreatingActivity)468         void updatePreferencesOrFinish(boolean isRecreatingActivity) {
469             Intent intent = getActivity().getIntent();
470             int quality = -1;
471             if (StorageManager.isFileEncryptedNativeOrEmulated()) {
472                 quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
473             } else {
474                 // For non-file encrypted devices we need to show encryption interstitial, so always
475                 // show the lock type picker and ignore PASSWORD_TYPE_KEY.
476                 Log.i(TAG, "Ignoring PASSWORD_TYPE_KEY because device is not file encrypted");
477             }
478             if (quality == -1) {
479                 // If caller didn't specify password quality, show UI and allow the user to choose.
480                 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
481                 quality = mController.upgradeQuality(quality);
482                 final boolean hideDisabledPrefs = intent.getBooleanExtra(
483                         HIDE_DISABLED_PREFS, false);
484                 final PreferenceScreen prefScreen = getPreferenceScreen();
485                 if (prefScreen != null) {
486                     prefScreen.removeAll();
487                 }
488                 addPreferences();
489                 disableUnusablePreferences(quality, hideDisabledPrefs);
490                 updatePreferenceText();
491                 updateCurrentPreference();
492                 updatePreferenceSummaryIfNeeded();
493             } else if (!isRecreatingActivity) {
494                 // Don't start the activity again if we are recreated for configuration change
495                 updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */);
496             }
497         }
498 
addPreferences()499         protected void addPreferences() {
500             addPreferencesFromResource(R.xml.security_settings_picker);
501 
502             if (!TextUtils.isEmpty(mCallerAppName) && !mIsCallingAppAdmin) {
503                 FooterPreferenceMixinCompat footerMixin =
504                         new FooterPreferenceMixinCompat(this, getSettingsLifecycle());
505                 FooterPreference footer = footerMixin.createFooterPreference();
506                 footer.setTitle(getFooterString());
507             }
508 
509             // Used for testing purposes
510             findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
511             findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
512             findPreference(KEY_SKIP_FACE).setViewId(R.id.lock_none);
513             findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin);
514             findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
515         }
516 
getFooterString()517         private String getFooterString() {
518             @StringRes int stringId;
519             switch (mRequestedMinComplexity) {
520                 case PASSWORD_COMPLEXITY_HIGH:
521                     stringId = R.string.unlock_footer_high_complexity_requested;
522                     break;
523                 case PASSWORD_COMPLEXITY_MEDIUM:
524                     stringId = R.string.unlock_footer_medium_complexity_requested;
525                     break;
526                 case PASSWORD_COMPLEXITY_LOW:
527                     stringId = R.string.unlock_footer_low_complexity_requested;
528                     break;
529                 case PASSWORD_COMPLEXITY_NONE:
530                 default:
531                     stringId = R.string.unlock_footer_none_complexity_requested;
532                     break;
533             }
534 
535             return getResources().getString(stringId, mCallerAppName);
536         }
537 
updatePreferenceText()538         private void updatePreferenceText() {
539             if (mForFingerprint) {
540                 setPreferenceTitle(ScreenLockType.PATTERN,
541                         R.string.fingerprint_unlock_set_unlock_pattern);
542                 setPreferenceTitle(ScreenLockType.PIN, R.string.fingerprint_unlock_set_unlock_pin);
543                 setPreferenceTitle(ScreenLockType.PASSWORD,
544                         R.string.fingerprint_unlock_set_unlock_password);
545             } else if (mForFace) {
546                 setPreferenceTitle(ScreenLockType.PATTERN,
547                         R.string.face_unlock_set_unlock_pattern);
548                 setPreferenceTitle(ScreenLockType.PIN, R.string.face_unlock_set_unlock_pin);
549                 setPreferenceTitle(ScreenLockType.PASSWORD,
550                         R.string.face_unlock_set_unlock_password);
551             }
552 
553             if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
554                 setPreferenceTitle(ScreenLockType.MANAGED,
555                         mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
556             } else {
557                 removePreference(ScreenLockType.MANAGED.preferenceKey);
558             }
559 
560             if (!(mForFingerprint && mIsSetNewPassword)) {
561                 removePreference(KEY_SKIP_FINGERPRINT);
562             }
563             if (!(mForFace && mIsSetNewPassword)) {
564                 removePreference(KEY_SKIP_FACE);
565             }
566         }
567 
setPreferenceTitle(ScreenLockType lock, @StringRes int title)568         private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
569             Preference preference = findPreference(lock.preferenceKey);
570             if (preference != null) {
571                 preference.setTitle(title);
572             }
573         }
574 
setPreferenceTitle(ScreenLockType lock, CharSequence title)575         private void setPreferenceTitle(ScreenLockType lock, CharSequence title) {
576             Preference preference = findPreference(lock.preferenceKey);
577             if (preference != null) {
578                 preference.setTitle(title);
579             }
580         }
581 
setPreferenceSummary(ScreenLockType lock, @StringRes int summary)582         private void setPreferenceSummary(ScreenLockType lock, @StringRes int summary) {
583             Preference preference = findPreference(lock.preferenceKey);
584             if (preference != null) {
585                 preference.setSummary(summary);
586             }
587         }
588 
updateCurrentPreference()589         private void updateCurrentPreference() {
590             String currentKey = getKeyForCurrent();
591             Preference preference = findPreference(currentKey);
592             if (preference != null) {
593                 preference.setSummary(R.string.current_screen_lock);
594             }
595         }
596 
getKeyForCurrent()597         private String getKeyForCurrent() {
598             final int credentialOwner = UserManager.get(getContext())
599                     .getCredentialOwnerProfile(mUserId);
600             if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
601                 return ScreenLockType.NONE.preferenceKey;
602             }
603             ScreenLockType lock =
604                     ScreenLockType.fromQuality(
605                             mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner));
606             return lock != null ? lock.preferenceKey : null;
607         }
608 
609         /***
610          * Disables preferences that are less secure than required quality. The actual
611          * implementation is in disableUnusablePreferenceImpl.
612          *
613          * @param quality the requested quality.
614          * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
615          * they're not shown at all.
616          */
disableUnusablePreferences(final int quality, boolean hideDisabledPrefs)617         protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
618             disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
619         }
620 
621         /***
622          * Disables preferences that are less secure than required quality.
623          *
624          * @param quality the requested quality.
625          * @param hideDisabled whether to hide disable screen lock options.
626          */
disableUnusablePreferencesImpl(final int quality, boolean hideDisabled)627         protected void disableUnusablePreferencesImpl(final int quality,
628                 boolean hideDisabled) {
629             final PreferenceScreen entries = getPreferenceScreen();
630 
631             int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId);
632             EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet(
633                     getActivity(), mUserId);
634 
635             for (ScreenLockType lock : ScreenLockType.values()) {
636                 String key = lock.preferenceKey;
637                 Preference pref = findPreference(key);
638                 if (pref instanceof RestrictedPreference) {
639                     boolean visible = mController.isScreenLockVisible(lock);
640                     boolean enabled = mController.isScreenLockEnabled(lock, quality);
641                     boolean disabledByAdmin =
642                             mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality);
643                     if (hideDisabled) {
644                         visible = visible && enabled;
645                     }
646                     if (!visible) {
647                         entries.removePreference(pref);
648                     } else if (disabledByAdmin && enforcedAdmin != null) {
649                         ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
650                     } else if (!enabled) {
651                         // we need to setDisabledByAdmin to null first to disable the padlock
652                         // in case it was set earlier.
653                         ((RestrictedPreference) pref).setDisabledByAdmin(null);
654                         pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
655                         pref.setEnabled(false);
656                     } else {
657                         ((RestrictedPreference) pref).setDisabledByAdmin(null);
658                     }
659                 }
660             }
661         }
662 
updatePreferenceSummaryIfNeeded()663         private void updatePreferenceSummaryIfNeeded() {
664             // On a default block encrypted device with accessibility, add a warning
665             // that your data is not credential encrypted
666             if (!StorageManager.isBlockEncrypted()) {
667                 return;
668             }
669 
670             if (StorageManager.isNonDefaultBlockEncrypted()) {
671                 return;
672             }
673 
674             if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
675                     AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
676                 return;
677             }
678 
679             setPreferenceSummary(ScreenLockType.PATTERN, R.string.secure_lock_encryption_warning);
680             setPreferenceSummary(ScreenLockType.PIN, R.string.secure_lock_encryption_warning);
681             setPreferenceSummary(ScreenLockType.PASSWORD, R.string.secure_lock_encryption_warning);
682             setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning);
683         }
684 
getLockManagedPasswordIntent(byte[] password)685         protected Intent getLockManagedPasswordIntent(byte[] password) {
686             return mManagedPasswordProvider.createIntent(false, password);
687         }
688 
getLockPasswordIntent(int quality)689         protected Intent getLockPasswordIntent(int quality) {
690             ChooseLockPassword.IntentBuilder builder =
691                     new ChooseLockPassword.IntentBuilder(getContext())
692                             .setPasswordQuality(quality)
693                             .setRequestedMinComplexity(mRequestedMinComplexity)
694                             .setForFingerprint(mForFingerprint)
695                             .setForFace(mForFace)
696                             .setUserId(mUserId);
697             if (mHasChallenge) {
698                 builder.setChallenge(mChallenge);
699             }
700             if (mUserPassword != null) {
701                 builder.setPassword(mUserPassword);
702             }
703             return builder.build();
704         }
705 
getLockPatternIntent()706         protected Intent getLockPatternIntent() {
707             ChooseLockPattern.IntentBuilder builder =
708                     new ChooseLockPattern.IntentBuilder(getContext())
709                             .setForFingerprint(mForFingerprint)
710                             .setForFace(mForFace)
711                             .setUserId(mUserId);
712             if (mHasChallenge) {
713                 builder.setChallenge(mChallenge);
714             }
715             if (mUserPassword != null) {
716                 builder.setPattern(mUserPassword);
717             }
718             return builder.build();
719         }
720 
getEncryptionInterstitialIntent(Context context, int quality, boolean required, Intent unlockMethodIntent)721         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
722                 boolean required, Intent unlockMethodIntent) {
723             return EncryptionInterstitial.createStartIntent(context, quality, required,
724                     unlockMethodIntent);
725         }
726 
727         /**
728          * Keeps track of the biometric removal status. When all biometrics (including managed
729          * profiles) are removed, finishes the activity. Otherwise, it's possible the UI still
730          * shows enrolled biometrics due to the async remove.
731          */
732         private class RemovalTracker {
733             boolean mFingerprintDone;
734             boolean mFaceDone;
735 
onFingerprintDone()736             void onFingerprintDone() {
737                 mFingerprintDone = true;
738                 if (mFingerprintDone && mFaceDone) {
739                     finish();
740                 }
741             }
742 
onFaceDone()743             void onFaceDone() {
744                 mFaceDone = true;
745                 if (mFingerprintDone && mFaceDone) {
746                     finish();
747                 }
748             }
749         }
750 
751         /**
752          * Invokes an activity to change the user's pattern, password or PIN based on given quality
753          * and minimum quality specified by DevicePolicyManager. If quality is
754          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
755          *
756          * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
757          * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
758          * @param chooseLockSkipped whether or not this activity is skipped. This is true when this
759          * activity was not shown to the user at all, instead automatically proceeding based on
760          * the given intent extras, typically {@link LockPatternUtils#PASSWORD_TYPE_KEY}.
761          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
762          */
updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped)763         void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) {
764             // We should never get here without confirming user's existing password.
765             if (!mPasswordConfirmed) {
766                 throw new IllegalStateException("Tried to update password without confirming it");
767             }
768 
769             quality = mController.upgradeQuality(quality);
770             Intent intent = getIntentForUnlockMethod(quality);
771             if (intent != null) {
772                 if (getIntent().getBooleanExtra(EXTRA_SHOW_OPTIONS_BUTTON, false)) {
773                     intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped);
774                 }
775                 intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras());
776                 startActivityForResult(intent,
777                         mIsSetNewPassword && mHasChallenge
778                                 ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
779                                 : CHOOSE_LOCK_REQUEST);
780                 return;
781             }
782 
783             if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
784                 mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId);
785                 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
786                 getActivity().setResult(Activity.RESULT_OK);
787                 removeAllBiometricsForUserAndFinish(mUserId);
788             } else {
789                 removeAllBiometricsForUserAndFinish(mUserId);
790             }
791         }
792 
removeAllBiometricsForUserAndFinish(final int userId)793         private void removeAllBiometricsForUserAndFinish(final int userId) {
794             final RemovalTracker tracker = new RemovalTracker();
795             removeAllFingerprintForUserAndFinish(userId, tracker);
796             removeAllFaceForUserAndFinish(userId, tracker);
797         }
798 
getIntentForUnlockMethod(int quality)799         private Intent getIntentForUnlockMethod(int quality) {
800             Intent intent = null;
801             if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
802                 intent = getLockManagedPasswordIntent(mUserPassword);
803             } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
804                 intent = getLockPasswordIntent(quality);
805             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
806                 intent = getLockPatternIntent();
807             }
808             return intent;
809         }
810 
removeAllFingerprintForUserAndFinish(final int userId, RemovalTracker tracker)811         private void removeAllFingerprintForUserAndFinish(final int userId,
812                 RemovalTracker tracker) {
813             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
814                 if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
815                     mFingerprintManager.setActiveUser(userId);
816                     // For the purposes of M and N, groupId is the same as userId.
817                     final int groupId = userId;
818                     Fingerprint finger = new Fingerprint(null, groupId, 0, 0);
819                     mFingerprintManager.remove(finger, userId,
820                             new RemovalCallback() {
821                                 @Override
822                                 public void onRemovalError(Fingerprint fp, int errMsgId,
823                                         CharSequence errString) {
824                                     Log.e(TAG, String.format(
825                                             "Can't remove fingerprint %d in group %d. Reason: %s",
826                                             fp.getBiometricId(), fp.getGroupId(), errString));
827                                     // TODO: need to proceed with the removal of managed profile
828                                     // fingerprints and finish() gracefully.
829                                 }
830 
831                                 @Override
832                                 public void onRemovalSucceeded(Fingerprint fp, int remaining) {
833                                     if (remaining == 0) {
834                                         removeManagedProfileFingerprintsAndFinishIfNecessary(userId,
835                                                 tracker);
836                                     }
837                                 }
838                             });
839                 } else {
840                     // No fingerprints in this user, we may also want to delete managed profile
841                     // fingerprints
842                     removeManagedProfileFingerprintsAndFinishIfNecessary(userId, tracker);
843                 }
844             } else {
845                 // The removal callback will call finish, once all fingerprints are removed.
846                 // We need to wait for that to occur, otherwise, the UI will still show that
847                 // fingerprints exist even though they are (about to) be removed depending on
848                 // the race condition.
849                 tracker.onFingerprintDone();
850             }
851         }
852 
removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId, RemovalTracker tracker)853         private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId,
854                 RemovalTracker tracker) {
855             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
856                 mFingerprintManager.setActiveUser(UserHandle.myUserId());
857             }
858             boolean hasChildProfile = false;
859             if (!mUserManager.getUserInfo(parentUserId).isManagedProfile()) {
860                 // Current user is primary profile, remove work profile fingerprints if necessary
861                 final List<UserInfo> profiles = mUserManager.getProfiles(parentUserId);
862                 final int profilesSize = profiles.size();
863                 for (int i = 0; i < profilesSize; i++) {
864                     final UserInfo userInfo = profiles.get(i);
865                     if (userInfo.isManagedProfile() && !mLockPatternUtils
866                             .isSeparateProfileChallengeEnabled(userInfo.id)) {
867                         removeAllFingerprintForUserAndFinish(userInfo.id, tracker);
868                         hasChildProfile = true;
869                         break;
870                     }
871                 }
872             }
873             if (!hasChildProfile) {
874                 tracker.onFingerprintDone();
875             }
876         }
877 
878         // TODO: figure out how to eliminate duplicated code. It's a bit hard due to the async-ness
removeAllFaceForUserAndFinish(final int userId, RemovalTracker tracker)879         private void removeAllFaceForUserAndFinish(final int userId, RemovalTracker tracker) {
880             if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
881                 if (mFaceManager.hasEnrolledTemplates(userId)) {
882                     mFaceManager.setActiveUser(userId);
883                     Face face = new Face(null, 0, 0);
884                     mFaceManager.remove(face, userId,
885                             new FaceManager.RemovalCallback() {
886                         @Override
887                         public void onRemovalError(Face face, int errMsgId, CharSequence err) {
888                             Log.e(TAG, String.format("Can't remove face %d. Reason: %s",
889                                     face.getBiometricId(), err));
890                         }
891                         @Override
892                         public void onRemovalSucceeded(Face face, int remaining) {
893                             if (remaining == 0) {
894                                 removeManagedProfileFacesAndFinishIfNecessary(userId, tracker);
895                             }
896                         }
897                     });
898                 } else {
899                     // No faces in this user, we may also want to delete managed profile faces
900                     removeManagedProfileFacesAndFinishIfNecessary(userId, tracker);
901                 }
902             } else {
903                 tracker.onFaceDone();
904             }
905         }
906 
907         // TODO: figure out how to eliminate duplicated code. It's a bit hard due to the async-ness
removeManagedProfileFacesAndFinishIfNecessary(final int parentUserId, RemovalTracker tracker)908         private void removeManagedProfileFacesAndFinishIfNecessary(final int parentUserId,
909                 RemovalTracker tracker) {
910             if (mFaceManager != null && mFaceManager.isHardwareDetected()) {
911                 mFaceManager.setActiveUser(UserHandle.myUserId());
912             }
913             boolean hasChildProfile = false;
914             if (!mUserManager.getUserInfo(parentUserId).isManagedProfile()) {
915                 // Current user is primary profile, remove work profile faces if necessary
916                 final List<UserInfo> profiles = mUserManager.getProfiles(parentUserId);
917                 final int profilesSize = profiles.size();
918                 for (int i = 0; i < profilesSize; i++) {
919                     final UserInfo userInfo = profiles.get(i);
920                     if (userInfo.isManagedProfile() && !mLockPatternUtils
921                             .isSeparateProfileChallengeEnabled(userInfo.id)) {
922                         removeAllFaceForUserAndFinish(userInfo.id, tracker);
923                         hasChildProfile = true;
924                         break;
925                     }
926                 }
927             }
928             if (!hasChildProfile) {
929                 tracker.onFaceDone();
930             }
931         }
932 
933         @Override
onDestroy()934         public void onDestroy() {
935             super.onDestroy();
936         }
937 
938         @Override
getHelpResource()939         public int getHelpResource() {
940             return R.string.help_url_choose_lockscreen;
941         }
942 
getResIdForFactoryResetProtectionWarningTitle()943         private int getResIdForFactoryResetProtectionWarningTitle() {
944             boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
945             return isProfile ? R.string.unlock_disable_frp_warning_title_profile
946                     : R.string.unlock_disable_frp_warning_title;
947         }
948 
getResIdForFactoryResetProtectionWarningMessage()949         private int getResIdForFactoryResetProtectionWarningMessage() {
950             final boolean hasFingerprints;
951             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
952                 hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(mUserId);
953             } else {
954                 hasFingerprints = false;
955             }
956             boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
957             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
958                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
959                     if (hasFingerprints && isProfile) {
960                         return R.string
961                                 .unlock_disable_frp_warning_content_pattern_fingerprint_profile;
962                     } else if (hasFingerprints && !isProfile) {
963                         return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
964                     } else if (isProfile) {
965                         return R.string.unlock_disable_frp_warning_content_pattern_profile;
966                     } else {
967                         return R.string.unlock_disable_frp_warning_content_pattern;
968                     }
969                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
970                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
971                     if (hasFingerprints && isProfile) {
972                         return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile;
973                     } else if (hasFingerprints && !isProfile) {
974                         return R.string.unlock_disable_frp_warning_content_pin_fingerprint;
975                     } else if (isProfile) {
976                         return R.string.unlock_disable_frp_warning_content_pin_profile;
977                     } else {
978                         return R.string.unlock_disable_frp_warning_content_pin;
979                     }
980                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
981                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
982                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
983                 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
984                     if (hasFingerprints && isProfile) {
985                         return R.string
986                                 .unlock_disable_frp_warning_content_password_fingerprint_profile;
987                     } else if (hasFingerprints && !isProfile) {
988                         return R.string.unlock_disable_frp_warning_content_password_fingerprint;
989                     } else if (isProfile) {
990                         return R.string.unlock_disable_frp_warning_content_password_profile;
991                     } else {
992                         return R.string.unlock_disable_frp_warning_content_password;
993                     }
994                 default:
995                     if (hasFingerprints && isProfile) {
996                         return R.string
997                                 .unlock_disable_frp_warning_content_unknown_fingerprint_profile;
998                     } else if (hasFingerprints && !isProfile) {
999                         return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
1000                     } else if (isProfile) {
1001                         return R.string.unlock_disable_frp_warning_content_unknown_profile;
1002                     } else {
1003                         return R.string.unlock_disable_frp_warning_content_unknown;
1004                     }
1005             }
1006         }
1007 
isUnlockMethodSecure(String unlockMethod)1008         private boolean isUnlockMethodSecure(String unlockMethod) {
1009             return !(ScreenLockType.SWIPE.preferenceKey.equals(unlockMethod) ||
1010                     ScreenLockType.NONE.preferenceKey.equals(unlockMethod));
1011         }
1012 
setUnlockMethod(String unlockMethod)1013         private boolean setUnlockMethod(String unlockMethod) {
1014             EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
1015 
1016             ScreenLockType lock = ScreenLockType.fromKey(unlockMethod);
1017             if (lock != null) {
1018                 switch (lock) {
1019                     case NONE:
1020                     case SWIPE:
1021                         updateUnlockMethodAndFinish(
1022                                 lock.defaultQuality,
1023                                 lock == ScreenLockType.NONE,
1024                                 false /* chooseLockSkipped */);
1025                         return true;
1026                     case PATTERN:
1027                     case PIN:
1028                     case PASSWORD:
1029                     case MANAGED:
1030                         maybeEnableEncryption(lock.defaultQuality, false);
1031                         return true;
1032                 }
1033             }
1034             Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
1035             return false;
1036         }
1037 
showFactoryResetProtectionWarningDialog(String unlockMethodToSet)1038         private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
1039             int title = getResIdForFactoryResetProtectionWarningTitle();
1040             int message = getResIdForFactoryResetProtectionWarningMessage();
1041             FactoryResetProtectionWarningDialog dialog =
1042                     FactoryResetProtectionWarningDialog.newInstance(
1043                             title, message, unlockMethodToSet);
1044             dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
1045         }
1046 
1047         public static class FactoryResetProtectionWarningDialog extends InstrumentedDialogFragment {
1048 
1049             private static final String ARG_TITLE_RES = "titleRes";
1050             private static final String ARG_MESSAGE_RES = "messageRes";
1051             private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
1052 
newInstance( int titleRes, int messageRes, String unlockMethodToSet)1053             public static FactoryResetProtectionWarningDialog newInstance(
1054                     int titleRes, int messageRes, String unlockMethodToSet) {
1055                 FactoryResetProtectionWarningDialog frag =
1056                         new FactoryResetProtectionWarningDialog();
1057                 Bundle args = new Bundle();
1058                 args.putInt(ARG_TITLE_RES, titleRes);
1059                 args.putInt(ARG_MESSAGE_RES, messageRes);
1060                 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
1061                 frag.setArguments(args);
1062                 return frag;
1063             }
1064 
1065             @Override
show(FragmentManager manager, String tag)1066             public void show(FragmentManager manager, String tag) {
1067                 if (manager.findFragmentByTag(tag) == null) {
1068                     // Prevent opening multiple dialogs if tapped on button quickly
1069                     super.show(manager, tag);
1070                 }
1071             }
1072 
1073             @Override
onCreateDialog(Bundle savedInstanceState)1074             public Dialog onCreateDialog(Bundle savedInstanceState) {
1075                 final Bundle args = getArguments();
1076 
1077                 return new AlertDialog.Builder(getActivity())
1078                         .setTitle(args.getInt(ARG_TITLE_RES))
1079                         .setMessage(args.getInt(ARG_MESSAGE_RES))
1080                         .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
1081                                 (dialog, whichButton) -> {
1082                                     String unlockMethod = args.getString(ARG_UNLOCK_METHOD_TO_SET);
1083                                     ((ChooseLockGenericFragment) getParentFragment())
1084                                             .setUnlockMethod(unlockMethod);
1085                                 })
1086                         .setNegativeButton(R.string.cancel, (dialog, whichButton) -> dismiss())
1087                         .create();
1088             }
1089 
1090             @Override
getMetricsCategory()1091             public int getMetricsCategory() {
1092                 return SettingsEnums.DIALOG_FRP;
1093             }
1094         }
1095     }
1096 }
1097