Home | History | Annotate | Download | only in password
      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 
     17 package com.android.settings.password;
     18 
     19 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD;
     20 import static android.app.admin.DevicePolicyManager.ACTION_SET_NEW_PASSWORD;
     21 
     22 import static com.android.settings.password.ChooseLockPassword.ChooseLockPasswordFragment.RESULT_FINISHED;
     23 
     24 import android.accessibilityservice.AccessibilityServiceInfo;
     25 import android.app.Activity;
     26 import android.app.AlertDialog;
     27 import android.app.Dialog;
     28 import android.app.Fragment;
     29 import android.app.FragmentManager;
     30 import android.app.admin.DevicePolicyManager;
     31 import android.content.Context;
     32 import android.content.Intent;
     33 import android.content.pm.UserInfo;
     34 import android.hardware.fingerprint.Fingerprint;
     35 import android.hardware.fingerprint.FingerprintManager;
     36 import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
     37 import android.os.Bundle;
     38 import android.os.UserHandle;
     39 import android.os.UserManager;
     40 import android.os.storage.StorageManager;
     41 import android.security.KeyStore;
     42 import android.support.annotation.StringRes;
     43 import android.support.v7.preference.Preference;
     44 import android.support.v7.preference.PreferenceScreen;
     45 import android.text.TextUtils;
     46 import android.util.EventLog;
     47 import android.util.Log;
     48 import android.view.accessibility.AccessibilityManager;
     49 import android.widget.TextView;
     50 
     51 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     52 import com.android.internal.widget.LockPatternUtils;
     53 import com.android.settings.EncryptionInterstitial;
     54 import com.android.settings.EventLogTags;
     55 import com.android.settings.R;
     56 import com.android.settings.SettingsActivity;
     57 import com.android.settings.SettingsPreferenceFragment;
     58 import com.android.settings.Utils;
     59 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
     60 import com.android.settings.fingerprint.FingerprintEnrollBase;
     61 import com.android.settings.fingerprint.FingerprintEnrollFindSensor;
     62 import com.android.settingslib.RestrictedLockUtils;
     63 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
     64 import com.android.settingslib.RestrictedPreference;
     65 
     66 import java.util.List;
     67 
     68 public 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                 boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword;
    240                 if (skipConfirmation
    241                         || !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
    242                         getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
    243                     mPasswordConfirmed = true; // no password set, so no need to confirm
    244                     updatePreferencesOrFinish(savedInstanceState != null);
    245                 } else {
    246                     mWaitingForConfirmation = true;
    247                 }
    248             }
    249             addHeaderView();
    250         }
    251 
    252         protected void addHeaderView() {
    253             if (mForFingerprint) {
    254                 setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
    255                 if (mIsSetNewPassword) {
    256                     ((TextView) getHeaderView().findViewById(R.id.fingerprint_header_description))
    257                             .setText(R.string.fingerprint_unlock_title);
    258                 }
    259             }
    260         }
    261 
    262         @Override
    263         public boolean onPreferenceTreeClick(Preference preference) {
    264             final String key = preference.getKey();
    265 
    266             if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
    267                 // Show the disabling FRP warning only when the user is switching from a secure
    268                 // unlock method to an insecure one
    269                 showFactoryResetProtectionWarningDialog(key);
    270                 return true;
    271             } else if (KEY_SKIP_FINGERPRINT.equals(key)) {
    272                 Intent chooseLockGenericIntent = new Intent(getActivity(),
    273                     ChooseLockGeneric.InternalActivity.class);
    274                 chooseLockGenericIntent.setAction(getIntent().getAction());
    275                 // Forward the target user id to  ChooseLockGeneric.
    276                 chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
    277                 chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
    278                 if (mUserPassword != null) {
    279                     chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
    280                             mUserPassword);
    281                 }
    282                 startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
    283                 return true;
    284             } else {
    285                 return setUnlockMethod(key);
    286             }
    287         }
    288 
    289         /**
    290          * If the device has encryption already enabled, then ask the user if they
    291          * also want to encrypt the phone with this password.
    292          *
    293          * @param quality
    294          * @param disabled
    295          */
    296         // TODO: why does this take disabled, its always called with a quality higher than
    297         // what makes sense with disabled == true
    298         private void maybeEnableEncryption(int quality, boolean disabled) {
    299             DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
    300             if (UserManager.get(getActivity()).isAdminUser()
    301                     && mUserId == UserHandle.myUserId()
    302                     && LockPatternUtils.isDeviceEncryptionEnabled()
    303                     && !LockPatternUtils.isFileEncryptionEnabled()
    304                     && !dpm.getDoNotAskCredentialsOnBoot()) {
    305                 mEncryptionRequestQuality = quality;
    306                 mEncryptionRequestDisabled = disabled;
    307                 // Get the intent that the encryption interstitial should start for creating
    308                 // the new unlock method.
    309                 Intent unlockMethodIntent = getIntentForUnlockMethod(quality);
    310                 unlockMethodIntent.putExtra(
    311                         ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
    312                         mForChangeCredRequiredForBoot);
    313                 final Context context = getActivity();
    314                 // If accessibility is enabled and the user hasn't seen this dialog before, set the
    315                 // default state to agree with that which is compatible with accessibility
    316                 // (password not required).
    317                 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
    318                 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
    319                 Intent intent = getEncryptionInterstitialIntent(context, quality, required,
    320                         unlockMethodIntent);
    321                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
    322                         mForFingerprint);
    323                 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
    324                 startActivityForResult(
    325                         intent,
    326                         mIsSetNewPassword && mHasChallenge
    327                                 ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
    328                                 : ENABLE_ENCRYPTION_REQUEST);
    329             } else {
    330                 if (mForChangeCredRequiredForBoot) {
    331                     // Welp, couldn't change it. Oh well.
    332                     finish();
    333                     return;
    334                 }
    335                 updateUnlockMethodAndFinish(quality, disabled, false /* chooseLockSkipped */);
    336             }
    337         }
    338 
    339         @Override
    340         public void onActivityResult(int requestCode, int resultCode, Intent data) {
    341             super.onActivityResult(requestCode, resultCode, data);
    342             mWaitingForConfirmation = false;
    343             if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
    344                 mPasswordConfirmed = true;
    345                 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
    346                 updatePreferencesOrFinish(false /* isRecreatingActivity */);
    347                 if (mForChangeCredRequiredForBoot) {
    348                     if (!TextUtils.isEmpty(mUserPassword)) {
    349                         maybeEnableEncryption(
    350                                 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
    351                     } else {
    352                         finish();
    353                     }
    354                 }
    355             } else if (requestCode == CHOOSE_LOCK_REQUEST
    356                     || requestCode == ENABLE_ENCRYPTION_REQUEST) {
    357                 if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) {
    358                     getActivity().setResult(resultCode, data);
    359                     finish();
    360                 } else {
    361                     // If PASSWORD_TYPE_KEY is set, this activity is used as a trampoline to start
    362                     // the actual password enrollment. If the result is canceled, which means the
    363                     // user pressed back, finish the activity with result canceled.
    364                     int quality = getIntent().getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
    365                     if (quality != -1) {
    366                         getActivity().setResult(RESULT_CANCELED, data);
    367                         finish();
    368                     }
    369                 }
    370             } else if (requestCode == CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
    371                     && resultCode == FingerprintEnrollBase.RESULT_FINISHED) {
    372                 Intent intent = getFindSensorIntent(getActivity());
    373                 if (data != null) {
    374                     intent.putExtras(data.getExtras());
    375                 }
    376                 // Forward the target user id to fingerprint setup page.
    377                 intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
    378                 startActivity(intent);
    379                 finish();
    380             } else if (requestCode == SKIP_FINGERPRINT_REQUEST) {
    381                 if (resultCode != RESULT_CANCELED) {
    382                     getActivity().setResult(
    383                             resultCode == RESULT_FINISHED ? RESULT_OK : resultCode, data);
    384                     finish();
    385                 }
    386             } else {
    387                 getActivity().setResult(Activity.RESULT_CANCELED);
    388                 finish();
    389             }
    390             if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
    391                 finish();
    392             }
    393         }
    394 
    395         protected Intent getFindSensorIntent(Context context) {
    396             return new Intent(context, FingerprintEnrollFindSensor.class);
    397         }
    398 
    399         @Override
    400         public void onSaveInstanceState(Bundle outState) {
    401             super.onSaveInstanceState(outState);
    402             // Saved so we don't force user to re-enter their password if configuration changes
    403             outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
    404             outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
    405             outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality);
    406             outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled);
    407             if (mUserPassword != null) {
    408                 outState.putString(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mUserPassword);
    409             }
    410         }
    411 
    412         private void updatePreferencesOrFinish(boolean isRecreatingActivity) {
    413             Intent intent = getActivity().getIntent();
    414             int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
    415             if (quality == -1) {
    416                 // If caller didn't specify password quality, show UI and allow the user to choose.
    417                 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
    418                 quality = mController.upgradeQuality(quality);
    419                 final boolean hideDisabledPrefs = intent.getBooleanExtra(
    420                         HIDE_DISABLED_PREFS, false);
    421                 final PreferenceScreen prefScreen = getPreferenceScreen();
    422                 if (prefScreen != null) {
    423                     prefScreen.removeAll();
    424                 }
    425                 addPreferences();
    426                 disableUnusablePreferences(quality, hideDisabledPrefs);
    427                 updatePreferenceText();
    428                 updateCurrentPreference();
    429                 updatePreferenceSummaryIfNeeded();
    430             } else if (!isRecreatingActivity) {
    431                 // Don't start the activity again if we are recreated for configuration change
    432                 updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */);
    433             }
    434         }
    435 
    436         protected void addPreferences() {
    437             addPreferencesFromResource(R.xml.security_settings_picker);
    438 
    439             // Used for testing purposes
    440             findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
    441             findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
    442             findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin);
    443             findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
    444         }
    445 
    446         private void updatePreferenceText() {
    447             if (mForFingerprint) {
    448                 setPreferenceTitle(ScreenLockType.PATTERN,
    449                         R.string.fingerprint_unlock_set_unlock_pattern);
    450                 setPreferenceTitle(ScreenLockType.PIN, R.string.fingerprint_unlock_set_unlock_pin);
    451                 setPreferenceTitle(ScreenLockType.PASSWORD,
    452                         R.string.fingerprint_unlock_set_unlock_password);
    453             }
    454 
    455             if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
    456                 setPreferenceTitle(ScreenLockType.MANAGED,
    457                         mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
    458             } else {
    459                 removePreference(ScreenLockType.MANAGED.preferenceKey);
    460             }
    461 
    462             if (!(mForFingerprint && mIsSetNewPassword)) {
    463                 removePreference(KEY_SKIP_FINGERPRINT);
    464             }
    465         }
    466 
    467         private void setPreferenceTitle(ScreenLockType lock, @StringRes int title) {
    468             Preference preference = findPreference(lock.preferenceKey);
    469             if (preference != null) {
    470                 preference.setTitle(title);
    471             }
    472         }
    473 
    474         private void setPreferenceTitle(ScreenLockType lock, CharSequence title) {
    475             Preference preference = findPreference(lock.preferenceKey);
    476             if (preference != null) {
    477                 preference.setTitle(title);
    478             }
    479         }
    480 
    481         private void setPreferenceSummary(ScreenLockType lock, @StringRes int summary) {
    482             Preference preference = findPreference(lock.preferenceKey);
    483             if (preference != null) {
    484                 preference.setSummary(summary);
    485             }
    486         }
    487 
    488         private void updateCurrentPreference() {
    489             String currentKey = getKeyForCurrent();
    490             Preference preference = findPreference(currentKey);
    491             if (preference != null) {
    492                 preference.setSummary(R.string.current_screen_lock);
    493             }
    494         }
    495 
    496         private String getKeyForCurrent() {
    497             final int credentialOwner = UserManager.get(getContext())
    498                     .getCredentialOwnerProfile(mUserId);
    499             if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
    500                 return ScreenLockType.NONE.preferenceKey;
    501             }
    502             ScreenLockType lock =
    503                     ScreenLockType.fromQuality(
    504                             mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner));
    505             return lock != null ? lock.preferenceKey : null;
    506         }
    507 
    508         /***
    509          * Disables preferences that are less secure than required quality. The actual
    510          * implementation is in disableUnusablePreferenceImpl.
    511          *
    512          * @param quality the requested quality.
    513          * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
    514          * they're not shown at all.
    515          */
    516         protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
    517             disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
    518         }
    519 
    520         /***
    521          * Disables preferences that are less secure than required quality.
    522          *
    523          * @param quality the requested quality.
    524          * @param hideDisabled whether to hide disable screen lock options.
    525          */
    526         protected void disableUnusablePreferencesImpl(final int quality,
    527                 boolean hideDisabled) {
    528             final PreferenceScreen entries = getPreferenceScreen();
    529 
    530             int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId);
    531             EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
    532                     getActivity(), mUserId);
    533 
    534             for (ScreenLockType lock : ScreenLockType.values()) {
    535                 String key = lock.preferenceKey;
    536                 Preference pref = findPreference(key);
    537                 if (pref instanceof RestrictedPreference) {
    538                     boolean visible = mController.isScreenLockVisible(lock);
    539                     boolean enabled = mController.isScreenLockEnabled(lock, quality);
    540                     boolean disabledByAdmin =
    541                             mController.isScreenLockDisabledByAdmin(lock, adminEnforcedQuality);
    542                     if (hideDisabled) {
    543                         visible = visible && enabled;
    544                     }
    545                     if (!visible) {
    546                         entries.removePreference(pref);
    547                     } else if (disabledByAdmin && enforcedAdmin != null) {
    548                         ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
    549                     } else if (!enabled) {
    550                         // we need to setDisabledByAdmin to null first to disable the padlock
    551                         // in case it was set earlier.
    552                         ((RestrictedPreference) pref).setDisabledByAdmin(null);
    553                         pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
    554                         pref.setEnabled(false);
    555                     } else {
    556                         ((RestrictedPreference) pref).setDisabledByAdmin(null);
    557                     }
    558                 }
    559             }
    560         }
    561 
    562         private void updatePreferenceSummaryIfNeeded() {
    563             // On a default block encrypted device with accessibility, add a warning
    564             // that your data is not credential encrypted
    565             if (!StorageManager.isBlockEncrypted()) {
    566                 return;
    567             }
    568 
    569             if (StorageManager.isNonDefaultBlockEncrypted()) {
    570                 return;
    571             }
    572 
    573             if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
    574                     AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
    575                 return;
    576             }
    577 
    578             setPreferenceSummary(ScreenLockType.PATTERN, R.string.secure_lock_encryption_warning);
    579             setPreferenceSummary(ScreenLockType.PIN, R.string.secure_lock_encryption_warning);
    580             setPreferenceSummary(ScreenLockType.PASSWORD, R.string.secure_lock_encryption_warning);
    581             setPreferenceSummary(ScreenLockType.MANAGED, R.string.secure_lock_encryption_warning);
    582         }
    583 
    584         protected Intent getLockManagedPasswordIntent(String password) {
    585             return mManagedPasswordProvider.createIntent(false, password);
    586         }
    587 
    588         protected Intent getLockPasswordIntent(int quality, int minLength, int maxLength) {
    589             ChooseLockPassword.IntentBuilder builder =
    590                     new ChooseLockPassword.IntentBuilder(getContext())
    591                             .setPasswordQuality(quality)
    592                             .setPasswordLengthRange(minLength, maxLength)
    593                             .setForFingerprint(mForFingerprint)
    594                             .setUserId(mUserId);
    595             if (mHasChallenge) {
    596                 builder.setChallenge(mChallenge);
    597             }
    598             if (mUserPassword != null) {
    599                 builder.setPassword(mUserPassword);
    600             }
    601             return builder.build();
    602         }
    603 
    604         protected Intent getLockPatternIntent() {
    605             ChooseLockPattern.IntentBuilder builder =
    606                     new ChooseLockPattern.IntentBuilder(getContext())
    607                             .setForFingerprint(mForFingerprint)
    608                             .setUserId(mUserId);
    609             if (mHasChallenge) {
    610                 builder.setChallenge(mChallenge);
    611             }
    612             if (mUserPassword != null) {
    613                 builder.setPattern(mUserPassword);
    614             }
    615             return builder.build();
    616         }
    617 
    618         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
    619                 boolean required, Intent unlockMethodIntent) {
    620             return EncryptionInterstitial.createStartIntent(context, quality, required,
    621                     unlockMethodIntent);
    622         }
    623 
    624         /**
    625          * Invokes an activity to change the user's pattern, password or PIN based on given quality
    626          * and minimum quality specified by DevicePolicyManager. If quality is
    627          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
    628          *
    629          * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
    630          * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
    631          * @param chooseLockSkipped whether or not this activity is skipped. This is true when this
    632          * activity was not shown to the user at all, instead automatically proceeding based on
    633          * the given intent extras, typically {@link LockPatternUtils#PASSWORD_TYPE_KEY}.
    634          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
    635          */
    636         void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) {
    637             // Sanity check. We should never get here without confirming user's existing password.
    638             if (!mPasswordConfirmed) {
    639                 throw new IllegalStateException("Tried to update password without confirming it");
    640             }
    641 
    642             quality = mController.upgradeQuality(quality);
    643             Intent intent = getIntentForUnlockMethod(quality);
    644             if (intent != null) {
    645                 if (getIntent().getBooleanExtra(EXTRA_SHOW_OPTIONS_BUTTON, false)) {
    646                     intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped);
    647                 }
    648                 intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras());
    649                 startActivityForResult(intent,
    650                         mIsSetNewPassword && mHasChallenge
    651                                 ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
    652                                 : CHOOSE_LOCK_REQUEST);
    653                 return;
    654             }
    655 
    656             if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    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         public 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