OSDN Git Service

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