ChooseLockGeneric.java revision 91e0ba7d40f6768d19d1e9a32145847af88c6a8c
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
17package com.android.settings;
18
19import android.accessibilityservice.AccessibilityServiceInfo;
20import android.app.Activity;
21import android.app.AlertDialog;
22import android.app.Dialog;
23import android.app.DialogFragment;
24import android.app.Fragment;
25import android.app.FragmentManager;
26import android.app.admin.DevicePolicyManager;
27import android.content.Context;
28import android.content.DialogInterface;
29import android.content.Intent;
30import android.hardware.fingerprint.Fingerprint;
31import android.hardware.fingerprint.FingerprintManager;
32import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
33import android.os.Bundle;
34import android.os.Process;
35import android.os.UserHandle;
36import android.os.UserManager;
37import android.security.KeyStore;
38import android.support.v7.preference.Preference;
39import android.support.v7.preference.PreferenceScreen;
40import android.text.TextUtils;
41import android.util.EventLog;
42import android.util.Log;
43import android.view.View;
44import android.view.accessibility.AccessibilityManager;
45import android.widget.Toast;
46
47import com.android.internal.logging.MetricsProto.MetricsEvent;
48import com.android.internal.widget.LockPatternUtils;
49import com.android.settingslib.RestrictedLockUtils;
50import com.android.settingslib.RestrictedPreference;
51
52import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
53
54public class ChooseLockGeneric extends SettingsActivity {
55    public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
56
57    @Override
58    public Intent getIntent() {
59        Intent modIntent = new Intent(super.getIntent());
60        modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
61        return modIntent;
62    }
63
64    @Override
65    protected boolean isValidFragment(String fragmentName) {
66        if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
67        return false;
68    }
69
70    /* package */ Class<? extends Fragment> getFragmentClass() {
71        return ChooseLockGenericFragment.class;
72    }
73
74    public static class InternalActivity extends ChooseLockGeneric {
75    }
76
77    public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
78        private static final String TAG = "ChooseLockGenericFragment";
79        private static final int MIN_PASSWORD_LENGTH = 4;
80        private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
81        private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
82        private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
83        private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
84        private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
85        private static final String PASSWORD_CONFIRMED = "password_confirmed";
86        private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
87        public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
88        public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
89        public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality";
90        public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled";
91        public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
92
93        private static final int CONFIRM_EXISTING_REQUEST = 100;
94        private static final int ENABLE_ENCRYPTION_REQUEST = 101;
95        private static final int CHOOSE_LOCK_REQUEST = 102;
96
97        private ChooseLockSettingsHelper mChooseLockSettingsHelper;
98        private DevicePolicyManager mDPM;
99        private KeyStore mKeyStore;
100        private boolean mHasChallenge = false;
101        private long mChallenge;
102        private boolean mPasswordConfirmed = false;
103        private boolean mWaitingForConfirmation = false;
104        private int mEncryptionRequestQuality;
105        private boolean mEncryptionRequestDisabled;
106        private boolean mRequirePassword;
107        private boolean mForFingerprint = false;
108        private boolean mForChangeCredRequiredForBoot = false;
109        private String mUserPassword;
110        private LockPatternUtils mLockPatternUtils;
111        private FingerprintManager mFingerprintManager;
112        private int mUserId;
113        private RemovalCallback mRemovalCallback = new RemovalCallback() {
114
115            @Override
116            public void onRemovalSucceeded(Fingerprint fingerprint) {
117                Log.v(TAG, "Fingerprint removed: " + fingerprint.getFingerId());
118                if (mFingerprintManager.getEnrolledFingerprints().size() == 0) {
119                    finish();
120                }
121            }
122
123            @Override
124            public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
125                Activity activity = getActivity();
126                if (activity != null) {
127                    Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT);
128                }
129                finish();
130            }
131        };
132
133        @Override
134        protected int getMetricsCategory() {
135            return MetricsEvent.CHOOSE_LOCK_GENERIC;
136        }
137
138        @Override
139        public void onCreate(Bundle savedInstanceState) {
140            super.onCreate(savedInstanceState);
141
142            mFingerprintManager =
143                (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE);
144            mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
145            mKeyStore = KeyStore.getInstance();
146            mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
147            mLockPatternUtils = new LockPatternUtils(getActivity());
148
149            // Defaults to needing to confirm credentials
150            final boolean confirmCredentials = getActivity().getIntent()
151                .getBooleanExtra(CONFIRM_CREDENTIALS, true);
152            if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
153                mPasswordConfirmed = !confirmCredentials;
154            }
155
156            mHasChallenge = getActivity().getIntent().getBooleanExtra(
157                    ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
158            mChallenge = getActivity().getIntent().getLongExtra(
159                    ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
160            mForFingerprint = getActivity().getIntent().getBooleanExtra(
161                    ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
162            mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
163                    ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
164
165            if (savedInstanceState != null) {
166                mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
167                mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
168                mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY);
169                mEncryptionRequestDisabled = savedInstanceState.getBoolean(
170                        ENCRYPT_REQUESTED_DISABLED);
171            }
172
173            int targetUser = Utils.getSecureTargetUser(
174                    getActivity().getActivityToken(),
175                    UserManager.get(getActivity()),
176                    null,
177                    getActivity().getIntent().getExtras()).getIdentifier();
178            if (DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(
179                    getActivity().getIntent().getAction()) ||
180                    !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) {
181                // Always use parent if explicitely requested or if profile challenge is not
182                // supported
183                mUserId = Utils.getUserIdFromBundle(getContext(), getArguments());
184            } else {
185                mUserId = targetUser;
186            }
187
188            if (mPasswordConfirmed) {
189                updatePreferencesOrFinish();
190                if (mForChangeCredRequiredForBoot) {
191                    maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
192                            mUserId), false);
193                }
194            } else if (!mWaitingForConfirmation) {
195                ChooseLockSettingsHelper helper =
196                        new ChooseLockSettingsHelper(this.getActivity(), this);
197                if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
198                        getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
199                    mPasswordConfirmed = true; // no password set, so no need to confirm
200                    updatePreferencesOrFinish();
201                } else {
202                    mWaitingForConfirmation = true;
203                }
204            }
205        }
206
207        @Override
208        public void onViewCreated(View view, Bundle savedInstanceState) {
209            super.onViewCreated(view, savedInstanceState);
210            if (mForFingerprint) {
211                setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
212            }
213        }
214
215        @Override
216        public boolean onPreferenceTreeClick(Preference preference) {
217            final String key = preference.getKey();
218
219            if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
220                // Show the disabling FRP warning only when the user is switching from a secure
221                // unlock method to an insecure one
222                showFactoryResetProtectionWarningDialog(key);
223                return true;
224            } else {
225                return setUnlockMethod(key);
226            }
227        }
228
229        /**
230         * If the device has encryption already enabled, then ask the user if they
231         * also want to encrypt the phone with this password.
232         *
233         * @param quality
234         * @param disabled
235         */
236        // TODO: why does this take disabled, its always called with a quality higher than
237        // what makes sense with disabled == true
238        private void maybeEnableEncryption(int quality, boolean disabled) {
239            DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
240            if (UserManager.get(getActivity()).isAdminUser()
241                    && mUserId == UserHandle.myUserId()
242                    && LockPatternUtils.isDeviceEncryptionEnabled()
243                    && !LockPatternUtils.isFileEncryptionEnabled()
244                    && !dpm.getDoNotAskCredentialsOnBoot()) {
245                mEncryptionRequestQuality = quality;
246                mEncryptionRequestDisabled = disabled;
247                // Get the intent that the encryption interstitial should start for creating
248                // the new unlock method.
249                Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled);
250                unlockMethodIntent.putExtra(
251                        ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
252                        mForChangeCredRequiredForBoot);
253                final Context context = getActivity();
254                // If accessibility is enabled and the user hasn't seen this dialog before, set the
255                // default state to agree with that which is compatible with accessibility
256                // (password not required).
257                final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
258                final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
259                Intent intent = getEncryptionInterstitialIntent(context, quality, required,
260                        unlockMethodIntent);
261                intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
262                        mForFingerprint);
263                startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST);
264            } else {
265                if (mForChangeCredRequiredForBoot) {
266                    // Welp, couldn't change it. Oh well.
267                    finish();
268                    return;
269                }
270                mRequirePassword = false; // device encryption not enabled or not device owner.
271                updateUnlockMethodAndFinish(quality, disabled);
272            }
273        }
274
275        @Override
276        public void onActivityResult(int requestCode, int resultCode, Intent data) {
277            super.onActivityResult(requestCode, resultCode, data);
278            mWaitingForConfirmation = false;
279            if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
280                mPasswordConfirmed = true;
281                mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
282                updatePreferencesOrFinish();
283                if (mForChangeCredRequiredForBoot) {
284                    if (!TextUtils.isEmpty(mUserPassword)) {
285                        maybeEnableEncryption(
286                                mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
287                    } else {
288                        finish();
289                    }
290                }
291            } else if (requestCode == CHOOSE_LOCK_REQUEST
292                    || requestCode == ENABLE_ENCRYPTION_REQUEST) {
293                if (resultCode != RESULT_CANCELED) {
294                    getActivity().setResult(resultCode, data);
295                    finish();
296                }
297            } else {
298                getActivity().setResult(Activity.RESULT_CANCELED);
299                finish();
300            }
301            if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
302                finish();
303            }
304        }
305
306        @Override
307        public void onSaveInstanceState(Bundle outState) {
308            super.onSaveInstanceState(outState);
309            // Saved so we don't force user to re-enter their password if configuration changes
310            outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
311            outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
312            outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality);
313            outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled);
314        }
315
316        private void updatePreferencesOrFinish() {
317            Intent intent = getActivity().getIntent();
318            int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
319            if (quality == -1) {
320                // If caller didn't specify password quality, show UI and allow the user to choose.
321                quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
322                quality = upgradeQuality(quality);
323                final boolean hideDisabledPrefs = intent.getBooleanExtra(
324                        HIDE_DISABLED_PREFS, false);
325                final PreferenceScreen prefScreen = getPreferenceScreen();
326                if (prefScreen != null) {
327                    prefScreen.removeAll();
328                }
329                addPreferencesFromResource(R.xml.security_settings_picker);
330                disableUnusablePreferences(quality, hideDisabledPrefs);
331                updatePreferenceText();
332                updateCurrentPreference();
333                updatePreferenceSummaryIfNeeded();
334            } else {
335                updateUnlockMethodAndFinish(quality, false);
336            }
337        }
338
339        private void updatePreferenceText() {
340            if (mForFingerprint) {
341                Preference pattern = findPreference(KEY_UNLOCK_SET_PATTERN);
342                pattern.setTitle(R.string.fingerprint_unlock_set_unlock_pattern);
343
344                Preference pin = findPreference(KEY_UNLOCK_SET_PIN);
345                pin.setTitle(R.string.fingerprint_unlock_set_unlock_pin);
346
347                Preference password = findPreference(KEY_UNLOCK_SET_PASSWORD);
348                password.setTitle(R.string.fingerprint_unlock_set_unlock_password);
349            }
350        }
351
352        private void updateCurrentPreference() {
353            String currentKey = getKeyForCurrent();
354            Preference preference = findPreference(currentKey);
355            if (preference != null) {
356                preference.setSummary(R.string.current_screen_lock);
357            }
358        }
359
360        private String getKeyForCurrent() {
361            final int credentialOwner = UserManager.get(getContext())
362                    .getCredentialOwnerProfile(mUserId);
363            if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
364                return KEY_UNLOCK_SET_OFF;
365            }
366            switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner)) {
367                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
368                    return KEY_UNLOCK_SET_PATTERN;
369                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
370                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
371                    return KEY_UNLOCK_SET_PIN;
372                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
373                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
374                    return KEY_UNLOCK_SET_PASSWORD;
375                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
376                    return KEY_UNLOCK_SET_NONE;
377            }
378            return null;
379        }
380
381        /** increases the quality if necessary */
382        private int upgradeQuality(int quality) {
383            quality = upgradeQualityForDPM(quality);
384            return quality;
385        }
386
387        private int upgradeQualityForDPM(int quality) {
388            // Compare min allowed password quality
389            int minQuality = mDPM.getPasswordQuality(null);
390            if (quality < minQuality) {
391                quality = minQuality;
392            }
393            return quality;
394        }
395
396        /***
397         * Disables preferences that are less secure than required quality. The actual
398         * implementation is in disableUnusablePreferenceImpl.
399         *
400         * @param quality the requested quality.
401         * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
402         * they're not shown at all.
403         */
404        protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
405            disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
406        }
407
408        /***
409         * Disables preferences that are less secure than required quality.
410         *
411         * @param quality the requested quality.
412         * @param hideDisabled whether to hide disable screen lock options.
413         */
414        protected void disableUnusablePreferencesImpl(final int quality,
415                boolean hideDisabled) {
416            final PreferenceScreen entries = getPreferenceScreen();
417
418            int adminEnforcedQuality = mDPM.getPasswordQuality(null);
419            EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
420                    getActivity(), mUserId);
421            for (int i = entries.getPreferenceCount() - 1; i >= 0; --i) {
422                Preference pref = entries.getPreference(i);
423                if (pref instanceof RestrictedPreference) {
424                    final String key = pref.getKey();
425                    boolean enabled = true;
426                    boolean visible = true;
427                    boolean disabledByAdmin = false;
428                    if (KEY_UNLOCK_SET_OFF.equals(key)) {
429                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
430                        if (getResources().getBoolean(R.bool.config_hide_none_security_option)) {
431                            enabled = false;
432                            visible = false;
433                        }
434                        disabledByAdmin = adminEnforcedQuality
435                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
436                    } else if (KEY_UNLOCK_SET_NONE.equals(key)) {
437                        if (mUserId != UserHandle.myUserId()) {
438                            // Swipe doesn't make sense for profiles.
439                            visible = false;
440                        }
441                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
442                        disabledByAdmin = adminEnforcedQuality
443                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
444                    } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
445                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
446                        disabledByAdmin = adminEnforcedQuality
447                                > DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
448                    } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
449                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
450                        disabledByAdmin = adminEnforcedQuality
451                                > DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
452                    } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
453                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
454                        disabledByAdmin = adminEnforcedQuality
455                                > DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
456                    }
457                    if (hideDisabled) {
458                        visible = enabled;
459                    }
460                    if (!visible) {
461                        entries.removePreference(pref);
462                    } else if (disabledByAdmin && enforcedAdmin != null) {
463                        ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
464                    } else if (!enabled) {
465                        // we need to setDisabledByAdmin to null first to disable the padlock
466                        // in case it was set earlier.
467                        ((RestrictedPreference) pref).setDisabledByAdmin(null);
468                        pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
469                        pref.setEnabled(false);
470                    } else {
471                        ((RestrictedPreference) pref).setDisabledByAdmin(null);
472                    }
473                }
474            }
475        }
476
477        private void updatePreferenceSummaryIfNeeded() {
478            if (LockPatternUtils.isDeviceEncrypted()) {
479                return;
480            }
481
482            if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
483                    AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
484                return;
485            }
486
487            CharSequence summary = getString(R.string.secure_lock_encryption_warning);
488
489            PreferenceScreen screen = getPreferenceScreen();
490            final int preferenceCount = screen.getPreferenceCount();
491            for (int i = 0; i < preferenceCount; i++) {
492                Preference preference = screen.getPreference(i);
493                switch (preference.getKey()) {
494                    case KEY_UNLOCK_SET_PATTERN:
495                    case KEY_UNLOCK_SET_PIN:
496                    case KEY_UNLOCK_SET_PASSWORD: {
497                        preference.setSummary(summary);
498                    } break;
499                }
500            }
501        }
502
503        protected Intent getLockPasswordIntent(Context context, int quality,
504                int minLength, final int maxLength,
505                boolean requirePasswordToDecrypt, boolean confirmCredentials, int userId) {
506            return ChooseLockPassword.createIntent(context, quality, minLength,
507                    maxLength, requirePasswordToDecrypt, confirmCredentials, userId);
508        }
509
510        protected Intent getLockPasswordIntent(Context context, int quality,
511                int minLength, final int maxLength,
512                boolean requirePasswordToDecrypt, long challenge, int userId) {
513            return ChooseLockPassword.createIntent(context, quality, minLength,
514                    maxLength, requirePasswordToDecrypt, challenge, userId);
515        }
516
517        protected Intent getLockPasswordIntent(Context context, int quality, int minLength,
518                int maxLength, boolean requirePasswordToDecrypt, String password, int userId) {
519            return ChooseLockPassword.createIntent(context, quality, minLength, maxLength,
520                    requirePasswordToDecrypt, password, userId);
521        }
522
523        protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
524                final boolean confirmCredentials, int userId) {
525            return ChooseLockPattern.createIntent(context, requirePassword,
526                    confirmCredentials, userId);
527        }
528
529        protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
530               long challenge, int userId) {
531            return ChooseLockPattern.createIntent(context, requirePassword, challenge, userId);
532        }
533
534        protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
535                final String pattern, int userId) {
536            return ChooseLockPattern.createIntent(context, requirePassword, pattern, userId);
537        }
538
539        protected Intent getEncryptionInterstitialIntent(Context context, int quality,
540                boolean required, Intent unlockMethodIntent) {
541            return EncryptionInterstitial.createStartIntent(context, quality, required,
542                    unlockMethodIntent);
543        }
544
545        /**
546         * Invokes an activity to change the user's pattern, password or PIN based on given quality
547         * and minimum quality specified by DevicePolicyManager. If quality is
548         * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
549         *
550         * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
551         * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
552         * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
553         */
554        void updateUnlockMethodAndFinish(int quality, boolean disabled) {
555            // Sanity check. We should never get here without confirming user's existing password.
556            if (!mPasswordConfirmed) {
557                throw new IllegalStateException("Tried to update password without confirming it");
558            }
559
560            quality = upgradeQuality(quality);
561            Intent intent = getIntentForUnlockMethod(quality, disabled);
562            if (intent != null) {
563                startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
564                return;
565            }
566
567            if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
568                mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, true);
569                mChooseLockSettingsHelper.utils().clearLock(mUserId);
570                mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
571                mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, false);
572                removeAllFingerprintTemplatesAndFinish();
573                getActivity().setResult(Activity.RESULT_OK);
574            } else {
575                removeAllFingerprintTemplatesAndFinish();
576            }
577        }
578
579        private Intent getIntentForUnlockMethod(int quality, boolean disabled) {
580            Intent intent = null;
581            final Context context = getActivity();
582            if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
583                int minLength = mDPM.getPasswordMinimumLength(null);
584                if (minLength < MIN_PASSWORD_LENGTH) {
585                    minLength = MIN_PASSWORD_LENGTH;
586                }
587                final int maxLength = mDPM.getPasswordMaximumLength(quality);
588                if (mHasChallenge) {
589                    intent = getLockPasswordIntent(context, quality, minLength,
590                            maxLength, mRequirePassword, mChallenge, mUserId);
591                } else {
592                    intent = getLockPasswordIntent(context, quality, minLength,
593                            maxLength, mRequirePassword, mUserPassword, mUserId);
594                }
595            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
596                if (mHasChallenge) {
597                    intent = getLockPatternIntent(context, mRequirePassword,
598                            mChallenge, mUserId);
599                } else {
600                    intent = getLockPatternIntent(context, mRequirePassword,
601                            mUserPassword, mUserId);
602                }
603            }
604            return intent;
605        }
606
607        private void removeAllFingerprintTemplatesAndFinish() {
608            if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
609                    && mFingerprintManager.getEnrolledFingerprints().size() > 0) {
610                mFingerprintManager.remove(
611                        new Fingerprint(null, 0, 0, 0), mUserId, mRemovalCallback);
612            } else {
613                finish();
614            }
615        }
616
617        @Override
618        public void onDestroy() {
619            super.onDestroy();
620        }
621
622        @Override
623        protected int getHelpResource() {
624            return R.string.help_url_choose_lockscreen;
625        }
626
627        private int getResIdForFactoryResetProtectionWarningTitle() {
628            boolean isProfile = Utils.isManagedProfile(UserManager.get(getActivity()), mUserId);
629            return isProfile ? R.string.unlock_disable_frp_warning_title_profile
630                    : R.string.unlock_disable_frp_warning_title;
631        }
632
633        private int getResIdForFactoryResetProtectionWarningMessage() {
634            boolean hasFingerprints = mFingerprintManager.hasEnrolledFingerprints();
635            boolean isProfile = Utils.isManagedProfile(UserManager.get(getActivity()), mUserId);
636            switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
637                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
638                    if (hasFingerprints && isProfile) {
639                        return R.string
640                                .unlock_disable_frp_warning_content_pattern_fingerprint_profile;
641                    } else if (hasFingerprints && !isProfile) {
642                        return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
643                    } else if (isProfile) {
644                        return R.string.unlock_disable_frp_warning_content_pattern_profile;
645                    } else {
646                        return R.string.unlock_disable_frp_warning_content_pattern;
647                    }
648                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
649                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
650                    if (hasFingerprints && isProfile) {
651                        return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile;
652                    } else if (hasFingerprints && !isProfile) {
653                        return R.string.unlock_disable_frp_warning_content_pin_fingerprint;
654                    } else if (isProfile) {
655                        return R.string.unlock_disable_frp_warning_content_pin_profile;
656                    } else {
657                        return R.string.unlock_disable_frp_warning_content_pin;
658                    }
659                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
660                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
661                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
662                    if (hasFingerprints && isProfile) {
663                        return R.string
664                                .unlock_disable_frp_warning_content_password_fingerprint_profile;
665                    } else if (hasFingerprints && !isProfile) {
666                        return R.string.unlock_disable_frp_warning_content_password_fingerprint;
667                    } else if (isProfile) {
668                        return R.string.unlock_disable_frp_warning_content_password_profile;
669                    } else {
670                        return R.string.unlock_disable_frp_warning_content_password;
671                    }
672                default:
673                    if (hasFingerprints && isProfile) {
674                        return R.string
675                                .unlock_disable_frp_warning_content_unknown_fingerprint_profile;
676                    } else if (hasFingerprints && !isProfile) {
677                        return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
678                    } else if (isProfile) {
679                        return R.string.unlock_disable_frp_warning_content_unknown_profile;
680                    } else {
681                        return R.string.unlock_disable_frp_warning_content_unknown;
682                    }
683            }
684        }
685
686        private boolean isUnlockMethodSecure(String unlockMethod) {
687            return !(KEY_UNLOCK_SET_OFF.equals(unlockMethod) ||
688                    KEY_UNLOCK_SET_NONE.equals(unlockMethod));
689        }
690
691        private boolean setUnlockMethod(String unlockMethod) {
692            EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
693
694            if (KEY_UNLOCK_SET_OFF.equals(unlockMethod)) {
695                updateUnlockMethodAndFinish(
696                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true /* disabled */ );
697            } else if (KEY_UNLOCK_SET_NONE.equals(unlockMethod)) {
698                updateUnlockMethodAndFinish(
699                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false /* disabled */ );
700            } else if (KEY_UNLOCK_SET_PATTERN.equals(unlockMethod)) {
701                maybeEnableEncryption(
702                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
703            } else if (KEY_UNLOCK_SET_PIN.equals(unlockMethod)) {
704                maybeEnableEncryption(
705                        DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
706            } else if (KEY_UNLOCK_SET_PASSWORD.equals(unlockMethod)) {
707                maybeEnableEncryption(
708                        DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false);
709            } else {
710                Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
711                return false;
712            }
713            return true;
714        }
715
716        private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
717            int title = getResIdForFactoryResetProtectionWarningTitle();
718            int message = getResIdForFactoryResetProtectionWarningMessage();
719            FactoryResetProtectionWarningDialog dialog =
720                    FactoryResetProtectionWarningDialog.newInstance(
721                            title, message, unlockMethodToSet);
722            dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
723        }
724
725        public static class FactoryResetProtectionWarningDialog extends DialogFragment {
726
727            private static final String ARG_TITLE_RES = "titleRes";
728            private static final String ARG_MESSAGE_RES = "messageRes";
729            private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
730
731            public static FactoryResetProtectionWarningDialog newInstance(
732                    int titleRes, int messageRes, String unlockMethodToSet) {
733                FactoryResetProtectionWarningDialog frag =
734                        new FactoryResetProtectionWarningDialog();
735                Bundle args = new Bundle();
736                args.putInt(ARG_TITLE_RES, titleRes);
737                args.putInt(ARG_MESSAGE_RES, messageRes);
738                args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
739                frag.setArguments(args);
740                return frag;
741            }
742
743            @Override
744            public void show(FragmentManager manager, String tag) {
745                if (manager.findFragmentByTag(tag) == null) {
746                    // Prevent opening multiple dialogs if tapped on button quickly
747                    super.show(manager, tag);
748                }
749            }
750
751            @Override
752            public Dialog onCreateDialog(Bundle savedInstanceState) {
753                final Bundle args = getArguments();
754
755                return new AlertDialog.Builder(getActivity())
756                        .setTitle(args.getInt(ARG_TITLE_RES))
757                        .setMessage(args.getInt(ARG_MESSAGE_RES))
758                        .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
759                                new DialogInterface.OnClickListener() {
760                                    @Override
761                                    public void onClick(DialogInterface dialog, int whichButton) {
762                                        ((ChooseLockGenericFragment) getParentFragment())
763                                                .setUnlockMethod(
764                                                        args.getString(ARG_UNLOCK_METHOD_TO_SET));
765                                    }
766                                }
767                        )
768                        .setNegativeButton(R.string.cancel,
769                                new DialogInterface.OnClickListener() {
770                                    @Override
771                                    public void onClick(DialogInterface dialog, int whichButton) {
772                                        dismiss();
773                                    }
774                                }
775                        )
776                        .create();
777            }
778        }
779    }
780}
781