OSDN Git Service

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