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