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