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