ChooseLockGeneric.java revision 6465054995f8470e52ecaf68ea9508a28f8a5363
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 17package com.android.settings; 18 19import android.app.Activity; 20import android.app.admin.DevicePolicyManager; 21import android.content.Context; 22import android.content.Intent; 23import android.os.Bundle; 24import android.preference.Preference; 25import android.preference.PreferenceActivity; 26import android.preference.PreferenceCategory; 27import android.preference.PreferenceScreen; 28import android.security.KeyStore; 29 30import com.android.internal.widget.LockPatternUtils; 31 32public class ChooseLockGeneric extends PreferenceActivity { 33 34 @Override 35 public Intent getIntent() { 36 Intent modIntent = new Intent(super.getIntent()); 37 modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ChooseLockGenericFragment.class.getName()); 38 modIntent.putExtra(EXTRA_NO_HEADERS, true); 39 return modIntent; 40 } 41 42 public static class ChooseLockGenericFragment extends SettingsPreferenceFragment { 43 private static final int MIN_PASSWORD_LENGTH = 4; 44 private static final String KEY_UNLOCK_SET_OFF = "unlock_set_off"; 45 private static final String KEY_UNLOCK_SET_NONE = "unlock_set_none"; 46 private static final String KEY_UNLOCK_SET_PIN = "unlock_set_pin"; 47 private static final String KEY_UNLOCK_SET_PASSWORD = "unlock_set_password"; 48 private static final String KEY_UNLOCK_SET_PATTERN = "unlock_set_pattern"; 49 private static final int CONFIRM_EXISTING_REQUEST = 100; 50 private static final String PASSWORD_CONFIRMED = "password_confirmed"; 51 private static final String CONFIRM_CREDENTIALS = "confirm_credentials"; 52 public static final String MINIMUM_QUALITY_KEY = "minimum_quality"; 53 54 private ChooseLockSettingsHelper mChooseLockSettingsHelper; 55 private DevicePolicyManager mDPM; 56 private KeyStore mKeyStore; 57 private boolean mPasswordConfirmed = false; 58 59 @Override 60 public void onCreate(Bundle savedInstanceState) { 61 super.onCreate(savedInstanceState); 62 63 mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); 64 mKeyStore = KeyStore.getInstance(); 65 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); 66 67 if (savedInstanceState != null) { 68 mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); 69 } 70 71 if (!mPasswordConfirmed) { 72 ChooseLockSettingsHelper helper = 73 new ChooseLockSettingsHelper(this.getActivity(), this); 74 if (!helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST, null, null)) { 75 mPasswordConfirmed = true; // no password set, so no need to confirm 76 updatePreferencesOrFinish(); 77 } 78 } else { 79 updatePreferencesOrFinish(); 80 } 81 } 82 83 @Override 84 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, 85 Preference preference) { 86 final String key = preference.getKey(); 87 boolean handled = true; 88 if (KEY_UNLOCK_SET_OFF.equals(key)) { 89 updateUnlockMethodAndFinish( 90 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true); 91 } else if (KEY_UNLOCK_SET_NONE.equals(key)) { 92 updateUnlockMethodAndFinish( 93 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, false); 94 } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) { 95 updateUnlockMethodAndFinish( 96 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false); 97 } else if (KEY_UNLOCK_SET_PIN.equals(key)) { 98 updateUnlockMethodAndFinish( 99 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false); 100 } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) { 101 updateUnlockMethodAndFinish( 102 DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, false); 103 } else { 104 handled = false; 105 } 106 return handled; 107 } 108 109 @Override 110 public void onActivityResult(int requestCode, int resultCode, Intent data) { 111 super.onActivityResult(requestCode, resultCode, data); 112 if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) { 113 mPasswordConfirmed = true; 114 updatePreferencesOrFinish(); 115 } else { 116 getActivity().setResult(Activity.RESULT_CANCELED); 117 finish(); 118 } 119 } 120 121 @Override 122 public void onSaveInstanceState(Bundle outState) { 123 super.onSaveInstanceState(outState); 124 // Saved so we don't force user to re-enter their password if configuration changes 125 outState.putBoolean(PASSWORD_CONFIRMED, mPasswordConfirmed); 126 } 127 128 private void updatePreferencesOrFinish() { 129 int quality = getActivity().getIntent() 130 .getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1); 131 if (quality == -1) { 132 // If caller didn't specify password quality, show UI and allow the user to choose. 133 quality = getActivity().getIntent().getIntExtra(MINIMUM_QUALITY_KEY, -1); 134 quality = upgradeQuality(quality); 135 final PreferenceScreen prefScreen = getPreferenceScreen(); 136 if (prefScreen != null) { 137 prefScreen.removeAll(); 138 } 139 addPreferencesFromResource(R.xml.security_settings_picker); 140 disableUnusablePreferences(quality); 141 } else { 142 updateUnlockMethodAndFinish(quality, false); 143 } 144 } 145 146 private int upgradeQuality(int quality) { 147 quality = upgradeQualityForDPM(quality); 148 quality = upgradeQualityForEncryption(quality); 149 quality = upgradeQualityForKeyStore(quality); 150 return quality; 151 } 152 153 private int upgradeQualityForDPM(int quality) { 154 // Compare min allowed password quality 155 int minQuality = mDPM.getPasswordQuality(null); 156 if (quality < minQuality) { 157 quality = minQuality; 158 } 159 return quality; 160 } 161 162 /** 163 * Mix in "encryption minimums" to any given quality value. This prevents users 164 * from downgrading the pattern/pin/password to a level below the minimums. 165 * 166 * ASSUMPTION: Setting quality is sufficient (e.g. minimum lengths will be set 167 * appropriately.) 168 */ 169 private int upgradeQualityForEncryption(int quality) { 170 int encryptionStatus = mDPM.getStorageEncryptionStatus(); 171 boolean encrypted = (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) 172 || (encryptionStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVATING); 173 if (encrypted) { 174 if (quality < CryptKeeperSettings.MIN_PASSWORD_QUALITY) { 175 quality = CryptKeeperSettings.MIN_PASSWORD_QUALITY; 176 } 177 } 178 return quality; 179 } 180 181 private int upgradeQualityForKeyStore(int quality) { 182 if (!mKeyStore.isEmpty()) { 183 if (quality < CredentialStorage.MIN_PASSWORD_QUALITY) { 184 quality = CredentialStorage.MIN_PASSWORD_QUALITY; 185 } 186 } 187 return quality; 188 } 189 190 /*** 191 * Disables preferences that are less secure than required quality. 192 * 193 * @param quality the requested quality. 194 */ 195 private void disableUnusablePreferences(final int quality) { 196 final Preference picker = 197 getPreferenceScreen().findPreference("security_picker_category"); 198 final PreferenceCategory cat = (PreferenceCategory) picker; 199 final int preferenceCount = cat.getPreferenceCount(); 200 for (int i = 0; i < preferenceCount; i++) { 201 Preference pref = cat.getPreference(i); 202 if (pref instanceof PreferenceScreen) { 203 final String key = ((PreferenceScreen) pref).getKey(); 204 boolean enabled = true; 205 if (KEY_UNLOCK_SET_OFF.equals(key)) { 206 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 207 } else if (KEY_UNLOCK_SET_NONE.equals(key)) { 208 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; 209 } else if (KEY_UNLOCK_SET_PATTERN.equals(key)) { 210 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; 211 } else if (KEY_UNLOCK_SET_PIN.equals(key)) { 212 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; 213 } else if (KEY_UNLOCK_SET_PASSWORD.equals(key)) { 214 enabled = quality <= DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; 215 } 216 if (!enabled) { 217 pref.setSummary(R.string.unlock_set_unlock_disabled_summary); 218 pref.setEnabled(false); 219 } 220 } 221 } 222 } 223 224 /** 225 * Invokes an activity to change the user's pattern, password or PIN based on given quality 226 * and minimum quality specified by DevicePolicyManager. If quality is 227 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, password is cleared. 228 * 229 * @param quality the desired quality. Ignored if DevicePolicyManager requires more security 230 * @param disabled whether or not to show LockScreen at all. Only meaningful when quality is 231 * {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED} 232 */ 233 void updateUnlockMethodAndFinish(int quality, boolean disabled) { 234 // Sanity check. We should never get here without confirming user's existing password. 235 if (!mPasswordConfirmed) { 236 throw new IllegalStateException("Tried to update password without confirming it"); 237 } 238 239 quality = upgradeQuality(quality); 240 if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) { 241 int minLength = mDPM.getPasswordMinimumLength(null); 242 if (minLength < MIN_PASSWORD_LENGTH) { 243 minLength = MIN_PASSWORD_LENGTH; 244 } 245 final int maxLength = mDPM.getPasswordMaximumLength(quality); 246 Intent intent = new Intent().setClass(getActivity(), ChooseLockPassword.class); 247 intent.putExtra(LockPatternUtils.PASSWORD_TYPE_KEY, quality); 248 intent.putExtra(ChooseLockPassword.PASSWORD_MIN_KEY, minLength); 249 intent.putExtra(ChooseLockPassword.PASSWORD_MAX_KEY, maxLength); 250 intent.putExtra(CONFIRM_CREDENTIALS, false); 251 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 252 startActivity(intent); 253 } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) { 254 boolean showTutorial = !mChooseLockSettingsHelper.utils().isPatternEverChosen(); 255 Intent intent = new Intent(); 256 intent.setClass(getActivity(), showTutorial 257 ? ChooseLockPatternTutorial.class 258 : ChooseLockPattern.class); 259 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); 260 intent.putExtra("key_lock_method", "pattern"); 261 intent.putExtra(CONFIRM_CREDENTIALS, false); 262 startActivity(intent); 263 } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 264 mChooseLockSettingsHelper.utils().clearLock(); 265 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled); 266 getActivity().setResult(Activity.RESULT_OK); 267 } 268 finish(); 269 } 270 } 271} 272