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 static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
20import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
21import static com.android.settings.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
22import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
23
24import android.accessibilityservice.AccessibilityServiceInfo;
25import android.app.Activity;
26import android.app.AlertDialog;
27import android.app.Dialog;
28import android.app.Fragment;
29import android.app.FragmentManager;
30import android.app.admin.DevicePolicyManager;
31import android.content.Context;
32import android.content.DialogInterface;
33import android.content.Intent;
34import android.content.pm.UserInfo;
35import android.hardware.fingerprint.Fingerprint;
36import android.hardware.fingerprint.FingerprintManager;
37import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
38import android.os.Bundle;
39import android.os.UserHandle;
40import android.os.UserManager;
41import android.os.storage.StorageManager;
42import android.security.KeyStore;
43import android.support.v7.preference.Preference;
44import android.support.v7.preference.PreferenceScreen;
45import android.text.TextUtils;
46import android.util.EventLog;
47import android.util.Log;
48import android.view.accessibility.AccessibilityManager;
49import android.widget.TextView;
50
51import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
52import com.android.internal.widget.LockPatternUtils;
53import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
54import com.android.settings.fingerprint.FingerprintEnrollBase;
55import com.android.settings.fingerprint.FingerprintEnrollFindSensor;
56import com.android.settingslib.RestrictedLockUtils;
57import com.android.settingslib.RestrictedPreference;
58
59import java.util.List;
60
61public class ChooseLockGeneric extends SettingsActivity {
62    public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
63
64    @Override
65    public Intent getIntent() {
66        Intent modIntent = new Intent(super.getIntent());
67        modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
68
69        String action = modIntent.getAction();
70        if (ACTION_SET_NEW_PASSWORD.equals(action)
71                || ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(action)) {
72            modIntent.putExtra(EXTRA_HIDE_DRAWER, true);
73        }
74        return modIntent;
75    }
76
77    @Override
78    protected boolean isValidFragment(String fragmentName) {
79        if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
80        return false;
81    }
82
83    /* package */ Class<? extends Fragment> getFragmentClass() {
84        return ChooseLockGenericFragment.class;
85    }
86
87    public static class InternalActivity extends ChooseLockGeneric {
88    }
89
90    public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
91        private static final String TAG = "ChooseLockGenericFragment";
92        private static final int MIN_PASSWORD_LENGTH = 4;
93        private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
94        private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
95        private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
96        private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
97        private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
98        private static final String KEY_UNLOCK_SET_MANAGED = "unlock_set_managed";
99        private static final String KEY_SKIP_FINGERPRINT = "unlock_skip_fingerprint";
100        private static final String PASSWORD_CONFIRMED = "password_confirmed";
101        private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
102        public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
103        public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
104        public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality";
105        public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled";
106        public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
107
108        private static final int CONFIRM_EXISTING_REQUEST = 100;
109        private static final int ENABLE_ENCRYPTION_REQUEST = 101;
110        private static final int CHOOSE_LOCK_REQUEST = 102;
111        private static final int CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST = 103;
112        private static final int SKIP_FINGERPRINT_REQUEST = 104;
113
114        private ChooseLockSettingsHelper mChooseLockSettingsHelper;
115        private DevicePolicyManager mDPM;
116        private KeyStore mKeyStore;
117        private boolean mHasChallenge = false;
118        private long mChallenge;
119        private boolean mPasswordConfirmed = false;
120        private boolean mWaitingForConfirmation = false;
121        private int mEncryptionRequestQuality;
122        private boolean mEncryptionRequestDisabled;
123        private boolean mRequirePassword;
124        private boolean mForChangeCredRequiredForBoot = false;
125        private String mUserPassword;
126        private LockPatternUtils mLockPatternUtils;
127        private FingerprintManager mFingerprintManager;
128        private int mUserId;
129        private boolean mHideDrawer = false;
130        private ManagedLockPasswordProvider mManagedPasswordProvider;
131        private boolean mIsSetNewPassword = false;
132        private UserManager mUserManager;
133
134        protected boolean mForFingerprint = false;
135
136        @Override
137        public int getMetricsCategory() {
138            return MetricsEvent.CHOOSE_LOCK_GENERIC;
139        }
140
141        @Override
142        public void onCreate(Bundle savedInstanceState) {
143            super.onCreate(savedInstanceState);
144
145            String chooseLockAction = getActivity().getIntent().getAction();
146            mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity());
147            mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
148            mKeyStore = KeyStore.getInstance();
149            mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
150            mLockPatternUtils = new LockPatternUtils(getActivity());
151            mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
152                    || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction);
153
154            // Defaults to needing to confirm credentials
155            final boolean confirmCredentials = getActivity().getIntent()
156                .getBooleanExtra(CONFIRM_CREDENTIALS, true);
157            if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
158                mPasswordConfirmed = !confirmCredentials;
159            }
160            mHideDrawer = getActivity().getIntent().getBooleanExtra(EXTRA_HIDE_DRAWER, false);
161
162            mHasChallenge = getActivity().getIntent().getBooleanExtra(
163                    ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
164            mChallenge = getActivity().getIntent().getLongExtra(
165                    ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
166            mForFingerprint = getActivity().getIntent().getBooleanExtra(
167                    ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
168            mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
169                    ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
170            mUserManager = UserManager.get(getActivity());
171
172            if (savedInstanceState != null) {
173                mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
174                mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
175                mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY);
176                mEncryptionRequestDisabled = savedInstanceState.getBoolean(
177                        ENCRYPT_REQUESTED_DISABLED);
178            }
179
180            // a) If this is started from other user, use that user id.
181            // b) If this is started from the same user, read the extra if this is launched
182            //    from Settings app itself.
183            // c) Otherwise, use UserHandle.myUserId().
184            mUserId = Utils.getSecureTargetUser(
185                    getActivity().getActivityToken(),
186                    UserManager.get(getActivity()),
187                    getArguments(),
188                    getActivity().getIntent().getExtras()).getIdentifier();
189            if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction)
190                    && UserManager.get(getActivity()).isManagedProfile(mUserId)
191                    && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
192                getActivity().setTitle(R.string.lock_settings_picker_title_profile);
193            }
194
195            mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId);
196
197            if (mPasswordConfirmed) {
198                updatePreferencesOrFinish();
199                if (mForChangeCredRequiredForBoot) {
200                    maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
201                            mUserId), false);
202                }
203            } else if (!mWaitingForConfirmation) {
204                ChooseLockSettingsHelper helper =
205                        new ChooseLockSettingsHelper(this.getActivity(), this);
206                boolean managedProfileWithUnifiedLock =
207                        UserManager.get(getActivity()).isManagedProfile(mUserId)
208                        && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
209                if (managedProfileWithUnifiedLock
210                        || !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
211                        getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
212                    mPasswordConfirmed = true; // no password set, so no need to confirm
213                    updatePreferencesOrFinish();
214                } else {
215                    mWaitingForConfirmation = true;
216                }
217            }
218            addHeaderView();
219        }
220
221        protected void addHeaderView() {
222            if (mForFingerprint) {
223                setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
224                if (mIsSetNewPassword) {
225                    ((TextView) getHeaderView().findViewById(R.id.fingerprint_header_description))
226                            .setText(R.string.fingerprint_unlock_title);
227                }
228            }
229        }
230
231        @Override
232        public boolean onPreferenceTreeClick(Preference preference) {
233            final String key = preference.getKey();
234
235            if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
236                // Show the disabling FRP warning only when the user is switching from a secure
237                // unlock method to an insecure one
238                showFactoryResetProtectionWarningDialog(key);
239                return true;
240            } else if (KEY_SKIP_FINGERPRINT.equals(key)) {
241                Intent chooseLockGenericIntent = new Intent(getActivity(),
242                    ChooseLockGeneric.InternalActivity.class);
243                chooseLockGenericIntent.setAction(getIntent().getAction());
244                // Forward the target user id to  ChooseLockGeneric.
245                chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
246                chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
247                startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
248                return true;
249            } else {
250                return setUnlockMethod(key);
251            }
252        }
253
254        /**
255         * If the device has encryption already enabled, then ask the user if they
256         * also want to encrypt the phone with this password.
257         *
258         * @param quality
259         * @param disabled
260         */
261        // TODO: why does this take disabled, its always called with a quality higher than
262        // what makes sense with disabled == true
263        private void maybeEnableEncryption(int quality, boolean disabled) {
264            DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
265            if (UserManager.get(getActivity()).isAdminUser()
266                    && mUserId == UserHandle.myUserId()
267                    && LockPatternUtils.isDeviceEncryptionEnabled()
268                    && !LockPatternUtils.isFileEncryptionEnabled()
269                    && !dpm.getDoNotAskCredentialsOnBoot()) {
270                mEncryptionRequestQuality = quality;
271                mEncryptionRequestDisabled = disabled;
272                // Get the intent that the encryption interstitial should start for creating
273                // the new unlock method.
274                Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled);
275                unlockMethodIntent.putExtra(
276                        ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
277                        mForChangeCredRequiredForBoot);
278                final Context context = getActivity();
279                // If accessibility is enabled and the user hasn't seen this dialog before, set the
280                // default state to agree with that which is compatible with accessibility
281                // (password not required).
282                final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
283                final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
284                Intent intent = getEncryptionInterstitialIntent(context, quality, required,
285                        unlockMethodIntent);
286                intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
287                        mForFingerprint);
288                intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
289                startActivityForResult(
290                        intent,
291                        mIsSetNewPassword && mHasChallenge
292                                ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
293                                : ENABLE_ENCRYPTION_REQUEST);
294            } else {
295                if (mForChangeCredRequiredForBoot) {
296                    // Welp, couldn't change it. Oh well.
297                    finish();
298                    return;
299                }
300                mRequirePassword = false; // device encryption not enabled or not device owner.
301                updateUnlockMethodAndFinish(quality, disabled);
302            }
303        }
304
305        @Override
306        public void onActivityResult(int requestCode, int resultCode, Intent data) {
307            super.onActivityResult(requestCode, resultCode, data);
308            mWaitingForConfirmation = false;
309            if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
310                mPasswordConfirmed = true;
311                mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
312                updatePreferencesOrFinish();
313                if (mForChangeCredRequiredForBoot) {
314                    if (!TextUtils.isEmpty(mUserPassword)) {
315                        maybeEnableEncryption(
316                                mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
317                    } else {
318                        finish();
319                    }
320                }
321            } else if (requestCode == CHOOSE_LOCK_REQUEST
322                    || requestCode == ENABLE_ENCRYPTION_REQUEST) {
323                if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) {
324                    getActivity().setResult(resultCode, data);
325                    finish();
326                }
327            } else if (requestCode == CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
328                    && resultCode == FingerprintEnrollBase.RESULT_FINISHED) {
329                Intent intent = getFindSensorIntent(getActivity());
330                if (data != null) {
331                    intent.putExtras(data.getExtras());
332                }
333                // Forward the target user id to fingerprint setup page.
334                intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
335                startActivity(intent);
336                finish();
337            } else if (requestCode == SKIP_FINGERPRINT_REQUEST) {
338                if (resultCode != RESULT_CANCELED) {
339                    getActivity().setResult(
340                            resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data);
341                    finish();
342                }
343            } else {
344                getActivity().setResult(Activity.RESULT_CANCELED);
345                finish();
346            }
347            if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
348                finish();
349            }
350        }
351
352        protected Intent getFindSensorIntent(Context context) {
353            return new Intent(context, FingerprintEnrollFindSensor.class);
354        }
355
356        @Override
357        public void onSaveInstanceState(Bundle outState) {
358            super.onSaveInstanceState(outState);
359            // Saved so we don't force user to re-enter their password if configuration changes
360            outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
361            outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
362            outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality);
363            outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled);
364        }
365
366        private void updatePreferencesOrFinish() {
367            Intent intent = getActivity().getIntent();
368            int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
369            if (quality == -1) {
370                // If caller didn't specify password quality, show UI and allow the user to choose.
371                quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
372                quality = upgradeQuality(quality);
373                final boolean hideDisabledPrefs = intent.getBooleanExtra(
374                        HIDE_DISABLED_PREFS, false);
375                final PreferenceScreen prefScreen = getPreferenceScreen();
376                if (prefScreen != null) {
377                    prefScreen.removeAll();
378                }
379                addPreferences();
380                disableUnusablePreferences(quality, hideDisabledPrefs);
381                updatePreferenceText();
382                updateCurrentPreference();
383                updatePreferenceSummaryIfNeeded();
384            } else {
385                updateUnlockMethodAndFinish(quality, false);
386            }
387        }
388
389        protected void addPreferences() {
390            addPreferencesFromResource(R.xml.security_settings_picker);
391
392            // Used for testing purposes
393            findPreference(KEY_UNLOCK_SET_NONE).setViewId(R.id.lock_none);
394            findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
395            findPreference(KEY_UNLOCK_SET_PIN).setViewId(R.id.lock_pin);
396            findPreference(KEY_UNLOCK_SET_PASSWORD).setViewId(R.id.lock_password);
397        }
398
399        private void updatePreferenceText() {
400            if (mForFingerprint) {
401                final String key[] = { KEY_UNLOCK_SET_PATTERN,
402                        KEY_UNLOCK_SET_PIN,
403                        KEY_UNLOCK_SET_PASSWORD };
404                final int res[] = { R.string.fingerprint_unlock_set_unlock_pattern,
405                        R.string.fingerprint_unlock_set_unlock_pin,
406                        R.string.fingerprint_unlock_set_unlock_password };
407                for (int i = 0; i < key.length; i++) {
408                    Preference pref = findPreference(key[i]);
409                    if (pref != null) { // can be removed by device admin
410                        pref.setTitle(res[i]);
411                    }
412                }
413            }
414
415            if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
416                Preference managed = findPreference(KEY_UNLOCK_SET_MANAGED);
417                managed.setTitle(mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
418            } else {
419                removePreference(KEY_UNLOCK_SET_MANAGED);
420            }
421
422            if (!(mForFingerprint && mIsSetNewPassword)) {
423                removePreference(KEY_SKIP_FINGERPRINT);
424            }
425        }
426
427        private void updateCurrentPreference() {
428            String currentKey = getKeyForCurrent();
429            Preference preference = findPreference(currentKey);
430            if (preference != null) {
431                preference.setSummary(R.string.current_screen_lock);
432            }
433        }
434
435        private String getKeyForCurrent() {
436            final int credentialOwner = UserManager.get(getContext())
437                    .getCredentialOwnerProfile(mUserId);
438            if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
439                return KEY_UNLOCK_SET_OFF;
440            }
441            switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner)) {
442                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
443                    return KEY_UNLOCK_SET_PATTERN;
444                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
445                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
446                    return KEY_UNLOCK_SET_PIN;
447                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
448                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
449                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
450                    return KEY_UNLOCK_SET_PASSWORD;
451                case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
452                    return KEY_UNLOCK_SET_MANAGED;
453                case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
454                    return KEY_UNLOCK_SET_NONE;
455            }
456            return null;
457        }
458
459        /** increases the quality if necessary */
460        private int upgradeQuality(int quality) {
461            quality = upgradeQualityForDPM(quality);
462            return quality;
463        }
464
465        private int upgradeQualityForDPM(int quality) {
466            // Compare min allowed password quality
467            int minQuality = mDPM.getPasswordQuality(null, mUserId);
468            if (quality < minQuality) {
469                quality = minQuality;
470            }
471            return quality;
472        }
473
474        /***
475         * Disables preferences that are less secure than required quality. The actual
476         * implementation is in disableUnusablePreferenceImpl.
477         *
478         * @param quality the requested quality.
479         * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
480         * they're not shown at all.
481         */
482        protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
483            disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
484        }
485
486        /***
487         * Disables preferences that are less secure than required quality.
488         *
489         * @param quality the requested quality.
490         * @param hideDisabled whether to hide disable screen lock options.
491         */
492        protected void disableUnusablePreferencesImpl(final int quality,
493                boolean hideDisabled) {
494            final PreferenceScreen entries = getPreferenceScreen();
495
496            int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId);
497            EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
498                    getActivity(), mUserId);
499            for (int i = entries.getPreferenceCount() - 1; i >= 0; --i) {
500                Preference pref = entries.getPreference(i);
501                if (pref instanceof RestrictedPreference) {
502                    final String key = pref.getKey();
503                    boolean enabled = true;
504                    boolean visible = true;
505                    boolean disabledByAdmin = false;
506                    if (KEY_UNLOCK_SET_OFF.equals(key)) {
507                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
508                        if (getResources().getBoolean(R.bool.config_hide_none_security_option)) {
509                            enabled = false;
510                            visible = false;
511                        }
512                        disabledByAdmin = adminEnforcedQuality
513                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
514                    } else if (KEY_UNLOCK_SET_NONE.equals(key)) {
515                        if (getResources().getBoolean(R.bool.config_hide_swipe_security_option)) {
516                            enabled = false;
517                            visible = false;
518                        } else {
519                            if (mUserId != UserHandle.myUserId()) {
520                                // Swipe doesn't make sense for profiles.
521                                visible = false;
522                            }
523                            enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
524                        }
525                        disabledByAdmin = adminEnforcedQuality
526                                > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
527                    } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
528                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
529                        disabledByAdmin = adminEnforcedQuality
530                                > DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
531                    } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
532                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
533                        disabledByAdmin = adminEnforcedQuality
534                                > DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
535                    } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
536                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
537                        disabledByAdmin = adminEnforcedQuality
538                                > DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
539                    } else if (KEY_UNLOCK_SET_MANAGED.equals(key)) {
540                        enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_MANAGED
541                                && mManagedPasswordProvider.isManagedPasswordChoosable();
542                        disabledByAdmin = adminEnforcedQuality
543                                > DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
544                    }
545                    if (hideDisabled) {
546                        visible = enabled;
547                    }
548                    if (!visible) {
549                        entries.removePreference(pref);
550                    } else if (disabledByAdmin && enforcedAdmin != null) {
551                        ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
552                    } else if (!enabled) {
553                        // we need to setDisabledByAdmin to null first to disable the padlock
554                        // in case it was set earlier.
555                        ((RestrictedPreference) pref).setDisabledByAdmin(null);
556                        pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
557                        pref.setEnabled(false);
558                    } else {
559                        ((RestrictedPreference) pref).setDisabledByAdmin(null);
560                    }
561                }
562            }
563        }
564
565        private void updatePreferenceSummaryIfNeeded() {
566            // On a default block encrypted device with accessibility, add a warning
567            // that your data is not credential encrypted
568            if (!StorageManager.isBlockEncrypted()) {
569                return;
570            }
571
572            if (StorageManager.isNonDefaultBlockEncrypted()) {
573                return;
574            }
575
576            if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
577                    AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
578                return;
579            }
580
581            CharSequence summary = getString(R.string.secure_lock_encryption_warning);
582
583            PreferenceScreen screen = getPreferenceScreen();
584            final int preferenceCount = screen.getPreferenceCount();
585            for (int i = 0; i < preferenceCount; i++) {
586                Preference preference = screen.getPreference(i);
587                switch (preference.getKey()) {
588                    case KEY_UNLOCK_SET_PATTERN:
589                    case KEY_UNLOCK_SET_PIN:
590                    case KEY_UNLOCK_SET_PASSWORD:
591                    case KEY_UNLOCK_SET_MANAGED: {
592                        preference.setSummary(summary);
593                    } break;
594                }
595            }
596        }
597
598        protected Intent getLockManagedPasswordIntent(boolean requirePassword, String password) {
599            return mManagedPasswordProvider.createIntent(requirePassword, password);
600        }
601
602        protected Intent getLockPasswordIntent(Context context, int quality,
603                int minLength, final int maxLength,
604                boolean requirePasswordToDecrypt, boolean confirmCredentials, int userId) {
605            return ChooseLockPassword.createIntent(context, quality, minLength,
606                    maxLength, requirePasswordToDecrypt, confirmCredentials, userId);
607        }
608
609        protected Intent getLockPasswordIntent(Context context, int quality,
610                int minLength, final int maxLength,
611                boolean requirePasswordToDecrypt, long challenge, int userId) {
612            return ChooseLockPassword.createIntent(context, quality, minLength,
613                    maxLength, requirePasswordToDecrypt, challenge, userId);
614        }
615
616        protected Intent getLockPasswordIntent(Context context, int quality, int minLength,
617                int maxLength, boolean requirePasswordToDecrypt, String password, int userId) {
618            return ChooseLockPassword.createIntent(context, quality, minLength, maxLength,
619                    requirePasswordToDecrypt, password, userId);
620        }
621
622        protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
623                final boolean confirmCredentials, int userId) {
624            return ChooseLockPattern.createIntent(context, requirePassword,
625                    confirmCredentials, userId);
626        }
627
628        protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
629               long challenge, int userId) {
630            return ChooseLockPattern.createIntent(context, requirePassword, challenge, userId);
631        }
632
633        protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
634                final String pattern, int userId) {
635            return ChooseLockPattern.createIntent(context, requirePassword, pattern, userId);
636        }
637
638        protected Intent getEncryptionInterstitialIntent(Context context, int quality,
639                boolean required, Intent unlockMethodIntent) {
640            return EncryptionInterstitial.createStartIntent(context, quality, required,
641                    unlockMethodIntent);
642        }
643
644        /**
645         * Invokes an activity to change the user's pattern, password or PIN based on given quality
646         * and minimum quality specified by DevicePolicyManager. If quality is
647         * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
648         *
649         * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
650         * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
651         * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
652         */
653        void updateUnlockMethodAndFinish(int quality, boolean disabled) {
654            // Sanity check. We should never get here without confirming user's existing password.
655            if (!mPasswordConfirmed) {
656                throw new IllegalStateException("Tried to update password without confirming it");
657            }
658
659            quality = upgradeQuality(quality);
660            Intent intent = getIntentForUnlockMethod(quality, disabled);
661            if (intent != null) {
662                startActivityForResult(intent,
663                        mIsSetNewPassword && mHasChallenge
664                                ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
665                                : CHOOSE_LOCK_REQUEST);
666                return;
667            }
668
669            if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
670                mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, true, mUserPassword);
671                mChooseLockSettingsHelper.utils().clearLock(mUserPassword, mUserId);
672                mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
673                getActivity().setResult(Activity.RESULT_OK);
674                removeAllFingerprintForUserAndFinish(mUserId);
675            } else {
676                removeAllFingerprintForUserAndFinish(mUserId);
677            }
678        }
679
680        private Intent getIntentForUnlockMethod(int quality, boolean disabled) {
681            Intent intent = null;
682            final Context context = getActivity();
683            if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
684                intent = getLockManagedPasswordIntent(mRequirePassword, mUserPassword);
685            } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
686                int minLength = mDPM.getPasswordMinimumLength(null, mUserId);
687                if (minLength < MIN_PASSWORD_LENGTH) {
688                    minLength = MIN_PASSWORD_LENGTH;
689                }
690                final int maxLength = mDPM.getPasswordMaximumLength(quality);
691                if (mHasChallenge) {
692                    intent = getLockPasswordIntent(context, quality, minLength,
693                            maxLength, mRequirePassword, mChallenge, mUserId);
694                } else {
695                    intent = getLockPasswordIntent(context, quality, minLength,
696                            maxLength, mRequirePassword, mUserPassword, mUserId);
697                }
698            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
699                if (mHasChallenge) {
700                    intent = getLockPatternIntent(context, mRequirePassword,
701                            mChallenge, mUserId);
702                } else {
703                    intent = getLockPatternIntent(context, mRequirePassword,
704                            mUserPassword, mUserId);
705                }
706            }
707            if (intent != null) {
708                intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
709            }
710            return intent;
711        }
712
713        private void removeAllFingerprintForUserAndFinish(final int userId) {
714            if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
715                if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
716                    mFingerprintManager.setActiveUser(userId);
717                    // For the purposes of M and N, groupId is the same as userId.
718                    final int groupId = userId;
719                    Fingerprint finger = new Fingerprint(null, groupId, 0, 0);
720                    mFingerprintManager.remove(finger, userId,
721                            new RemovalCallback() {
722                                @Override
723                                public void onRemovalError(Fingerprint fp, int errMsgId,
724                                        CharSequence errString) {
725                                    Log.e(TAG, String.format(
726                                            "Can't remove fingerprint %d in group %d. Reason: %s",
727                                            fp.getFingerId(), fp.getGroupId(), errString));
728                                    // TODO: need to proceed with the removal of managed profile
729                                    // fingerprints and finish() gracefully.
730                                }
731
732                                @Override
733                                public void onRemovalSucceeded(Fingerprint fp, int remaining) {
734                                    if (remaining == 0) {
735                                        removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
736                                    }
737                                }
738                            });
739                } else {
740                    // No fingerprints in this user, we may also want to delete managed profile
741                    // fingerprints
742                    removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
743                }
744            } else {
745                // The removal callback will call finish, once all fingerprints are removed.
746                // We need to wait for that to occur, otherwise, the UI will still show that
747                // fingerprints exist even though they are (about to) be removed depending on
748                // the race condition.
749                finish();
750            }
751        }
752
753        private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId) {
754            if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
755                mFingerprintManager.setActiveUser(UserHandle.myUserId());
756            }
757            boolean hasChildProfile = false;
758            if (!mUserManager.getUserInfo(parentUserId).isManagedProfile()) {
759                // Current user is primary profile, remove work profile fingerprints if necessary
760                final List<UserInfo> profiles = mUserManager.getProfiles(parentUserId);
761                final int profilesSize = profiles.size();
762                for (int i = 0; i < profilesSize; i++) {
763                    final UserInfo userInfo = profiles.get(i);
764                    if (userInfo.isManagedProfile() && !mLockPatternUtils
765                            .isSeparateProfileChallengeEnabled(userInfo.id)) {
766                        removeAllFingerprintForUserAndFinish(userInfo.id);
767                        hasChildProfile = true;
768                        break;
769                    }
770                }
771            }
772            if (!hasChildProfile) {
773                finish();
774            }
775        }
776
777        @Override
778        public void onDestroy() {
779            super.onDestroy();
780        }
781
782        @Override
783        protected int getHelpResource() {
784            return R.string.help_url_choose_lockscreen;
785        }
786
787        private int getResIdForFactoryResetProtectionWarningTitle() {
788            boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
789            return isProfile ? R.string.unlock_disable_frp_warning_title_profile
790                    : R.string.unlock_disable_frp_warning_title;
791        }
792
793        private int getResIdForFactoryResetProtectionWarningMessage() {
794            final boolean hasFingerprints;
795            if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
796                hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(mUserId);
797            } else {
798                hasFingerprints = false;
799            }
800            boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mUserId);
801            switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
802                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
803                    if (hasFingerprints && isProfile) {
804                        return R.string
805                                .unlock_disable_frp_warning_content_pattern_fingerprint_profile;
806                    } else if (hasFingerprints && !isProfile) {
807                        return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
808                    } else if (isProfile) {
809                        return R.string.unlock_disable_frp_warning_content_pattern_profile;
810                    } else {
811                        return R.string.unlock_disable_frp_warning_content_pattern;
812                    }
813                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
814                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
815                    if (hasFingerprints && isProfile) {
816                        return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile;
817                    } else if (hasFingerprints && !isProfile) {
818                        return R.string.unlock_disable_frp_warning_content_pin_fingerprint;
819                    } else if (isProfile) {
820                        return R.string.unlock_disable_frp_warning_content_pin_profile;
821                    } else {
822                        return R.string.unlock_disable_frp_warning_content_pin;
823                    }
824                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
825                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
826                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
827                case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
828                    if (hasFingerprints && isProfile) {
829                        return R.string
830                                .unlock_disable_frp_warning_content_password_fingerprint_profile;
831                    } else if (hasFingerprints && !isProfile) {
832                        return R.string.unlock_disable_frp_warning_content_password_fingerprint;
833                    } else if (isProfile) {
834                        return R.string.unlock_disable_frp_warning_content_password_profile;
835                    } else {
836                        return R.string.unlock_disable_frp_warning_content_password;
837                    }
838                default:
839                    if (hasFingerprints && isProfile) {
840                        return R.string
841                                .unlock_disable_frp_warning_content_unknown_fingerprint_profile;
842                    } else if (hasFingerprints && !isProfile) {
843                        return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
844                    } else if (isProfile) {
845                        return R.string.unlock_disable_frp_warning_content_unknown_profile;
846                    } else {
847                        return R.string.unlock_disable_frp_warning_content_unknown;
848                    }
849            }
850        }
851
852        private boolean isUnlockMethodSecure(String unlockMethod) {
853            return !(KEY_UNLOCK_SET_OFF.equals(unlockMethod) ||
854                    KEY_UNLOCK_SET_NONE.equals(unlockMethod));
855        }
856
857        private boolean setUnlockMethod(String unlockMethod) {
858            EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
859
860            if (KEY_UNLOCK_SET_OFF.equals(unlockMethod)) {
861                updateUnlockMethodAndFinish(
862                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true /* disabled */ );
863            } else if (KEY_UNLOCK_SET_NONE.equals(unlockMethod)) {
864                updateUnlockMethodAndFinish(
865                        DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false /* disabled */ );
866            } else if (KEY_UNLOCK_SET_MANAGED.equals(unlockMethod)) {
867                maybeEnableEncryption(DevicePolicyManager.PASSWORD_QUALITY_MANAGED, false);
868            } else if (KEY_UNLOCK_SET_PATTERN.equals(unlockMethod)) {
869                maybeEnableEncryption(
870                        DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
871            } else if (KEY_UNLOCK_SET_PIN.equals(unlockMethod)) {
872                maybeEnableEncryption(
873                        DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
874            } else if (KEY_UNLOCK_SET_PASSWORD.equals(unlockMethod)) {
875                maybeEnableEncryption(
876                        DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false);
877            } else {
878                Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
879                return false;
880            }
881            return true;
882        }
883
884        private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
885            int title = getResIdForFactoryResetProtectionWarningTitle();
886            int message = getResIdForFactoryResetProtectionWarningMessage();
887            FactoryResetProtectionWarningDialog dialog =
888                    FactoryResetProtectionWarningDialog.newInstance(
889                            title, message, unlockMethodToSet);
890            dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
891        }
892
893        public static class FactoryResetProtectionWarningDialog extends InstrumentedDialogFragment {
894
895            private static final String ARG_TITLE_RES = "titleRes";
896            private static final String ARG_MESSAGE_RES = "messageRes";
897            private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
898
899            public static FactoryResetProtectionWarningDialog newInstance(
900                    int titleRes, int messageRes, String unlockMethodToSet) {
901                FactoryResetProtectionWarningDialog frag =
902                        new FactoryResetProtectionWarningDialog();
903                Bundle args = new Bundle();
904                args.putInt(ARG_TITLE_RES, titleRes);
905                args.putInt(ARG_MESSAGE_RES, messageRes);
906                args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
907                frag.setArguments(args);
908                return frag;
909            }
910
911            @Override
912            public void show(FragmentManager manager, String tag) {
913                if (manager.findFragmentByTag(tag) == null) {
914                    // Prevent opening multiple dialogs if tapped on button quickly
915                    super.show(manager, tag);
916                }
917            }
918
919            @Override
920            public Dialog onCreateDialog(Bundle savedInstanceState) {
921                final Bundle args = getArguments();
922
923                return new AlertDialog.Builder(getActivity())
924                        .setTitle(args.getInt(ARG_TITLE_RES))
925                        .setMessage(args.getInt(ARG_MESSAGE_RES))
926                        .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
927                                new DialogInterface.OnClickListener() {
928                                    @Override
929                                    public void onClick(DialogInterface dialog, int whichButton) {
930                                        ((ChooseLockGenericFragment) getParentFragment())
931                                                .setUnlockMethod(
932                                                        args.getString(ARG_UNLOCK_METHOD_TO_SET));
933                                    }
934                                }
935                        )
936                        .setNegativeButton(R.string.cancel,
937                                new DialogInterface.OnClickListener() {
938                                    @Override
939                                    public void onClick(DialogInterface dialog, int whichButton) {
940                                        dismiss();
941                                    }
942                                }
943                        )
944                        .create();
945            }
946
947            @Override
948            public int getMetricsCategory() {
949                return MetricsEvent.DIALOG_FRP;
950            }
951        }
952    }
953}
954