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