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                 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