SecuritySettings.java revision 666800a237066457c5703fc7c746a5d477249d59
1/* 2 * Copyright (C) 2007 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 19 20import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; 21 22import com.android.internal.widget.LockPatternUtils; 23 24import android.app.admin.DevicePolicyManager; 25import android.content.ContentQueryMap; 26import android.content.ContentResolver; 27import android.content.Context; 28import android.content.Intent; 29import android.database.Cursor; 30import android.location.LocationManager; 31import android.os.Bundle; 32import android.os.Vibrator; 33import android.preference.CheckBoxPreference; 34import android.preference.ListPreference; 35import android.preference.Preference; 36import android.preference.Preference.OnPreferenceChangeListener; 37import android.preference.PreferenceGroup; 38import android.preference.PreferenceScreen; 39import android.provider.Settings; 40import android.security.KeyStore; 41import android.telephony.TelephonyManager; 42import android.util.Log; 43 44import java.util.ArrayList; 45import java.util.Observable; 46import java.util.Observer; 47 48/** 49 * Gesture lock pattern settings. 50 */ 51public class SecuritySettings extends SettingsPreferenceFragment 52 implements OnPreferenceChangeListener { 53 private static final String KEY_ENCRYPTION = "encryption"; 54 55 // Lock Settings 56 private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; 57 private static final String KEY_LOCK_ENABLED = "lockenabled"; 58 private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; 59 private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback"; 60 private static final String KEY_SECURITY_CATEGORY = "security_category"; 61 private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout"; 62 private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; 63 64 // Location Settings 65 private static final String KEY_LOCATION_CATEGORY = "location_category"; 66 private static final String KEY_LOCATION_NETWORK = "location_network"; 67 private static final String KEY_LOCATION_GPS = "location_gps"; 68 private static final String KEY_ASSISTED_GPS = "assisted_gps"; 69 private static final String KEY_USE_LOCATION = "location_use_for_services"; 70 71 // Misc Settings 72 private static final String KEY_SIM_LOCK = "sim_lock"; 73 private static final String KEY_SHOW_PASSWORD = "show_password"; 74 private static final String KEY_ENABLE_CREDENTIALS = "enable_credentials"; 75 private static final String KEY_RESET_CREDENTIALS = "reset_credentials"; 76 77 private static final String TAG = "SecuritySettings"; 78 79 private CheckBoxPreference mNetwork; 80 private CheckBoxPreference mGps; 81 private CheckBoxPreference mAssistedGps; 82 private CheckBoxPreference mUseLocation; 83 84 DevicePolicyManager mDPM; 85 86 // These provide support for receiving notification when Location Manager settings change. 87 // This is necessary because the Network Location Provider can change settings 88 // if the user does not confirm enabling the provider. 89 private ContentQueryMap mContentQueryMap; 90 91 private ChooseLockSettingsHelper mChooseLockSettingsHelper; 92 private LockPatternUtils mLockPatternUtils; 93 private ListPreference mLockAfter; 94 95 private Observer mSettingsObserver; 96 97 private CheckBoxPreference mVisiblePattern; 98 private CheckBoxPreference mTactileFeedback; 99 100 private CheckBoxPreference mShowPassword; 101 102 private CheckBoxPreference mEnableCredentials; 103 private Preference mResetCredentials; 104 105 @Override 106 public void onCreate(Bundle savedInstanceState) { 107 super.onCreate(savedInstanceState); 108 109 mLockPatternUtils = new LockPatternUtils(getActivity()); 110 111 mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); 112 113 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); 114 } 115 116 @Override 117 public void onStart() { 118 super.onStart(); 119 // listen for Location Manager settings changes 120 Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null, 121 "(" + Settings.System.NAME + "=?)", 122 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, 123 null); 124 mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null); 125 } 126 127 @Override 128 public void onStop() { 129 super.onStop(); 130 if (mSettingsObserver != null) { 131 mContentQueryMap.deleteObserver(mSettingsObserver); 132 } 133 } 134 135 private PreferenceScreen createPreferenceHierarchy() { 136 PreferenceScreen root = getPreferenceScreen(); 137 if (root != null) { 138 root.removeAll(); 139 } 140 addPreferencesFromResource(R.xml.security_settings); 141 root = getPreferenceScreen(); 142 143 mNetwork = (CheckBoxPreference) root.findPreference(KEY_LOCATION_NETWORK); 144 mGps = (CheckBoxPreference) root.findPreference(KEY_LOCATION_GPS); 145 mAssistedGps = (CheckBoxPreference) root.findPreference(KEY_ASSISTED_GPS); 146 if (GoogleLocationSettingHelper.isAvailable(getActivity())) { 147 // GSF present, Add setting for 'Use My Location' 148 PreferenceGroup locationCat = 149 (PreferenceGroup) root.findPreference(KEY_LOCATION_CATEGORY); 150 CheckBoxPreference useLocation = new CheckBoxPreference(getActivity()); 151 useLocation.setKey(KEY_USE_LOCATION); 152 useLocation.setTitle(R.string.use_location_title); 153 useLocation.setSummaryOn(R.string.use_location_summary_enabled); 154 useLocation.setSummaryOff(R.string.use_location_summary_disabled); 155 useLocation.setChecked( 156 GoogleLocationSettingHelper.getUseLocationForServices(getActivity()) 157 == GoogleLocationSettingHelper.USE_LOCATION_FOR_SERVICES_ON); 158 useLocation.setPersistent(false); 159 useLocation.setOnPreferenceChangeListener(this); 160 locationCat.addPreference(useLocation); 161 mUseLocation = useLocation; 162 } 163 164 // Add options for device encryption 165 // TODO: It still needs to be determined how a device specifies that it supports 166 // encryption. That mechanism needs to be checked before adding the following code 167 168 addPreferencesFromResource(R.xml.security_settings_encryption); 169 170 // Add options for lock/unlock screen 171 int resid = 0; 172 if (!mLockPatternUtils.isSecure()) { 173 if (mLockPatternUtils.isLockScreenDisabled()) { 174 resid = R.xml.security_settings_lockscreen; 175 } else { 176 resid = R.xml.security_settings_chooser; 177 } 178 } else { 179 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) { 180 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING: 181 resid = R.xml.security_settings_pattern; 182 break; 183 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: 184 resid = R.xml.security_settings_pin; 185 break; 186 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC: 187 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC: 188 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX: 189 resid = R.xml.security_settings_password; 190 break; 191 } 192 } 193 addPreferencesFromResource(resid); 194 195 // lock after preference 196 mLockAfter = (ListPreference) root.findPreference(KEY_LOCK_AFTER_TIMEOUT); 197 if (mLockAfter != null) { 198 setupLockAfterPreference(); 199 updateLockAfterPreferenceSummary(); 200 } 201 202 // visible pattern 203 mVisiblePattern = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_PATTERN); 204 205 // tactile feedback. Should be common to all unlock preference screens. 206 mTactileFeedback = (CheckBoxPreference) root.findPreference(KEY_TACTILE_FEEDBACK_ENABLED); 207 if (!((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) { 208 PreferenceGroup securityCategory = (PreferenceGroup) 209 root.findPreference(KEY_SECURITY_CATEGORY); 210 if (securityCategory != null && mTactileFeedback != null) { 211 securityCategory.removePreference(mTactileFeedback); 212 } 213 } 214 215 // Append the rest of the settings 216 addPreferencesFromResource(R.xml.security_settings_misc); 217 218 // Do not display SIM lock for CDMA phone 219 if (TelephonyManager.PHONE_TYPE_CDMA == TelephonyManager.getDefault().getPhoneType()) { 220 root.removePreference(root.findPreference(KEY_SIM_LOCK)); 221 } 222 223 // Show password 224 mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD); 225 226 // Credential storage 227 mEnableCredentials = (CheckBoxPreference) root.findPreference(KEY_ENABLE_CREDENTIALS); 228 mEnableCredentials.setOnPreferenceChangeListener(this); 229 mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS); 230 231 return root; 232 } 233 234 private void setupLockAfterPreference() { 235 // Compatible with pre-Froyo 236 long currentTimeout = Settings.Secure.getLong(getContentResolver(), 237 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); 238 mLockAfter.setValue(String.valueOf(currentTimeout)); 239 mLockAfter.setOnPreferenceChangeListener(this); 240 final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0); 241 final long displayTimeout = Math.max(0, 242 Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0)); 243 if (adminTimeout > 0) { 244 // This setting is a slave to display timeout when a device policy is enforced. 245 // As such, maxLockTimeout = adminTimeout - displayTimeout. 246 // If there isn't enough time, shows "immediately" setting. 247 disableUnusableTimeouts(Math.max(0, adminTimeout - displayTimeout)); 248 } 249 } 250 251 private void updateLockAfterPreferenceSummary() { 252 // Update summary message with current value 253 long currentTimeout = Settings.Secure.getLong(getContentResolver(), 254 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 0); 255 final CharSequence[] entries = mLockAfter.getEntries(); 256 final CharSequence[] values = mLockAfter.getEntryValues(); 257 int best = 0; 258 for (int i = 0; i < values.length; i++) { 259 long timeout = Long.valueOf(values[i].toString()); 260 if (currentTimeout >= timeout) { 261 best = i; 262 } 263 } 264 mLockAfter.setSummary(getString(R.string.lock_after_timeout_summary, entries[best])); 265 } 266 267 private void disableUnusableTimeouts(long maxTimeout) { 268 final CharSequence[] entries = mLockAfter.getEntries(); 269 final CharSequence[] values = mLockAfter.getEntryValues(); 270 ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>(); 271 ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>(); 272 for (int i = 0; i < values.length; i++) { 273 long timeout = Long.valueOf(values[i].toString()); 274 if (timeout <= maxTimeout) { 275 revisedEntries.add(entries[i]); 276 revisedValues.add(values[i]); 277 } 278 } 279 if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) { 280 mLockAfter.setEntries( 281 revisedEntries.toArray(new CharSequence[revisedEntries.size()])); 282 mLockAfter.setEntryValues( 283 revisedValues.toArray(new CharSequence[revisedValues.size()])); 284 final int userPreference = Integer.valueOf(mLockAfter.getValue()); 285 if (userPreference <= maxTimeout) { 286 mLockAfter.setValue(String.valueOf(userPreference)); 287 } else { 288 // There will be no highlighted selection since nothing in the list matches 289 // maxTimeout. The user can still select anything less than maxTimeout. 290 // TODO: maybe append maxTimeout to the list and mark selected. 291 } 292 } 293 mLockAfter.setEnabled(revisedEntries.size() > 0); 294 } 295 296 @Override 297 public void onResume() { 298 super.onResume(); 299 300 // Make sure we reload the preference hierarchy since some of these settings 301 // depend on others... 302 createPreferenceHierarchy(); 303 updateLocationToggles(); 304 305 if (mSettingsObserver == null) { 306 mSettingsObserver = new Observer() { 307 public void update(Observable o, Object arg) { 308 updateLocationToggles(); 309 } 310 }; 311 mContentQueryMap.addObserver(mSettingsObserver); 312 } 313 314 final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); 315 if (mVisiblePattern != null) { 316 mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled()); 317 } 318 if (mTactileFeedback != null) { 319 mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled()); 320 } 321 322 mShowPassword.setChecked(Settings.System.getInt(getContentResolver(), 323 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0); 324 325 int state = KeyStore.getInstance().test(); 326 mEnableCredentials.setChecked(state == KeyStore.NO_ERROR); 327 mEnableCredentials.setEnabled(state != KeyStore.UNINITIALIZED); 328 mResetCredentials.setEnabled(state != KeyStore.UNINITIALIZED); 329 } 330 331 @Override 332 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, 333 Preference preference) { 334 final String key = preference.getKey(); 335 336 final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); 337 if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) { 338 startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment", 339 SET_OR_CHANGE_LOCK_METHOD_REQUEST, null); 340 } else if (KEY_LOCK_ENABLED.equals(key)) { 341 lockPatternUtils.setLockPatternEnabled(isToggled(preference)); 342 } else if (KEY_VISIBLE_PATTERN.equals(key)) { 343 lockPatternUtils.setVisiblePatternEnabled(isToggled(preference)); 344 } else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) { 345 lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference)); 346 } else if (preference == mShowPassword) { 347 Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 348 mShowPassword.isChecked() ? 1 : 0); 349 } else if (preference == mNetwork) { 350 Settings.Secure.setLocationProviderEnabled(getContentResolver(), 351 LocationManager.NETWORK_PROVIDER, mNetwork.isChecked()); 352 } else if (preference == mGps) { 353 boolean enabled = mGps.isChecked(); 354 Settings.Secure.setLocationProviderEnabled(getContentResolver(), 355 LocationManager.GPS_PROVIDER, enabled); 356 if (mAssistedGps != null) { 357 mAssistedGps.setEnabled(enabled); 358 } 359 } else if (preference == mAssistedGps) { 360 Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSISTED_GPS_ENABLED, 361 mAssistedGps.isChecked() ? 1 : 0); 362 } else { 363 // If we didn't handle it, let preferences handle it. 364 return super.onPreferenceTreeClick(preferenceScreen, preference); 365 } 366 367 return true; 368 } 369 370 /* 371 * Creates toggles for each available location provider 372 */ 373 private void updateLocationToggles() { 374 ContentResolver res = getContentResolver(); 375 boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled( 376 res, LocationManager.GPS_PROVIDER); 377 mNetwork.setChecked(Settings.Secure.isLocationProviderEnabled( 378 res, LocationManager.NETWORK_PROVIDER)); 379 mGps.setChecked(gpsEnabled); 380 if (mAssistedGps != null) { 381 mAssistedGps.setChecked(Settings.Secure.getInt(res, 382 Settings.Secure.ASSISTED_GPS_ENABLED, 2) == 1); 383 mAssistedGps.setEnabled(gpsEnabled); 384 } 385 } 386 387 private boolean isToggled(Preference pref) { 388 return ((CheckBoxPreference) pref).isChecked(); 389 } 390 391 /** 392 * @see #confirmPatternThenDisableAndClear 393 */ 394 @Override 395 public void onActivityResult(int requestCode, int resultCode, Intent data) { 396 super.onActivityResult(requestCode, resultCode, data); 397 createPreferenceHierarchy(); 398 } 399 400 public boolean onPreferenceChange(Preference preference, Object value) { 401 if (preference == mLockAfter) { 402 int timeout = Integer.parseInt((String) value); 403 try { 404 Settings.Secure.putInt(getContentResolver(), 405 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout); 406 } catch (NumberFormatException e) { 407 Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e); 408 } 409 updateLockAfterPreferenceSummary(); 410 } else if (preference == mUseLocation) { 411 boolean newValue = (value == null ? false : (Boolean) value); 412 GoogleLocationSettingHelper.setUseLocationForServices(getActivity(), newValue); 413 // We don't want to change the value immediately here, since the user may click 414 // disagree in the dialog that pops up. When the activity we just launched exits, this 415 // activity will be restated and the new value re-read, so the checkbox will get its 416 // new value then. 417 return false; 418 } else if (preference == mEnableCredentials) { 419 if (value != null && (Boolean) value) { 420 getActivity().startActivity(new Intent(CredentialStorage.ACTION_UNLOCK)); 421 return false; 422 } else { 423 KeyStore.getInstance().lock(); 424 } 425 } 426 return true; 427 } 428} 429