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.content.pm.UserInfo;
31 import android.hardware.fingerprint.Fingerprint;
32 import android.hardware.fingerprint.FingerprintManager;
33 import android.hardware.fingerprint.FingerprintManager.RemovalCallback;
34 import android.os.Bundle;
35 import android.os.Process;
36 import android.os.UserHandle;
37 import android.os.UserManager;
38 import android.os.storage.StorageManager;
39 import android.security.KeyStore;
40 import android.support.v7.preference.Preference;
41 import android.support.v7.preference.PreferenceScreen;
42 import android.text.TextUtils;
43 import android.util.EventLog;
44 import android.util.Log;
45 import android.view.View;
46 import android.view.accessibility.AccessibilityManager;
47 import android.widget.Toast;
48 
49 import com.android.internal.logging.MetricsProto.MetricsEvent;
50 import com.android.internal.widget.LockPatternUtils;
51 import com.android.settingslib.RestrictedLockUtils;
52 import com.android.settingslib.RestrictedPreference;
53 
54 import java.util.List;
55 
56 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
57 
58 public class ChooseLockGeneric extends SettingsActivity {
59     public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
60 
61     @Override
getIntent()62     public Intent getIntent() {
63         Intent modIntent = new Intent(super.getIntent());
64         modIntent.putExtra(EXTRA_SHOW_FRAGMENT, getFragmentClass().getName());
65 
66         String action = modIntent.getAction();
67         if (DevicePolicyManager.ACTION_SET_NEW_PASSWORD.equals(action)
68                 || DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(action)) {
69             modIntent.putExtra(EXTRA_HIDE_DRAWER, true);
70         }
71         return modIntent;
72     }
73 
74     @Override
isValidFragment(String fragmentName)75     protected boolean isValidFragment(String fragmentName) {
76         if (ChooseLockGenericFragment.class.getName().equals(fragmentName)) return true;
77         return false;
78     }
79 
getFragmentClass()80     /* package */ Class<? extends Fragment> getFragmentClass() {
81         return ChooseLockGenericFragment.class;
82     }
83 
84     public static class InternalActivity extends ChooseLockGeneric {
85     }
86 
87     public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {
88         private static final String TAG = "ChooseLockGenericFragment";
89         private static final int MIN_PASSWORD_LENGTH = 4;
90         private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off";
91         private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none";
92         private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin";
93         private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password";
94         private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern";
95         private static final String KEY_UNLOCK_SET_MANAGED = "unlock_set_managed";
96         private static final String PASSWORD_CONFIRMED = "password_confirmed";
97         private static final String WAITING_FOR_CONFIRMATION = "waiting_for_confirmation";
98         public static final String MINIMUM_QUALITY_KEY = "minimum_quality";
99         public static final String HIDE_DISABLED_PREFS = "hide_disabled_prefs";
100         public static final String ENCRYPT_REQUESTED_QUALITY = "encrypt_requested_quality";
101         public static final String ENCRYPT_REQUESTED_DISABLED = "encrypt_requested_disabled";
102         public static final String TAG_FRP_WARNING_DIALOG = "frp_warning_dialog";
103 
104         private static final int CONFIRM_EXISTING_REQUEST = 100;
105         private static final int ENABLE_ENCRYPTION_REQUEST = 101;
106         private static final int CHOOSE_LOCK_REQUEST = 102;
107 
108         private ChooseLockSettingsHelper mChooseLockSettingsHelper;
109         private DevicePolicyManager mDPM;
110         private KeyStore mKeyStore;
111         private boolean mHasChallenge = false;
112         private long mChallenge;
113         private boolean mPasswordConfirmed = false;
114         private boolean mWaitingForConfirmation = false;
115         private int mEncryptionRequestQuality;
116         private boolean mEncryptionRequestDisabled;
117         private boolean mRequirePassword;
118         private boolean mForChangeCredRequiredForBoot = false;
119         private String mUserPassword;
120         private LockPatternUtils mLockPatternUtils;
121         private FingerprintManager mFingerprintManager;
122         private int mUserId;
123         private boolean mHideDrawer = false;
124         private ManagedLockPasswordProvider mManagedPasswordProvider;
125 
126         protected boolean mForFingerprint = false;
127 
128         @Override
getMetricsCategory()129         protected int getMetricsCategory() {
130             return MetricsEvent.CHOOSE_LOCK_GENERIC;
131         }
132 
133         @Override
onCreate(Bundle savedInstanceState)134         public void onCreate(Bundle savedInstanceState) {
135             super.onCreate(savedInstanceState);
136 
137             mFingerprintManager =
138                 (FingerprintManager) getActivity().getSystemService(Context.FINGERPRINT_SERVICE);
139             mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
140             mKeyStore = KeyStore.getInstance();
141             mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity());
142             mLockPatternUtils = new LockPatternUtils(getActivity());
143 
144             // Defaults to needing to confirm credentials
145             final boolean confirmCredentials = getActivity().getIntent()
146                 .getBooleanExtra(CONFIRM_CREDENTIALS, true);
147             if (getActivity() instanceof ChooseLockGeneric.InternalActivity) {
148                 mPasswordConfirmed = !confirmCredentials;
149             }
150             mHideDrawer = getActivity().getIntent().getBooleanExtra(EXTRA_HIDE_DRAWER, false);
151 
152             mHasChallenge = getActivity().getIntent().getBooleanExtra(
153                     ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
154             mChallenge = getActivity().getIntent().getLongExtra(
155                     ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
156             mForFingerprint = getActivity().getIntent().getBooleanExtra(
157                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
158             mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean(
159                     ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT);
160 
161             if (savedInstanceState != null) {
162                 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED);
163                 mWaitingForConfirmation = savedInstanceState.getBoolean(WAITING_FOR_CONFIRMATION);
164                 mEncryptionRequestQuality = savedInstanceState.getInt(ENCRYPT_REQUESTED_QUALITY);
165                 mEncryptionRequestDisabled = savedInstanceState.getBoolean(
166                         ENCRYPT_REQUESTED_DISABLED);
167             }
168 
169             int targetUser = Utils.getSecureTargetUser(
170                     getActivity().getActivityToken(),
171                     UserManager.get(getActivity()),
172                     null,
173                     getActivity().getIntent().getExtras()).getIdentifier();
174             if (DevicePolicyManager.ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(
175                     getActivity().getIntent().getAction()) ||
176                     !mLockPatternUtils.isSeparateProfileChallengeAllowed(targetUser)) {
177                 // Always use parent if explicitely requested or if profile challenge is not
178                 // supported
179                 Bundle arguments = getArguments();
180                 mUserId = Utils.getUserIdFromBundle(getContext(), arguments != null ? arguments
181                         : getActivity().getIntent().getExtras());
182             } else {
183                 mUserId = targetUser;
184             }
185 
186             if (DevicePolicyManager.ACTION_SET_NEW_PASSWORD
187                     .equals(getActivity().getIntent().getAction())
188                     && Utils.isManagedProfile(UserManager.get(getActivity()), mUserId)
189                     && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) {
190                 getActivity().setTitle(R.string.lock_settings_picker_title_profile);
191             }
192 
193             mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId);
194 
195             if (mPasswordConfirmed) {
196                 updatePreferencesOrFinish();
197                 if (mForChangeCredRequiredForBoot) {
198                     maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
199                             mUserId), false);
200                 }
201             } else if (!mWaitingForConfirmation) {
202                 ChooseLockSettingsHelper helper =
203                         new ChooseLockSettingsHelper(this.getActivity(), this);
204                 boolean managedProfileWithUnifiedLock = Utils
205                         .isManagedProfile(UserManager.get(getActivity()), mUserId)
206                         && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
207                 if (managedProfileWithUnifiedLock
208                         || !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
209                         getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
210                     mPasswordConfirmed = true; // no password set, so no need to confirm
211                     updatePreferencesOrFinish();
212                 } else {
213                     mWaitingForConfirmation = true;
214                 }
215             }
216             addHeaderView();
217         }
218 
addHeaderView()219         protected void addHeaderView() {
220             if (mForFingerprint) {
221                 setHeaderView(R.layout.choose_lock_generic_fingerprint_header);
222             }
223         }
224 
225         @Override
onPreferenceTreeClick(Preference preference)226         public boolean onPreferenceTreeClick(Preference preference) {
227             final String key = preference.getKey();
228 
229             if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
230                 // Show the disabling FRP warning only when the user is switching from a secure
231                 // unlock method to an insecure one
232                 showFactoryResetProtectionWarningDialog(key);
233                 return true;
234             } else {
235                 return setUnlockMethod(key);
236             }
237         }
238 
239         /**
240          * If the device has encryption already enabled, then ask the user if they
241          * also want to encrypt the phone with this password.
242          *
243          * @param quality
244          * @param disabled
245          */
246         // TODO: why does this take disabled, its always called with a quality higher than
247         // what makes sense with disabled == true
maybeEnableEncryption(int quality, boolean disabled)248         private void maybeEnableEncryption(int quality, boolean disabled) {
249             DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
250             if (UserManager.get(getActivity()).isAdminUser()
251                     && mUserId == UserHandle.myUserId()
252                     && LockPatternUtils.isDeviceEncryptionEnabled()
253                     && !LockPatternUtils.isFileEncryptionEnabled()
254                     && !dpm.getDoNotAskCredentialsOnBoot()) {
255                 mEncryptionRequestQuality = quality;
256                 mEncryptionRequestDisabled = disabled;
257                 // Get the intent that the encryption interstitial should start for creating
258                 // the new unlock method.
259                 Intent unlockMethodIntent = getIntentForUnlockMethod(quality, disabled);
260                 unlockMethodIntent.putExtra(
261                         ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
262                         mForChangeCredRequiredForBoot);
263                 final Context context = getActivity();
264                 // If accessibility is enabled and the user hasn't seen this dialog before, set the
265                 // default state to agree with that which is compatible with accessibility
266                 // (password not required).
267                 final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
268                 final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
269                 Intent intent = getEncryptionInterstitialIntent(context, quality, required,
270                         unlockMethodIntent);
271                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
272                         mForFingerprint);
273                 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
274                 startActivityForResult(intent, ENABLE_ENCRYPTION_REQUEST);
275             } else {
276                 if (mForChangeCredRequiredForBoot) {
277                     // Welp, couldn't change it. Oh well.
278                     finish();
279                     return;
280                 }
281                 mRequirePassword = false; // device encryption not enabled or not device owner.
282                 updateUnlockMethodAndFinish(quality, disabled);
283             }
284         }
285 
286         @Override
onActivityResult(int requestCode, int resultCode, Intent data)287         public void onActivityResult(int requestCode, int resultCode, Intent data) {
288             super.onActivityResult(requestCode, resultCode, data);
289             mWaitingForConfirmation = false;
290             if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
291                 mPasswordConfirmed = true;
292                 mUserPassword = data.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);
293                 updatePreferencesOrFinish();
294                 if (mForChangeCredRequiredForBoot) {
295                     if (!TextUtils.isEmpty(mUserPassword)) {
296                         maybeEnableEncryption(
297                                 mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
298                     } else {
299                         finish();
300                     }
301                 }
302             } else if (requestCode == CHOOSE_LOCK_REQUEST
303                     || requestCode == ENABLE_ENCRYPTION_REQUEST) {
304                 if (resultCode != RESULT_CANCELED || mForChangeCredRequiredForBoot) {
305                     getActivity().setResult(resultCode, data);
306                     finish();
307                 }
308             } else {
309                 getActivity().setResult(Activity.RESULT_CANCELED);
310                 finish();
311             }
312             if (requestCode == Activity.RESULT_CANCELED && mForChangeCredRequiredForBoot) {
313                 finish();
314             }
315         }
316 
317         @Override
onSaveInstanceState(Bundle outState)318         public void onSaveInstanceState(Bundle outState) {
319             super.onSaveInstanceState(outState);
320             // Saved so we don't force user to re-enter their password if configuration changes
321             outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed);
322             outState.putBoolean(WAITING_FOR_CONFIRMATION, mWaitingForConfirmation);
323             outState.putInt(ENCRYPT_REQUESTED_QUALITY, mEncryptionRequestQuality);
324             outState.putBoolean(ENCRYPT_REQUESTED_DISABLED, mEncryptionRequestDisabled);
325         }
326 
updatePreferencesOrFinish()327         private void updatePreferencesOrFinish() {
328             Intent intent = getActivity().getIntent();
329             int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
330             if (quality == -1) {
331                 // If caller didn't specify password quality, show UI and allow the user to choose.
332                 quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
333                 quality = upgradeQuality(quality);
334                 final boolean hideDisabledPrefs = intent.getBooleanExtra(
335                         HIDE_DISABLED_PREFS, false);
336                 final PreferenceScreen prefScreen = getPreferenceScreen();
337                 if (prefScreen != null) {
338                     prefScreen.removeAll();
339                 }
340                 addPreferences();
341                 disableUnusablePreferences(quality, hideDisabledPrefs);
342                 updatePreferenceText();
343                 updateCurrentPreference();
344                 updatePreferenceSummaryIfNeeded();
345             } else {
346                 updateUnlockMethodAndFinish(quality, false);
347             }
348         }
349 
addPreferences()350         protected void addPreferences() {
351             addPreferencesFromResource(R.xml.security_settings_picker);
352 
353             // Used for testing purposes
354             findPreference(KEY_UNLOCK_SET_NONE).setViewId(R.id.lock_none);
355             findPreference(KEY_UNLOCK_SET_PIN).setViewId(R.id.lock_pin);
356             findPreference(KEY_UNLOCK_SET_PASSWORD).setViewId(R.id.lock_password);
357         }
358 
updatePreferenceText()359         private void updatePreferenceText() {
360             if (mForFingerprint) {
361                 Preference pattern = findPreference(KEY_UNLOCK_SET_PATTERN);
362                 pattern.setTitle(R.string.fingerprint_unlock_set_unlock_pattern);
363 
364                 Preference pin = findPreference(KEY_UNLOCK_SET_PIN);
365                 pin.setTitle(R.string.fingerprint_unlock_set_unlock_pin);
366 
367                 Preference password = findPreference(KEY_UNLOCK_SET_PASSWORD);
368                 password.setTitle(R.string.fingerprint_unlock_set_unlock_password);
369             }
370 
371             if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
372                 Preference managed = findPreference(KEY_UNLOCK_SET_MANAGED);
373                 managed.setTitle(mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
374             } else {
375                 removePreference(KEY_UNLOCK_SET_MANAGED);
376             }
377         }
378 
updateCurrentPreference()379         private void updateCurrentPreference() {
380             String currentKey = getKeyForCurrent();
381             Preference preference = findPreference(currentKey);
382             if (preference != null) {
383                 preference.setSummary(R.string.current_screen_lock);
384             }
385         }
386 
getKeyForCurrent()387         private String getKeyForCurrent() {
388             final int credentialOwner = UserManager.get(getContext())
389                     .getCredentialOwnerProfile(mUserId);
390             if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
391                 return KEY_UNLOCK_SET_OFF;
392             }
393             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner)) {
394                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
395                     return KEY_UNLOCK_SET_PATTERN;
396                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
397                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
398                     return KEY_UNLOCK_SET_PIN;
399                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
400                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
401                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
402                     return KEY_UNLOCK_SET_PASSWORD;
403                 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
404                     return KEY_UNLOCK_SET_MANAGED;
405                 case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
406                     return KEY_UNLOCK_SET_NONE;
407             }
408             return null;
409         }
410 
411         /** increases the quality if necessary */
upgradeQuality(int quality)412         private int upgradeQuality(int quality) {
413             quality = upgradeQualityForDPM(quality);
414             return quality;
415         }
416 
upgradeQualityForDPM(int quality)417         private int upgradeQualityForDPM(int quality) {
418             // Compare min allowed password quality
419             int minQuality = mDPM.getPasswordQuality(null, mUserId);
420             if (quality < minQuality) {
421                 quality = minQuality;
422             }
423             return quality;
424         }
425 
426         /***
427          * Disables preferences that are less secure than required quality. The actual
428          * implementation is in disableUnusablePreferenceImpl.
429          *
430          * @param quality the requested quality.
431          * @param hideDisabledPrefs if false preferences show why they were disabled; otherwise
432          * they're not shown at all.
433          */
disableUnusablePreferences(final int quality, boolean hideDisabledPrefs)434         protected void disableUnusablePreferences(final int quality, boolean hideDisabledPrefs) {
435             disableUnusablePreferencesImpl(quality, hideDisabledPrefs);
436         }
437 
438         /***
439          * Disables preferences that are less secure than required quality.
440          *
441          * @param quality the requested quality.
442          * @param hideDisabled whether to hide disable screen lock options.
443          */
disableUnusablePreferencesImpl(final int quality, boolean hideDisabled)444         protected void disableUnusablePreferencesImpl(final int quality,
445                 boolean hideDisabled) {
446             final PreferenceScreen entries = getPreferenceScreen();
447 
448             int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId);
449             EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfPasswordQualityIsSet(
450                     getActivity(), mUserId);
451             for (int i = entries.getPreferenceCount() - 1; i >= 0; --i) {
452                 Preference pref = entries.getPreference(i);
453                 if (pref instanceof RestrictedPreference) {
454                     final String key = pref.getKey();
455                     boolean enabled = true;
456                     boolean visible = true;
457                     boolean disabledByAdmin = false;
458                     if (KEY_UNLOCK_SET_OFF.equals(key)) {
459                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
460                         if (getResources().getBoolean(R.bool.config_hide_none_security_option)) {
461                             enabled = false;
462                             visible = false;
463                         }
464                         disabledByAdmin = adminEnforcedQuality
465                                 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
466                     } else if (KEY_UNLOCK_SET_NONE.equals(key)) {
467                         if (mUserId != UserHandle.myUserId()) {
468                             // Swipe doesn't make sense for profiles.
469                             visible = false;
470                         }
471                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
472                         disabledByAdmin = adminEnforcedQuality
473                                 > DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
474                     } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
475                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
476                         disabledByAdmin = adminEnforcedQuality
477                                 > DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
478                     } else if (KEY_UNLOCK_SET_PIN.equals(key)) {
479                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
480                         disabledByAdmin = adminEnforcedQuality
481                                 > DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
482                     } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) {
483                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
484                         disabledByAdmin = adminEnforcedQuality
485                                 > DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
486                     } else if (KEY_UNLOCK_SET_MANAGED.equals(key)) {
487                         enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_MANAGED
488                                 && mManagedPasswordProvider.isManagedPasswordChoosable();
489                         disabledByAdmin = adminEnforcedQuality
490                                 > DevicePolicyManager.PASSWORD_QUALITY_MANAGED;
491                     }
492                     if (hideDisabled) {
493                         visible = enabled;
494                     }
495                     if (!visible) {
496                         entries.removePreference(pref);
497                     } else if (disabledByAdmin && enforcedAdmin != null) {
498                         ((RestrictedPreference) pref).setDisabledByAdmin(enforcedAdmin);
499                     } else if (!enabled) {
500                         // we need to setDisabledByAdmin to null first to disable the padlock
501                         // in case it was set earlier.
502                         ((RestrictedPreference) pref).setDisabledByAdmin(null);
503                         pref.setSummary(R.string.unlock_set_unlock_disabled_summary);
504                         pref.setEnabled(false);
505                     } else {
506                         ((RestrictedPreference) pref).setDisabledByAdmin(null);
507                     }
508                 }
509             }
510         }
511 
updatePreferenceSummaryIfNeeded()512         private void updatePreferenceSummaryIfNeeded() {
513             // On a default block encrypted device with accessibility, add a warning
514             // that your data is not credential encrypted
515             if (!StorageManager.isBlockEncrypted()) {
516                 return;
517             }
518 
519             if (StorageManager.isNonDefaultBlockEncrypted()) {
520                 return;
521             }
522 
523             if (AccessibilityManager.getInstance(getActivity()).getEnabledAccessibilityServiceList(
524                     AccessibilityServiceInfo.FEEDBACK_ALL_MASK).isEmpty()) {
525                 return;
526             }
527 
528             CharSequence summary = getString(R.string.secure_lock_encryption_warning);
529 
530             PreferenceScreen screen = getPreferenceScreen();
531             final int preferenceCount = screen.getPreferenceCount();
532             for (int i = 0; i < preferenceCount; i++) {
533                 Preference preference = screen.getPreference(i);
534                 switch (preference.getKey()) {
535                     case KEY_UNLOCK_SET_PATTERN:
536                     case KEY_UNLOCK_SET_PIN:
537                     case KEY_UNLOCK_SET_PASSWORD:
538                     case KEY_UNLOCK_SET_MANAGED: {
539                         preference.setSummary(summary);
540                     } break;
541                 }
542             }
543         }
544 
getLockManagedPasswordIntent(boolean requirePassword, String password)545         protected Intent getLockManagedPasswordIntent(boolean requirePassword, String password) {
546             return mManagedPasswordProvider.createIntent(requirePassword, password);
547         }
548 
getLockPasswordIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, boolean confirmCredentials, int userId)549         protected Intent getLockPasswordIntent(Context context, int quality,
550                 int minLength, final int maxLength,
551                 boolean requirePasswordToDecrypt, boolean confirmCredentials, int userId) {
552             return ChooseLockPassword.createIntent(context, quality, minLength,
553                     maxLength, requirePasswordToDecrypt, confirmCredentials, userId);
554         }
555 
getLockPasswordIntent(Context context, int quality, int minLength, final int maxLength, boolean requirePasswordToDecrypt, long challenge, int userId)556         protected Intent getLockPasswordIntent(Context context, int quality,
557                 int minLength, final int maxLength,
558                 boolean requirePasswordToDecrypt, long challenge, int userId) {
559             return ChooseLockPassword.createIntent(context, quality, minLength,
560                     maxLength, requirePasswordToDecrypt, challenge, userId);
561         }
562 
getLockPasswordIntent(Context context, int quality, int minLength, int maxLength, boolean requirePasswordToDecrypt, String password, int userId)563         protected Intent getLockPasswordIntent(Context context, int quality, int minLength,
564                 int maxLength, boolean requirePasswordToDecrypt, String password, int userId) {
565             return ChooseLockPassword.createIntent(context, quality, minLength, maxLength,
566                     requirePasswordToDecrypt, password, userId);
567         }
568 
getLockPatternIntent(Context context, final boolean requirePassword, final boolean confirmCredentials, int userId)569         protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
570                 final boolean confirmCredentials, int userId) {
571             return ChooseLockPattern.createIntent(context, requirePassword,
572                     confirmCredentials, userId);
573         }
574 
getLockPatternIntent(Context context, final boolean requirePassword, long challenge, int userId)575         protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
576                long challenge, int userId) {
577             return ChooseLockPattern.createIntent(context, requirePassword, challenge, userId);
578         }
579 
getLockPatternIntent(Context context, final boolean requirePassword, final String pattern, int userId)580         protected Intent getLockPatternIntent(Context context, final boolean requirePassword,
581                 final String pattern, int userId) {
582             return ChooseLockPattern.createIntent(context, requirePassword, pattern, userId);
583         }
584 
getEncryptionInterstitialIntent(Context context, int quality, boolean required, Intent unlockMethodIntent)585         protected Intent getEncryptionInterstitialIntent(Context context, int quality,
586                 boolean required, Intent unlockMethodIntent) {
587             return EncryptionInterstitial.createStartIntent(context, quality, required,
588                     unlockMethodIntent);
589         }
590 
591         /**
592          * Invokes an activity to change the user's pattern, password or PIN based on given quality
593          * and minimum quality specified by DevicePolicyManager. If quality is
594          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared.
595          *
596          * @param quality the desired quality. Ignored if DevicePolicyManager requires more security
597          * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is
598          * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}
599          */
updateUnlockMethodAndFinish(int quality, boolean disabled)600         void updateUnlockMethodAndFinish(int quality, boolean disabled) {
601             // Sanity check. We should never get here without confirming user's existing password.
602             if (!mPasswordConfirmed) {
603                 throw new IllegalStateException("Tried to update password without confirming it");
604             }
605 
606             quality = upgradeQuality(quality);
607             Intent intent = getIntentForUnlockMethod(quality, disabled);
608             if (intent != null) {
609                 startActivityForResult(intent, CHOOSE_LOCK_REQUEST);
610                 return;
611             }
612 
613             if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
614                 mLockPatternUtils.setSeparateProfileChallengeEnabled(mUserId, true, mUserPassword);
615                 mChooseLockSettingsHelper.utils().clearLock(mUserId);
616                 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled, mUserId);
617                 removeAllFingerprintForUserAndFinish(mUserId);
618                 getActivity().setResult(Activity.RESULT_OK);
619             } else {
620                 removeAllFingerprintForUserAndFinish(mUserId);
621             }
622         }
623 
getIntentForUnlockMethod(int quality, boolean disabled)624         private Intent getIntentForUnlockMethod(int quality, boolean disabled) {
625             Intent intent = null;
626             final Context context = getActivity();
627             if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
628                 intent = getLockManagedPasswordIntent(mRequirePassword, mUserPassword);
629             } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
630                 int minLength = mDPM.getPasswordMinimumLength(null, mUserId);
631                 if (minLength < MIN_PASSWORD_LENGTH) {
632                     minLength = MIN_PASSWORD_LENGTH;
633                 }
634                 final int maxLength = mDPM.getPasswordMaximumLength(quality);
635                 if (mHasChallenge) {
636                     intent = getLockPasswordIntent(context, quality, minLength,
637                             maxLength, mRequirePassword, mChallenge, mUserId);
638                 } else {
639                     intent = getLockPasswordIntent(context, quality, minLength,
640                             maxLength, mRequirePassword, mUserPassword, mUserId);
641                 }
642             } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
643                 if (mHasChallenge) {
644                     intent = getLockPatternIntent(context, mRequirePassword,
645                             mChallenge, mUserId);
646                 } else {
647                     intent = getLockPatternIntent(context, mRequirePassword,
648                             mUserPassword, mUserId);
649                 }
650             }
651             if (intent != null) {
652                 intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
653             }
654             return intent;
655         }
656 
removeAllFingerprintForUserAndFinish(final int userId)657         private void removeAllFingerprintForUserAndFinish(final int userId) {
658             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
659                 if (mFingerprintManager.hasEnrolledFingerprints(userId)) {
660                     mFingerprintManager.setActiveUser(userId);
661                     // For the purposes of M and N, groupId is the same as userId.
662                     final int groupId = userId;
663                     Fingerprint finger = new Fingerprint(null, groupId, 0, 0);
664                     mFingerprintManager.remove(finger, userId,
665                             new RemovalCallback() {
666                                 @Override
667                                 public void onRemovalError(Fingerprint fp, int errMsgId,
668                                         CharSequence errString) {
669                                     Log.v(TAG, "Fingerprint removed: " + fp.getFingerId());
670                                     if (fp.getFingerId() == 0) {
671                                         removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
672                                     }
673                                 }
674 
675                                 @Override
676                                 public void onRemovalSucceeded(Fingerprint fingerprint) {
677                                     if (fingerprint.getFingerId() == 0) {
678                                         removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
679                                     }
680                                 }
681                             });
682                 } else {
683                     // No fingerprints in this user, we may also want to delete managed profile
684                     // fingerprints
685                     removeManagedProfileFingerprintsAndFinishIfNecessary(userId);
686                 }
687             } else {
688                 // The removal callback will call finish, once all fingerprints are removed.
689                 // We need to wait for that to occur, otherwise, the UI will still show that
690                 // fingerprints exist even though they are (about to) be removed depending on
691                 // the race condition.
692                 finish();
693             }
694         }
695 
removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId)696         private void removeManagedProfileFingerprintsAndFinishIfNecessary(final int parentUserId) {
697             mFingerprintManager.setActiveUser(UserHandle.myUserId());
698             final UserManager um = UserManager.get(getActivity());
699             boolean hasChildProfile = false;
700             if (!um.getUserInfo(parentUserId).isManagedProfile()) {
701                 // Current user is primary profile, remove work profile fingerprints if necessary
702                 final List<UserInfo> profiles = um.getProfiles(parentUserId);
703                 final int profilesSize = profiles.size();
704                 for (int i = 0; i < profilesSize; i++) {
705                     final UserInfo userInfo = profiles.get(i);
706                     if (userInfo.isManagedProfile() && !mLockPatternUtils
707                             .isSeparateProfileChallengeEnabled(userInfo.id)) {
708                         removeAllFingerprintForUserAndFinish(userInfo.id);
709                         hasChildProfile = true;
710                         break;
711                     }
712                 }
713             }
714             if (!hasChildProfile) {
715                 finish();
716             }
717         }
718 
719         @Override
onDestroy()720         public void onDestroy() {
721             super.onDestroy();
722         }
723 
724         @Override
getHelpResource()725         protected int getHelpResource() {
726             return R.string.help_url_choose_lockscreen;
727         }
728 
getResIdForFactoryResetProtectionWarningTitle()729         private int getResIdForFactoryResetProtectionWarningTitle() {
730             boolean isProfile = Utils.isManagedProfile(UserManager.get(getActivity()), mUserId);
731             return isProfile ? R.string.unlock_disable_frp_warning_title_profile
732                     : R.string.unlock_disable_frp_warning_title;
733         }
734 
getResIdForFactoryResetProtectionWarningMessage()735         private int getResIdForFactoryResetProtectionWarningMessage() {
736             boolean hasFingerprints = mFingerprintManager.hasEnrolledFingerprints(mUserId);
737             boolean isProfile = Utils.isManagedProfile(UserManager.get(getActivity()), mUserId);
738             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)) {
739                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
740                     if (hasFingerprints && isProfile) {
741                         return R.string
742                                 .unlock_disable_frp_warning_content_pattern_fingerprint_profile;
743                     } else if (hasFingerprints && !isProfile) {
744                         return R.string.unlock_disable_frp_warning_content_pattern_fingerprint;
745                     } else if (isProfile) {
746                         return R.string.unlock_disable_frp_warning_content_pattern_profile;
747                     } else {
748                         return R.string.unlock_disable_frp_warning_content_pattern;
749                     }
750                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
751                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
752                     if (hasFingerprints && isProfile) {
753                         return R.string.unlock_disable_frp_warning_content_pin_fingerprint_profile;
754                     } else if (hasFingerprints && !isProfile) {
755                         return R.string.unlock_disable_frp_warning_content_pin_fingerprint;
756                     } else if (isProfile) {
757                         return R.string.unlock_disable_frp_warning_content_pin_profile;
758                     } else {
759                         return R.string.unlock_disable_frp_warning_content_pin;
760                     }
761                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
762                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
763                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
764                 case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
765                     if (hasFingerprints && isProfile) {
766                         return R.string
767                                 .unlock_disable_frp_warning_content_password_fingerprint_profile;
768                     } else if (hasFingerprints && !isProfile) {
769                         return R.string.unlock_disable_frp_warning_content_password_fingerprint;
770                     } else if (isProfile) {
771                         return R.string.unlock_disable_frp_warning_content_password_profile;
772                     } else {
773                         return R.string.unlock_disable_frp_warning_content_password;
774                     }
775                 default:
776                     if (hasFingerprints && isProfile) {
777                         return R.string
778                                 .unlock_disable_frp_warning_content_unknown_fingerprint_profile;
779                     } else if (hasFingerprints && !isProfile) {
780                         return R.string.unlock_disable_frp_warning_content_unknown_fingerprint;
781                     } else if (isProfile) {
782                         return R.string.unlock_disable_frp_warning_content_unknown_profile;
783                     } else {
784                         return R.string.unlock_disable_frp_warning_content_unknown;
785                     }
786             }
787         }
788 
isUnlockMethodSecure(String unlockMethod)789         private boolean isUnlockMethodSecure(String unlockMethod) {
790             return !(KEY_UNLOCK_SET_OFF.equals(unlockMethod) ||
791                     KEY_UNLOCK_SET_NONE.equals(unlockMethod));
792         }
793 
setUnlockMethod(String unlockMethod)794         private boolean setUnlockMethod(String unlockMethod) {
795             EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
796 
797             if (KEY_UNLOCK_SET_OFF.equals(unlockMethod)) {
798                 updateUnlockMethodAndFinish(
799                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true /* disabled */ );
800             } else if (KEY_UNLOCK_SET_NONE.equals(unlockMethod)) {
801                 updateUnlockMethodAndFinish(
802                         DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false /* disabled */ );
803             } else if (KEY_UNLOCK_SET_MANAGED.equals(unlockMethod)) {
804                 maybeEnableEncryption(DevicePolicyManager.PASSWORD_QUALITY_MANAGED, false);
805             } else if (KEY_UNLOCK_SET_PATTERN.equals(unlockMethod)) {
806                 maybeEnableEncryption(
807                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
808             } else if (KEY_UNLOCK_SET_PIN.equals(unlockMethod)) {
809                 maybeEnableEncryption(
810                         DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
811             } else if (KEY_UNLOCK_SET_PASSWORD.equals(unlockMethod)) {
812                 maybeEnableEncryption(
813                         DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false);
814             } else {
815                 Log.e(TAG, "Encountered unknown unlock method to set: " + unlockMethod);
816                 return false;
817             }
818             return true;
819         }
820 
showFactoryResetProtectionWarningDialog(String unlockMethodToSet)821         private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
822             int title = getResIdForFactoryResetProtectionWarningTitle();
823             int message = getResIdForFactoryResetProtectionWarningMessage();
824             FactoryResetProtectionWarningDialog dialog =
825                     FactoryResetProtectionWarningDialog.newInstance(
826                             title, message, unlockMethodToSet);
827             dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
828         }
829 
830         public static class FactoryResetProtectionWarningDialog extends DialogFragment {
831 
832             private static final String ARG_TITLE_RES = "titleRes";
833             private static final String ARG_MESSAGE_RES = "messageRes";
834             private static final String ARG_UNLOCK_METHOD_TO_SET = "unlockMethodToSet";
835 
newInstance( int titleRes, int messageRes, String unlockMethodToSet)836             public static FactoryResetProtectionWarningDialog newInstance(
837                     int titleRes, int messageRes, String unlockMethodToSet) {
838                 FactoryResetProtectionWarningDialog frag =
839                         new FactoryResetProtectionWarningDialog();
840                 Bundle args = new Bundle();
841                 args.putInt(ARG_TITLE_RES, titleRes);
842                 args.putInt(ARG_MESSAGE_RES, messageRes);
843                 args.putString(ARG_UNLOCK_METHOD_TO_SET, unlockMethodToSet);
844                 frag.setArguments(args);
845                 return frag;
846             }
847 
848             @Override
show(FragmentManager manager, String tag)849             public void show(FragmentManager manager, String tag) {
850                 if (manager.findFragmentByTag(tag) == null) {
851                     // Prevent opening multiple dialogs if tapped on button quickly
852                     super.show(manager, tag);
853                 }
854             }
855 
856             @Override
onCreateDialog(Bundle savedInstanceState)857             public Dialog onCreateDialog(Bundle savedInstanceState) {
858                 final Bundle args = getArguments();
859 
860                 return new AlertDialog.Builder(getActivity())
861                         .setTitle(args.getInt(ARG_TITLE_RES))
862                         .setMessage(args.getInt(ARG_MESSAGE_RES))
863                         .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
864                                 new DialogInterface.OnClickListener() {
865                                     @Override
866                                     public void onClick(DialogInterface dialog, int whichButton) {
867                                         ((ChooseLockGenericFragment) getParentFragment())
868                                                 .setUnlockMethod(
869                                                         args.getString(ARG_UNLOCK_METHOD_TO_SET));
870                                     }
871                                 }
872                         )
873                         .setNegativeButton(R.string.cancel,
874                                 new DialogInterface.OnClickListener() {
875                                     @Override
876                                     public void onClick(DialogInterface dialog, int whichButton) {
877                                         dismiss();
878                                     }
879                                 }
880                         )
881                         .create();
882             }
883         }
884     }
885 }
886