• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import android.accessibilityservice.AccessibilityServiceInfo;
20 import android.app.Activity;
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.app.DialogFragment;
24 import android.app.Fragment;
25 import android.app.FragmentManager;
26 import android.app.admin.DevicePolicyManager;
27 import android.content.Context;
28 import android.content.DialogInterface;
29 import android.content.Intent;
30 import android.os.Bundle;
31 import android.os.Process;
32 import android.os.UserHandle;
33 import android.preference.Preference;
34 import android.preference.PreferenceScreen;
35 import android.security.KeyStore;
36 import android.hardware.fingerprint.Fingerprint;
37 import android.hardware.fingerprint.FingerprintManager;
38 import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
39 import android.util.EventLog;
40 import android.util.Log;
41 import android.view.LayoutInflater;
42 import android.view.View;
43 import android.view.accessibility.AccessibilityManager;
44 import android.widget.ListView;
45 import android.widget.Toast;
46 
47 import com.android.internal.logging.MetricsLogger;
48 import com.android.internal.widget.LockPatternUtils;
49 
50 public class ChooseLockGeneric extends SettingsActivity {
51     public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
52 
53     @Override
getIntent()54     public Intent getIntent() {
55         Intent modIntent = new Intent(super.getIntent());
56         modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
57         return modIntent;
58     }
59 
60     @Override
isValidFragment(String fragmentName)61     protected boolean isValidFragment(String fragmentName) {
62         if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
63         return false;
64     }
65 
getFragmentClass()66     /* package */ Class<? extends Fragment> getFragmentClass() {
67         return ChooseLockGenericFragment.class;
68     }
69 
70     public static class InternalActivity extends ChooseLockGeneric {
71     }
72 
73     public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
74         private static final String TAG = "ChooseLockGenericFragment";
75         private static final int MIN_PASSWORD_LENGTH = 4;
76         private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
77         private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
78         private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
79         private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
80         private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
81         private static final String PASSWORD_CONFIRMED = "password_confirmed";
82         private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
83         public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
84         public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
85         public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality";
86         public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled";
87         public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
88 
89         private static final int CONFIRM_EXISTING_REQUEST = 100;
90         private static final int ENABLE_ENCRYPTION_REQUEST = 101;
91         private static final int CHOOSE_LOCK_REQUEST = 102;
92 
93         private ChooseLockSettingsHelper mChooseLockSettingsHelper;
94         private DevicePolicyManager mDPM;
95         private KeyStore mKeyStore;
96         private boolean mHasChallenge = false;
97         private long mChallenge;
98         private boolean mPasswordConfirmed = false;
99         private boolean mWaitingForConfirmation = false;
100         private int mEncryptionRequestQuality;
101         private boolean mEncryptionRequestDisabled;
102         private boolean mRequirePassword;
103         private boolean mForFingerprint = false;
104         private String mUserPassword;
105         private LockPatternUtils mLockPatternUtils;
106         private FingerprintManager mFingerprintManager;
107         private RemovalCallback mRemovalCallback = new RemovalCallback() {
108 
109             @Override
110             public void onRemovalSucceeded(Fingerprint fingerprint) {
111                 Log.v(TAG, "Fingerprint removed: " + fingerprint.getFingerId());
112                 if (mFingerprintManager.getEnrolledFingerprints().size() == 0) {
113                     finish();
114                 }
115             }
116 
117             @Override
118             public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
119                 Activity activity = getActivity();
120                 if (activity != null) {
121                     Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT);
122                 }
123                 finish();
124             }
125         };
126 
127         @Override
getMetricsCategory()128         protected int getMetricsCategory() {
129             return MetricsLogger.CHOOSE_LOCK_GENERIC;
130         }
131 
132         @Override
onCreate(Bundle savedInstanceState)133         public void onCreate(Bundle savedInstanceState) {
134             super.onCreate(savedInstanceState);
135 
136             mFingerprintManager =
137                 (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE);
138             mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
139             mKeyStore = KeyStore.getInstance();
140             mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
141             mLockPatternUtils = new LockPatternUtils(getActivity());
142 
143             // Defaults to needing to confirm credentials
144             final boolean confirmCredentials = getActivity().getIntent()
145                 .getBooleanExtra(CONFIRM_CREDENTIALS, true);
146             if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
147                 mPasswordConfirmed = !confirmCredentials;
148             }
149 
150             mHasChallenge = getActivity().getIntent().getBooleanExtra(
151                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
152             mChallenge = getActivity().getIntent().getLongExtra(
153                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
154             mForFingerprint = getActivity().getIntent().getBooleanExtra(
155                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
156 
157             if (savedInstanceState != null) {
158                 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
159                 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
160                 mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY);
161                 mEncryptionRequestDisabled = savedInstanceState.getBoolean(
162                         ENCRYPT_REQUESTED_DISABLED);
163             }
164 
165             if (mPasswordConfirmed) {
166                 updatePreferencesOrFinish();
167             } else if (!mWaitingForConfirmation) {
168                 ChooseLockSettingsHelper helper =
169                         new ChooseLockSettingsHelper(this.getActivity(), this);
170                 if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
171                         getString(R.string.unlock_set_unlock_launch_picker_title), true)) {
172                     mPasswordConfirmed = true; // no password set, so no need to confirm
173                     updatePreferencesOrFinish();
174                 } else {
175                     mWaitingForConfirmation = true;
176                 }
177             }
178         }
179 
180         @Override
onViewCreated(View view, Bundle savedInstanceState)181         public void onViewCreated(View view, Bundle savedInstanceState) {
182             super.onViewCreated(view, savedInstanceState);
183             if (mForFingerprint) {
184                 final LayoutInflater inflater = LayoutInflater.from(getContext());
185                 final ListView listView = getListView();
186                 final View fingerprintHeader = inflater.inflate(
187                         R.layout.choose_lock_generic_fingerprint_header, listView, false);
188                 listView.addHeaderView(fingerprintHeader, null, false);
189             }
190         }
191 
192         @Override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)193         public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
194                 Preference preference) {
195             final String key = preference.getKey();
196 
197             if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(UserHandle.myUserId())) {
198                 // Show the disabling FRP warning only when the user is switching from a secure
199                 // unlock method to an insecure one
200                 showFactoryResetProtectionWarningDialog(key);
201                 return true;
202             } else {
203                 return setUnlockMethod(key);
204             }
205         }
206 
207         /**
208          * If the device has encryption already enabled, then ask the user if they
209          * also want to encrypt the phone with this password.
210          *
211          * @param quality
212          * @param disabled
213          */
214         // TODO: why does this take disabled, its always called with a quality higher than
215         // what makes sense with disabled == true
maybeEnableEncryption(int quality, boolean disabled)216         private void maybeEnableEncryption(int quality, boolean disabled) {
217             DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
218             if (Process.myUserHandle().isOwner() && LockPatternUtils.isDeviceEncryptionEnabled()
219                     && !dpm.getDoNotAskCredentialsOnBoot()) {
220                 mEncryptionRequestQuality = quality;
221                 mEncryptionRequestDisabled = disabled;
222                 final Context context = getActivity();
223                 // If accessibility is enabled and the user hasn't seen this dialog before, set the
224                 // default state to agree with that which is compatible with accessibility
225                 // (password not required).
226                 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
227                 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
228                 Intent intent = getEncryptionInterstitialIntent(context, quality, required);
229                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
230                         mForFingerprint);
231                 startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST);
232             } else {
233                 mRequirePassword = false; // device encryption not enabled or not device owner.
234                 updateUnlockMethodAndFinish(quality, disabled);
235             }
236         }
237 
238         @Override
onActivityResult(int requestCode, int resultCode, Intent data)239         public void onActivityResult(int requestCode, int resultCode, Intent data) {
240             super.onActivityResult(requestCode, resultCode, data);
241             mWaitingForConfirmation = false;
242             if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
243                 mPasswordConfirmed = true;
244                 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
245                 updatePreferencesOrFinish();
246             } else if (requestCode == ENABLE_ENCRYPTION_REQUEST
247                     && resultCode == Activity.RESULT_OK) {
248                 mRequirePassword = data.getBooleanExtra(
249                         EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
250                 updateUnlockMethodAndFinish(mEncryptionRequestQuality, mEncryptionRequestDisabled);
251             } else if (requestCode == CHOOSE_LOCK_REQUEST) {
252                 getActivity().setResult(resultCode, data);
253                 finish();
254             } else {
255                 getActivity().setResult(Activity.RESULT_CANCELED);
256                 finish();
257             }
258         }
259 
260         @Override
onSaveInstanceState(Bundle outState)261         public void onSaveInstanceState(Bundle outState) {
262             super.onSaveInstanceState(outState);
263             // Saved so we don't force user to re-enter their password if configuration changes
264             outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
265             outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
266             outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality);
267             outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled);
268         }
269 
updatePreferencesOrFinish()270         private void updatePreferencesOrFinish() {
271             Intent intent = getActivity().getIntent();
272             int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
273             if (quality == -1) {
274                 // If caller didn't specify password quality, show UI and allow the user to choose.
275                 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
276                 quality = upgradeQuality(quality);
277                 final boolean hideDisabledPrefs = intent.getBooleanExtra(
278                         HIDE_DISABLED_PREFS, false);
279                 final PreferenceScreen prefScreen = getPreferenceScreen();
280                 if (prefScreen != null) {
281                     prefScreen.removeAll();
282                 }
283                 addPreferencesFromResource(R.xml.security_settings_picker);
284                 disableUnusablePreferences(quality, hideDisabledPrefs);
285                 updateCurrentPreference();
286                 updatePreferenceSummaryIfNeeded();
287             } else {
288                 updateUnlockMethodAndFinish(quality, false);
289             }
290         }
291 
updateCurrentPreference()292         private void updateCurrentPreference() {
293             String currentKey = getKeyForCurrent();
294             Preference preference = findPreference(currentKey);
295             if (preference != null) {
296                 preference.setSummary(R.string.current_screen_lock);
297             }
298         }
299 
getKeyForCurrent()300         private String getKeyForCurrent() {
301             if (mLockPatternUtils.isLockScreenDisabled(UserHandle.myUserId())) {
302                 return KEY_UNLOCK_SET_OFF;
303             }
304             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId())) {
305                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
306                     return KEY_UNLOCK_SET_PATTERN;
307                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
308                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
309                     return KEY_UNLOCK_SET_PIN;
310                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
311                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
312                     return KEY_UNLOCK_SET_PASSWORD;
313                 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
314                     return KEY_UNLOCK_SET_NONE;
315             }
316             return null;
317         }
318 
319         /** increases the quality if necessary */
upgradeQuality(int quality)320         private int upgradeQuality(int quality) {
321             quality = upgradeQualityForDPM(quality);
322             return quality;
323         }
324 
upgradeQualityForDPM(int quality)325         private int upgradeQualityForDPM(int quality) {
326             // Compare min allowed password quality
327             int minQuality = mDPM.getPasswordQuality(null);
328             if (quality < minQuality) {
329                 quality = minQuality;
330             }
331             return quality;
332         }
333 
334         /***
335          * Disables preferences that are less secure than required quality. The actual
336          * implementation is in disableUnusablePreferenceImpl.
337          *
338          * @param quality the requested quality.
339          * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
340          * they're not shown at all.
341          */
disableUnusablePreferences(final int quality, boolean hideDisabledPrefs)342         protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
343             disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
344         }
345 
346         /***
347          * Disables preferences that are less secure than required quality.
348          *
349          * @param quality the requested quality.
350          * @param hideDisabled whether to hide disable screen lock options.
351          */
disableUnusablePreferencesImpl(final int quality, boolean hideDisabled)352         protected void disableUnusablePreferencesImpl(final int quality,
353                 boolean hideDisabled) {
354             final PreferenceScreen entries = getPreferenceScreen();
355 
356             for (int i = entries.getPreferenceCount() - 1; i >= 0; --i) {
357                 Preference pref = entries.getPreference(i);
358                 if (pref instanceof PreferenceScreen) {
359                     final String key = pref.getKey();
360                     boolean enabled = true;
361                     boolean visible = true;
362                     if (KEY_UNLOCK_SET_OFF.equals(key)) {
363                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
364                         if (getResources().getBoolean(R.bool.config_hide_none_security_option)) {
365                             enabled = false;
366                             visible = false;
367                         }
368                     } else if (KEY_UNLOCK_SET_NONE.equals(key)) {
369                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
370                     } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
371                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
372                     } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
373                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
374                     } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
375                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
376                     }
377                     if (hideDisabled) {
378                         visible = enabled;
379                     }
380                     if (!visible) {
381                         entries.removePreference(pref);
382                     } else if (!enabled) {
383                         pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
384                         pref.setEnabled(false);
385                     }
386                 }
387             }
388         }
389 
updatePreferenceSummaryIfNeeded()390         private void updatePreferenceSummaryIfNeeded() {
391             if (LockPatternUtils.isDeviceEncrypted()) {
392                 return;
393             }
394 
395             if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
396                     AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
397                 return;
398             }
399 
400             CharSequence summary = getString(R.string.secure_lock_encryption_warning);
401 
402             PreferenceScreen screen = getPreferenceScreen();
403             final int preferenceCount = screen.getPreferenceCount();
404             for (int i = 0; i < preferenceCount; i++) {
405                 Preference preference = screen.getPreference(i);
406                 switch (preference.getKey()) {
407                     case KEY_UNLOCK_SET_PATTERN:
408                     case KEY_UNLOCK_SET_PIN:
409                     case KEY_UNLOCK_SET_PASSWORD: {
410                         preference.setSummary(summary);
411                     } break;
412                 }
413             }
414         }
415 
getLockPasswordIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, boolean confirmCredentials)416         protected Intent getLockPasswordIntent(Context context, int quality,
417                 int minLength, final int maxLength,
418                 boolean requirePasswordToDecrypt, boolean confirmCredentials) {
419             return ChooseLockPassword.createIntent(context, quality, minLength,
420                     maxLength, requirePasswordToDecrypt, confirmCredentials);
421         }
422 
getLockPasswordIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, long challenge)423         protected Intent getLockPasswordIntent(Context context, int quality,
424                 int minLength, final int maxLength,
425                 boolean requirePasswordToDecrypt, long challenge) {
426             return ChooseLockPassword.createIntent(context, quality, minLength,
427                     maxLength, requirePasswordToDecrypt, challenge);
428         }
429 
getLockPasswordIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, String password)430         protected Intent getLockPasswordIntent(Context context, int quality, int minLength,
431                 final int maxLength, boolean requirePasswordToDecrypt, String password) {
432             return ChooseLockPassword.createIntent(context, quality, minLength, maxLength,
433                     requirePasswordToDecrypt, password);
434         }
435 
getLockPatternIntent(Context context, final boolean requirePassword, final boolean confirmCredentials)436         protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
437                 final boolean confirmCredentials) {
438             return ChooseLockPattern.createIntent(context, requirePassword,
439                     confirmCredentials);
440         }
441 
getLockPatternIntent(Context context, final boolean requirePassword, long challenge)442         protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
443                long challenge) {
444             return ChooseLockPattern.createIntent(context, requirePassword, challenge);
445         }
446 
getLockPatternIntent(Context context, final boolean requirePassword, final String pattern)447         protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
448                 final String pattern) {
449             return ChooseLockPattern.createIntent(context, requirePassword, pattern);
450         }
451 
getEncryptionInterstitialIntent(Context context, int quality, boolean required)452         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
453                 boolean required) {
454             return EncryptionInterstitial.createStartIntent(context, quality, required);
455         }
456 
457         /**
458          * Invokes an activity to change the user's pattern, password or PIN based on given quality
459          * and minimum quality specified by DevicePolicyManager. If quality is
460          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
461          *
462          * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
463          * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
464          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
465          */
updateUnlockMethodAndFinish(int quality, boolean disabled)466         void updateUnlockMethodAndFinish(int quality, boolean disabled) {
467             // Sanity check. We should never get here without confirming user's existing password.
468             if (!mPasswordConfirmed) {
469                 throw new IllegalStateException("Tried to update password without confirming it");
470             }
471 
472             quality = upgradeQuality(quality);
473 
474             final Context context = getActivity();
475             if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
476                 int minLength = mDPM.getPasswordMinimumLength(null);
477                 if (minLength < MIN_PASSWORD_LENGTH) {
478                     minLength = MIN_PASSWORD_LENGTH;
479                 }
480                 final int maxLength = mDPM.getPasswordMaximumLength(quality);
481                 Intent intent;
482                 if (mHasChallenge) {
483                     intent = getLockPasswordIntent(context, quality, minLength,
484                             maxLength, mRequirePassword, mChallenge);
485                 } else {
486                     intent = getLockPasswordIntent(context, quality, minLength,
487                         maxLength, mRequirePassword, mUserPassword);
488                 }
489                 startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
490             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
491                 Intent intent;
492                 if (mHasChallenge) {
493                     intent = getLockPatternIntent(context, mRequirePassword,
494                         mChallenge);
495                 } else {
496                     intent = getLockPatternIntent(context, mRequirePassword,
497                         mUserPassword);
498                 }
499                 startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
500             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
501                 mChooseLockSettingsHelper.utils().clearLock(UserHandle.myUserId());
502                 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled,
503                         UserHandle.myUserId());
504                 removeAllFingerprintTemplatesAndFinish();
505                 getActivity().setResult(Activity.RESULT_OK);
506             } else {
507                 removeAllFingerprintTemplatesAndFinish();
508             }
509         }
510 
removeAllFingerprintTemplatesAndFinish()511         private void removeAllFingerprintTemplatesAndFinish() {
512             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()
513                     && mFingerprintManager.getEnrolledFingerprints().size() > 0) {
514                 mFingerprintManager.remove(new Fingerprint(null, 0, 0, 0), mRemovalCallback);
515             } else {
516                 finish();
517             }
518         }
519 
520         @Override
onDestroy()521         public void onDestroy() {
522             super.onDestroy();
523         }
524 
525         @Override
getHelpResource()526         protected int getHelpResource() {
527             return R.string.help_url_choose_lockscreen;
528         }
529 
getResIdForFactoryResetProtectionWarningMessage()530         private int getResIdForFactoryResetProtectionWarningMessage() {
531             boolean hasFingerprints = mFingerprintManager.hasEnrolledFingerprints();
532             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(UserHandle.myUserId())) {
533                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
534                     return hasFingerprints
535                             ? R.string.unlock_disable_frp_warning_content_pattern_fingerprint
536                             : R.string.unlock_disable_frp_warning_content_pattern;
537                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
538                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
539                     return hasFingerprints
540                             ? R.string.unlock_disable_frp_warning_content_pin_fingerprint
541                             : R.string.unlock_disable_frp_warning_content_pin;
542                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
543                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
544                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
545                     return hasFingerprints
546                             ? R.string.unlock_disable_frp_warning_content_password_fingerprint
547                             : R.string.unlock_disable_frp_warning_content_password;
548                 default:
549                     return hasFingerprints
550                             ? R.string.unlock_disable_frp_warning_content_unknown_fingerprint
551                             : R.string.unlock_disable_frp_warning_content_unknown;
552             }
553         }
554 
isUnlockMethodSecure(String unlockMethod)555         private boolean isUnlockMethodSecure(String unlockMethod) {
556             return !(KEY_UNLOCK_SET_OFF.equals(unlockMethod) ||
557                     KEY_UNLOCK_SET_NONE.equals(unlockMethod));
558         }
559 
setUnlockMethod(String unlockMethod)560         private boolean setUnlockMethod(String unlockMethod) {
561             EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
562 
563             if (KEY_UNLOCK_SET_OFF.equals(unlockMethod)) {
564                 updateUnlockMethodAndFinish(
565                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true /* disabled */ );
566             } else if (KEY_UNLOCK_SET_NONE.equals(unlockMethod)) {
567                 updateUnlockMethodAndFinish(
568                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false /* disabled */ );
569             } else if (KEY_UNLOCK_SET_PATTERN.equals(unlockMethod)) {
570                 maybeEnableEncryption(
571                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
572             } else if (KEY_UNLOCK_SET_PIN.equals(unlockMethod)) {
573                 maybeEnableEncryption(
574                         DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
575             } else if (KEY_UNLOCK_SET_PASSWORD.equals(unlockMethod)) {
576                 maybeEnableEncryption(
577                         DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false);
578             } else {
579                 Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
580                 return false;
581             }
582             return true;
583         }
584 
showFactoryResetProtectionWarningDialog(String unlockMethodToSet)585         private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
586             int message = getResIdForFactoryResetProtectionWarningMessage();
587             FactoryResetProtectionWarningDialog dialog =
588                     FactoryResetProtectionWarningDialog.newInstance(message, unlockMethodToSet);
589             dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
590         }
591 
592         public static class FactoryResetProtectionWarningDialog extends DialogFragment {
593 
594             private static final String ARG_MESSAGE_RES = "messageRes";
595             private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
596 
newInstance(int messageRes, String unlockMethodToSet)597             public static FactoryResetProtectionWarningDialog newInstance(int messageRes,
598                     String unlockMethodToSet) {
599                 FactoryResetProtectionWarningDialog frag =
600                         new FactoryResetProtectionWarningDialog();
601                 Bundle args = new Bundle();
602                 args.putInt(ARG_MESSAGE_RES, messageRes);
603                 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
604                 frag.setArguments(args);
605                 return frag;
606             }
607 
608             @Override
show(FragmentManager manager, String tag)609             public void show(FragmentManager manager, String tag) {
610                 if (manager.findFragmentByTag(tag) == null) {
611                     // Prevent opening multiple dialogs if tapped on button quickly
612                     super.show(manager, tag);
613                 }
614             }
615 
616             @Override
onCreateDialog(Bundle savedInstanceState)617             public Dialog onCreateDialog(Bundle savedInstanceState) {
618                 final Bundle args = getArguments();
619 
620                 return new AlertDialog.Builder(getActivity())
621                         .setTitle(R.string.unlock_disable_frp_warning_title)
622                         .setMessage(args.getInt(ARG_MESSAGE_RES))
623                         .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
624                                 new DialogInterface.OnClickListener() {
625                                     @Override
626                                     public void onClick(DialogInterface dialog, int whichButton) {
627                                         ((ChooseLockGenericFragment) getParentFragment())
628                                                 .setUnlockMethod(
629                                                         args.getString(ARG_UNLOCK_METHOD_TO_SET));
630                                     }
631                                 }
632                         )
633                         .setNegativeButton(R.string.cancel,
634                                 new DialogInterface.OnClickListener() {
635                                     @Override
636                                     public void onClick(DialogInterface dialog, int whichButton) {
637                                         dismiss();
638                                     }
639                                 }
640                         )
641                         .create();
642             }
643         }
644     }
645 }
646