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