2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.password;
19 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
20 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
22 import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
24 import android.accessibilityservice.AccessibilityServiceInfo;
25 import android.app.Activity;
26 import android.app.AlertDialog;
27 import android.app.Dialog;
28 import android.app.Fragment;
29 import android.app.FragmentManager;
30 import android.app.admin.DevicePolicyManager;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.pm.UserInfo;
34 import android.hardware.fingerprint.Fingerprint;
35 import android.hardware.fingerprint.FingerprintManager;
36 import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
37 import android.os.Bundle;
38 import android.os.UserHandle;
39 import android.os.UserManager;
40 import android.os.storage.StorageManager;
41 import android.security.KeyStore;
42 import android.support.annotation.StringRes;
43 import android.support.v7.preference.Preference;
44 import android.support.v7.preference.PreferenceScreen;
45 import android.text.TextUtils;
46 import android.util.EventLog;
47 import android.util.Log;
48 import android.view.accessibility.AccessibilityManager;
49 import android.widget.TextView;
51 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
52 import com.android.internal.widget.LockPatternUtils;
53 import com.android.settings.EncryptionInterstitial;
54 import com.android.settings.EventLogTags;
55 import com.android.settings.R;
56 import com.android.settings.SettingsActivity;
57 import com.android.settings.SettingsPreferenceFragment;
58 import com.android.settings.Utils;
59 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
60 import com.android.settings.fingerprint.FingerprintEnrollBase;
61 import com.android.settings.fingerprint.FingerprintEnrollFindSensor;
62 import com.android.settingslib.RestrictedLockUtils;
63 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
64 import com.android.settingslib.RestrictedPreference;
66 import java.util.List;
68 public class ChooseLockGeneric extends SettingsActivity {
69 public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
72 public Intent getIntent() {
73 Intent modIntent = new Intent(super.getIntent());
74 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
76 String action = modIntent.getAction();
77 if (ACTION_SET_NEW_PASSWORD.equals(action)
78 || ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(action)) {
79 modIntent.putExtra(EXTRA_HIDE_DRAWER, true);
85 protected boolean isValidFragment(String fragmentName) {
86 if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
90 /* package */ Class<? extends Fragment> getFragmentClass() {
91 return ChooseLockGenericFragment.class;
94 public static class InternalActivity extends ChooseLockGeneric {
97 public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
99 private static final String TAG = "ChooseLockGenericFragment";
100 private static final int MIN_PASSWORD_LENGTH = 4;
101 private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint";
102 private static final String PASSWORD_CONFIRMED = "password_confirmed";
103 private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
104 public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
105 public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
106 public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality";
107 public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled";
108 public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
111 * Boolean extra determining whether a "screen lock options" button should be shown. This
112 * extra is both sent and received by ChooseLockGeneric.
114 * When this extra is false, nothing will be done.
115 * When ChooseLockGeneric receives this extra set as true, and if ChooseLockGeneric is
116 * starting ChooseLockPassword or ChooseLockPattern automatically without user interaction,
117 * ChooseLockGeneric will set this extra to true when starting ChooseLockPassword/Pattern.
119 * This gives the user the choice to select a different screen lock type, even if
120 * ChooseLockGeneric selected a default.
122 public static final String EXTRA_SHOW_OPTIONS_BUTTON = "show_options_button";
125 * Original intent extras used to start this activity. This is passed to ChooseLockPassword
126 * when the "screen lock options" button is shown, so that when that button is clicked,
127 * ChooseLockGeneric can be relaunched with the same extras.
129 public static final String EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS = "choose_lock_generic_extras";
131 private static final int CONFIRM_EXISTING_REQUEST = 100;
132 private static final int ENABLE_ENCRYPTION_REQUEST = 101;
133 private static final int CHOOSE_LOCK_REQUEST = 102;
134 private static final int CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST = 103;
135 private static final int SKIP_FINGERPRINT_REQUEST = 104;
137 private ChooseLockSettingsHelper mChooseLockSettingsHelper;
138 private DevicePolicyManager mDPM;
139 private KeyStore mKeyStore;
140 private boolean mHasChallenge = false;
141 private long mChallenge;
142 private boolean mPasswordConfirmed = false;
143 private boolean mWaitingForConfirmation = false;
144 private int mEncryptionRequestQuality;
145 private boolean mEncryptionRequestDisabled;
146 private boolean mForChangeCredRequiredForBoot = false;
147 private String mUserPassword;
148 private LockPatternUtils mLockPatternUtils;
149 private FingerprintManager mFingerprintManager;
151 private boolean mHideDrawer = false;
152 private ManagedLockPasswordProvider mManagedPasswordProvider;
153 private boolean mIsSetNewPassword = false;
154 private UserManager mUserManager;
155 private ChooseLockGenericController mController;
157 protected boolean mForFingerprint = false;
160 public int getMetricsCategory() {
161 return MetricsEvent.CHOOSE_LOCK_GENERIC;
165 public void onCreate(Bundle savedInstanceState) {
166 super.onCreate(savedInstanceState);
168 String chooseLockAction = getActivity().getIntent().getAction();
169 mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity());
170 mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
171 mKeyStore = KeyStore.getInstance();
172 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
173 mLockPatternUtils = new LockPatternUtils(getActivity());
174 mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
175 || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction);
177 // Defaults to needing to confirm credentials
178 final boolean confirmCredentials = getActivity().getIntent()
179 .getBooleanExtra(CONFIRM_CREDENTIALS, true);
180 if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
181 mPasswordConfirmed = !confirmCredentials;
182 mUserPassword = getActivity().getIntent().getStringExtra(
183 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
185 mHideDrawer = getActivity().getIntent().getBooleanExtra(EXTRA_HIDE_DRAWER, false);
187 mHasChallenge = getActivity().getIntent().getBooleanExtra(
188 ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
189 mChallenge = getActivity().getIntent().getLongExtra(
190 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
191 mForFingerprint = getActivity().getIntent().getBooleanExtra(
192 ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
193 mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
194 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
195 mUserManager = UserManager.get(getActivity());
197 if (savedInstanceState != null) {
198 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
199 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
200 mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY);
201 mEncryptionRequestDisabled = savedInstanceState.getBoolean(
202 ENCRYPT_REQUESTED_DISABLED);
203 if (mUserPassword == null) {
204 mUserPassword = savedInstanceState.getString(
205 ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
209 // a) If this is started from other user, use that user id.
210 // b) If this is started from the same user, read the extra if this is launched
211 // from Settings app itself.
212 // c) Otherwise, use UserHandle.myUserId().
213 mUserId = Utils.getSecureTargetUser(
214 getActivity().getActivityToken(),
215 UserManager.get(getActivity()),
217 getActivity().getIntent().getExtras()).getIdentifier();
218 mController = new ChooseLockGenericController(getContext(), mUserId);
219 if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
220 && UserManager.get(getActivity()).isManagedProfile(mUserId)
221 && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
222 getActivity().setTitle(R.string.lock_settings_picker_title_profile);
225 mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId);
227 if (mPasswordConfirmed) {
228 updatePreferencesOrFinish(savedInstanceState != null);
229 if (mForChangeCredRequiredForBoot) {
230 maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
233 } else if (!mWaitingForConfirmation) {
234 ChooseLockSettingsHelper helper =
235 new ChooseLockSettingsHelper(this.getActivity(), this);
236 boolean managedProfileWithUnifiedLock =
237 UserManager.get(getActivity()).isManagedProfile(mUserId)
238 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
239 boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword;
241 || !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
242 getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
243 mPasswordConfirmed = true; // no password set, so no need to confirm
244 updatePreferencesOrFinish(savedInstanceState != null);
246 mWaitingForConfirmation = true;
252 protected void addHeaderView() {
253 if (mForFingerprint) {
254 setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
255 if (mIsSetNewPassword) {
256 ((TextView) getHeaderView().findViewById(R.id.fingerprint_header_description))
257 .setText(R.string.fingerprint_unlock_title);
263 public boolean onPreferenceTreeClick(Preference preference) {
264 final String key = preference.getKey();
266 if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
267 // Show the disabling FRP warning only when the user is switching from a secure
268 // unlock method to an insecure one
269 showFactoryResetProtectionWarningDialog(key);
271 } else if (KEY_SKIP_FINGERPRINT.equals(key)) {
272 Intent chooseLockGenericIntent = new Intent(getActivity(),
273 ChooseLockGeneric.InternalActivity.class);
274 chooseLockGenericIntent.setAction(getIntent().getAction());
275 // Forward the target user id to ChooseLockGeneric.
276 chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
277 chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
278 if (mUserPassword != null) {
279 chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
282 startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
285 return setUnlockMethod(key);
290 * If the device has encryption already enabled, then ask the user if they
291 * also want to encrypt the phone with this password.
296 // TODO: why does this take disabled, its always called with a quality higher than
297 // what makes sense with disabled == true
298 private void maybeEnableEncryption(int quality, boolean disabled) {
299 DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
300 if (UserManager.get(getActivity()).isAdminUser()
301 && mUserId == UserHandle.myUserId()
302 && LockPatternUtils.isDeviceEncryptionEnabled()
303 && !LockPatternUtils.isFileEncryptionEnabled()
304 && !dpm.getDoNotAskCredentialsOnBoot()) {
305 mEncryptionRequestQuality = quality;
306 mEncryptionRequestDisabled = disabled;
307 // Get the intent that the encryption interstitial should start for creating
308 // the new unlock method.
309 Intent unlockMethodIntent = getIntentForUnlockMethod(quality);
310 unlockMethodIntent.putExtra(
311 ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
312 mForChangeCredRequiredForBoot);
313 final Context context = getActivity();
314 // If accessibility is enabled and the user hasn't seen this dialog before, set the
315 // default state to agree with that which is compatible with accessibility
316 // (password not required).
317 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
318 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
319 Intent intent = getEncryptionInterstitialIntent(context, quality, required,
321 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
323 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
324 startActivityForResult(
326 mIsSetNewPassword && mHasChallenge
327 ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
328 : ENABLE_ENCRYPTION_REQUEST);
330 if (mForChangeCredRequiredForBoot) {
331 // Welp, couldn't change it. Oh well.
335 updateUnlockMethodAndFinish(quality, disabled, false /* chooseLockSkipped */);
340 public void onActivityResult(int requestCode, int resultCode, Intent data) {
341 super.onActivityResult(requestCode, resultCode, data);
342 mWaitingForConfirmation = false;
343 if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
344 mPasswordConfirmed = true;
345 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
346 updatePreferencesOrFinish(false /* isRecreatingActivity */);
347 if (mForChangeCredRequiredForBoot) {
348 if (!TextUtils.isEmpty(mUserPassword)) {
349 maybeEnableEncryption(
350 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
355 } else if (requestCode == CHOOSE_LOCK_REQUEST
356 || requestCode == ENABLE_ENCRYPTION_REQUEST) {
357 if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) {
358 getActivity().setResult(resultCode, data);
361 // If PASSWORD_TYPE_KEY is set, this activity is used as a trampoline to start
362 // the actual password enrollment. If the result is canceled, which means the
363 // user pressed back, finish the activity with result canceled.
364 int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
366 getActivity().setResult(RESULT_CANCELED, data);
370 } else if (requestCode == CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
371 && resultCode == FingerprintEnrollBase.RESULT_FINISHED) {
372 Intent intent = getFindSensorIntent(getActivity());
374 intent.putExtras(data.getExtras());
376 // Forward the target user id to fingerprint setup page.
377 intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
378 startActivity(intent);
380 } else if (requestCode == SKIP_FINGERPRINT_REQUEST) {
381 if (resultCode != RESULT_CANCELED) {
382 getActivity().setResult(
383 resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data);
387 getActivity().setResult(Activity.RESULT_CANCELED);
390 if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
395 protected Intent getFindSensorIntent(Context context) {
396 return new Intent(context, FingerprintEnrollFindSensor.class);
400 public void onSaveInstanceState(Bundle outState) {
401 super.onSaveInstanceState(outState);
402 // Saved so we don't force user to re-enter their password if configuration changes
403 outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
404 outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
405 outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality);
406 outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled);
407 if (mUserPassword != null) {
408 outState.putString(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
412 private void updatePreferencesOrFinish(boolean isRecreatingActivity) {
413 Intent intent = getActivity().getIntent();
414 int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
416 // If caller didn't specify password quality, show UI and allow the user to choose.
417 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
418 quality = mController.upgradeQuality(quality);
419 final boolean hideDisabledPrefs = intent.getBooleanExtra(
420 HIDE_DISABLED_PREFS, false);
421 final PreferenceScreen prefScreen = getPreferenceScreen();
422 if (prefScreen != null) {
423 prefScreen.removeAll();
426 disableUnusablePreferences(quality, hideDisabledPrefs);
427 updatePreferenceText();
428 updateCurrentPreference();
429 updatePreferenceSummaryIfNeeded();
430 } else if (!isRecreatingActivity) {
431 // Don't start the activity again if we are recreated for configuration change
432 updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */);
436 protected void addPreferences() {
437 addPreferencesFromResource(R.xml.security_settings_picker);
439 // Used for testing purposes
440 findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
441 findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
442 findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin);
443 findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
446 private void updatePreferenceText() {
447 if (mForFingerprint) {
448 setPreferenceTitle(ScreenLockType.PATTERN,
449 R.string.fingerprint_unlock_set_unlock_pattern);
450 setPreferenceTitle(ScreenLockType.PIN, R.string.fingerprint_unlock_set_unlock_pin);
451 setPreferenceTitle(ScreenLockType.PASSWORD,
452 R.string.fingerprint_unlock_set_unlock_password);
455 if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
456 setPreferenceTitle(ScreenLockType.MANAGED,
457 mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
459 removePreference(ScreenLockType.MANAGED.preferenceKey);
462 if (!(mForFingerprint && mIsSetNewPassword)) {
463 removePreference(KEY_SKIP_FINGERPRINT);
467 private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
468 Preference preference = findPreference(lock.preferenceKey);
469 if (preference != null) {
470 preference.setTitle(title);
474 private void setPreferenceTitle(ScreenLockType lock, CharSequence title) {
475 Preference preference = findPreference(lock.preferenceKey);
476 if (preference != null) {
477 preference.setTitle(title);
481 private void setPreferenceSummary(ScreenLockType lock, @StringRes int summary) {
482 Preference preference = findPreference(lock.preferenceKey);
483 if (preference != null) {
484 preference.setSummary(summary);
488 private void updateCurrentPreference() {
489 String currentKey = getKeyForCurrent();
490 Preference preference = findPreference(currentKey);
491 if (preference != null) {
492 preference.setSummary(R.string.current_screen_lock);
496 private String getKeyForCurrent() {
497 final int credentialOwner = UserManager.get(getContext())
498 .getCredentialOwnerProfile(mUserId);
499 if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
500 return ScreenLockType.NONE.preferenceKey;
502 ScreenLockType lock =
503 ScreenLockType.fromQuality(
504 mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner));
505 return lock != null ? lock.preferenceKey : null;
509 * Disables preferences that are less secure than required quality. The actual
510 * implementation is in disableUnusablePreferenceImpl.
512 * @param quality the requested quality.
513 * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
514 * they're not shown at all.
516 protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
517 disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
521 * Disables preferences that are less secure than required quality.
523 * @param quality the requested quality.
524 * @param hideDisabled whether to hide disable screen lock options.
526 protected void disableUnusablePreferencesImpl(final int quality,
527 boolean hideDisabled) {
528 final PreferenceScreen entries = getPreferenceScreen();
530 int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId);
531 EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
532 getActivity(), mUserId);
534 for (ScreenLockType lock : ScreenLockType.values()) {
535 String key = lock.preferenceKey;
536 Preference pref = findPreference(key);
537 if (pref instanceof RestrictedPreference) {
538 boolean visible = mController.isScreenLockVisible(lock);
539 boolean enabled = mController.isScreenLockEnabled(lock, quality);
540 boolean disabledByAdmin =
541 mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality);
543 visible = visible && enabled;
546 entries.removePreference(pref);
547 } else if (disabledByAdmin && enforcedAdmin != null) {
548 ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
549 } else if (!enabled) {
550 // we need to setDisabledByAdmin to null first to disable the padlock
551 // in case it was set earlier.
552 ((RestrictedPreference) pref).setDisabledByAdmin(null);
553 pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
554 pref.setEnabled(false);
556 ((RestrictedPreference) pref).setDisabledByAdmin(null);
562 private void updatePreferenceSummaryIfNeeded() {
563 // On a default block encrypted device with accessibility, add a warning
564 // that your data is not credential encrypted
565 if (!StorageManager.isBlockEncrypted()) {
569 if (StorageManager.isNonDefaultBlockEncrypted()) {
573 if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
574 AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
578 setPreferenceSummary(ScreenLockType.PATTERN, R.string.secure_lock_encryption_warning);
579 setPreferenceSummary(ScreenLockType.PIN, R.string.secure_lock_encryption_warning);
580 setPreferenceSummary(ScreenLockType.PASSWORD, R.string.secure_lock_encryption_warning);
581 setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning);
584 protected Intent getLockManagedPasswordIntent(String password) {
585 return mManagedPasswordProvider.createIntent(false, password);
588 protected Intent getLockPasswordIntent(int quality, int minLength, int maxLength) {
589 ChooseLockPassword.IntentBuilder builder =
590 new ChooseLockPassword.IntentBuilder(getContext())
591 .setPasswordQuality(quality)
592 .setPasswordLengthRange(minLength, maxLength)
593 .setForFingerprint(mForFingerprint)
596 builder.setChallenge(mChallenge);
598 if (mUserPassword != null) {
599 builder.setPassword(mUserPassword);
601 return builder.build();
604 protected Intent getLockPatternIntent() {
605 ChooseLockPattern.IntentBuilder builder =
606 new ChooseLockPattern.IntentBuilder(getContext())
607 .setForFingerprint(mForFingerprint)
610 builder.setChallenge(mChallenge);
612 if (mUserPassword != null) {
613 builder.setPattern(mUserPassword);
615 return builder.build();
618 protected Intent getEncryptionInterstitialIntent(Context context, int quality,
619 boolean required, Intent unlockMethodIntent) {
620 return EncryptionInterstitial.createStartIntent(context, quality, required,
625 * Invokes an activity to change the user's pattern, password or PIN based on given quality
626 * and minimum quality specified by DevicePolicyManager. If quality is
627 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
629 * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
630 * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
631 * @param chooseLockSkipped whether or not this activity is skipped. This is true when this
632 * activity was not shown to the user at all, instead automatically proceeding based on
633 * the given intent extras, typically {@link LockPatternUtils#PASSWORD_TYPE_KEY}.
634 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
636 void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) {
637 // Sanity check. We should never get here without confirming user's existing password.
638 if (!mPasswordConfirmed) {
639 throw new IllegalStateException("Tried to update password without confirming it");
642 quality = mController.upgradeQuality(quality);
643 Intent intent = getIntentForUnlockMethod(quality);
644 if (intent != null) {
645 if (getIntent().getBooleanExtra(EXTRA_SHOW_OPTIONS_BUTTON, false)) {
646 intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped);
648 intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras());
649 startActivityForResult(intent,
650 mIsSetNewPassword && mHasChallenge
651 ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
652 : CHOOSE_LOCK_REQUEST);
656 if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
657 mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId);
658 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
659 getActivity().setResult(Activity.RESULT_OK);
660 removeAllFingerprintForUserAndFinish(mUserId);
662 removeAllFingerprintForUserAndFinish(mUserId);
666 private Intent getIntentForUnlockMethod(int quality) {
667 Intent intent = null;
668 if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
669 intent = getLockManagedPasswordIntent(mUserPassword);
670 } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
671 int minLength = mDPM.getPasswordMinimumLength(null, mUserId);
672 if (minLength < MIN_PASSWORD_LENGTH) {
673 minLength = MIN_PASSWORD_LENGTH;
675 final int maxLength = mDPM.getPasswordMaximumLength(quality);
676 intent = getLockPasswordIntent(quality, minLength, maxLength);
677 } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
678 intent = getLockPatternIntent();
680 if (intent != null) {
681 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
686 private void removeAllFingerprintForUserAndFinish(final int userId) {
687 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
688 if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
689 mFingerprintManager.setActiveUser(userId);
690 // For the purposes of M and N, groupId is the same as userId.
691 final int groupId = userId;
692 Fingerprint finger = new Fingerprint(null, groupId, 0, 0);
693 mFingerprintManager.remove(finger, userId,
694 new RemovalCallback() {
696 public void onRemovalError(Fingerprint fp, int errMsgId,
697 CharSequence errString) {
698 Log.e(TAG, String.format(
699 "Can't remove fingerprint %d in group %d. Reason: %s",
700 fp.getFingerId(), fp.getGroupId(), errString));
701 // TODO: need to proceed with the removal of managed profile
702 // fingerprints and finish() gracefully.
706 public void onRemovalSucceeded(Fingerprint fp, int remaining) {
707 if (remaining == 0) {
708 removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
713 // No fingerprints in this user, we may also want to delete managed profile
715 removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
718 // The removal callback will call finish, once all fingerprints are removed.
719 // We need to wait for that to occur, otherwise, the UI will still show that
720 // fingerprints exist even though they are (about to) be removed depending on
721 // the race condition.
726 private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId) {
727 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
728 mFingerprintManager.setActiveUser(UserHandle.myUserId());
730 boolean hasChildProfile = false;
731 if (!mUserManager.getUserInfo(parentUserId).isManagedProfile()) {
732 // Current user is primary profile, remove work profile fingerprints if necessary
733 final List<UserInfo> profiles = mUserManager.getProfiles(parentUserId);
734 final int profilesSize = profiles.size();
735 for (int i = 0; i < profilesSize; i++) {
736 final UserInfo userInfo = profiles.get(i);
737 if (userInfo.isManagedProfile() && !mLockPatternUtils
738 .isSeparateProfileChallengeEnabled(userInfo.id)) {
739 removeAllFingerprintForUserAndFinish(userInfo.id);
740 hasChildProfile = true;
745 if (!hasChildProfile) {
751 public void onDestroy() {
756 public int getHelpResource() {
757 return R.string.help_url_choose_lockscreen;
760 private int getResIdForFactoryResetProtectionWarningTitle() {
761 boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
762 return isProfile ? R.string.unlock_disable_frp_warning_title_profile
763 : R.string.unlock_disable_frp_warning_title;
766 private int getResIdForFactoryResetProtectionWarningMessage() {
767 final boolean hasFingerprints;
768 if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
769 hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(mUserId);
771 hasFingerprints = false;
773 boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
774 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
775 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
776 if (hasFingerprints && isProfile) {
778 .unlock_disable_frp_warning_content_pattern_fingerprint_profile;
779 } else if (hasFingerprints && !isProfile) {
780 return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
781 } else if (isProfile) {
782 return R.string.unlock_disable_frp_warning_content_pattern_profile;
784 return R.string.unlock_disable_frp_warning_content_pattern;
786 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
787 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
788 if (hasFingerprints && isProfile) {
789 return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile;
790 } else if (hasFingerprints && !isProfile) {
791 return R.string.unlock_disable_frp_warning_content_pin_fingerprint;
792 } else if (isProfile) {
793 return R.string.unlock_disable_frp_warning_content_pin_profile;
795 return R.string.unlock_disable_frp_warning_content_pin;
797 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
798 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
799 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
800 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
801 if (hasFingerprints && isProfile) {
803 .unlock_disable_frp_warning_content_password_fingerprint_profile;
804 } else if (hasFingerprints && !isProfile) {
805 return R.string.unlock_disable_frp_warning_content_password_fingerprint;
806 } else if (isProfile) {
807 return R.string.unlock_disable_frp_warning_content_password_profile;
809 return R.string.unlock_disable_frp_warning_content_password;
812 if (hasFingerprints && isProfile) {
814 .unlock_disable_frp_warning_content_unknown_fingerprint_profile;
815 } else if (hasFingerprints && !isProfile) {
816 return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
817 } else if (isProfile) {
818 return R.string.unlock_disable_frp_warning_content_unknown_profile;
820 return R.string.unlock_disable_frp_warning_content_unknown;
825 private boolean isUnlockMethodSecure(String unlockMethod) {
826 return !(ScreenLockType.SWIPE.preferenceKey.equals(unlockMethod) ||
827 ScreenLockType.NONE.preferenceKey.equals(unlockMethod));
830 private boolean setUnlockMethod(String unlockMethod) {
831 EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
833 ScreenLockType lock = ScreenLockType.fromKey(unlockMethod);
838 updateUnlockMethodAndFinish(
840 lock == ScreenLockType.NONE,
841 false /* chooseLockSkipped */);
847 maybeEnableEncryption(lock.defaultQuality, false);
851 Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
855 private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
856 int title = getResIdForFactoryResetProtectionWarningTitle();
857 int message = getResIdForFactoryResetProtectionWarningMessage();
858 FactoryResetProtectionWarningDialog dialog =
859 FactoryResetProtectionWarningDialog.newInstance(
860 title, message, unlockMethodToSet);
861 dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
864 public static class FactoryResetProtectionWarningDialog extends InstrumentedDialogFragment {
866 private static final String ARG_TITLE_RES = "titleRes";
867 private static final String ARG_MESSAGE_RES = "messageRes";
868 private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
870 public static FactoryResetProtectionWarningDialog newInstance(
871 int titleRes, int messageRes, String unlockMethodToSet) {
872 FactoryResetProtectionWarningDialog frag =
873 new FactoryResetProtectionWarningDialog();
874 Bundle args = new Bundle();
875 args.putInt(ARG_TITLE_RES, titleRes);
876 args.putInt(ARG_MESSAGE_RES, messageRes);
877 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
878 frag.setArguments(args);
883 public void show(FragmentManager manager, String tag) {
884 if (manager.findFragmentByTag(tag) == null) {
885 // Prevent opening multiple dialogs if tapped on button quickly
886 super.show(manager, tag);
891 public Dialog onCreateDialog(Bundle savedInstanceState) {
892 final Bundle args = getArguments();
894 return new AlertDialog.Builder(getActivity())
895 .setTitle(args.getInt(ARG_TITLE_RES))
896 .setMessage(args.getInt(ARG_MESSAGE_RES))
897 .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
898 (dialog, whichButton) -> {
899 String unlockMethod = args.getString(ARG_UNLOCK_METHOD_TO_SET);
900 ((ChooseLockGenericFragment) getParentFragment())
901 .setUnlockMethod(unlockMethod);
903 .setNegativeButton(R.string.cancel, (dialog, whichButton) -> dismiss())
908 public int getMetricsCategory() {
909 return MetricsEvent.DIALOG_FRP;