2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings;
20 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
22 import com.android.internal.widget.LockPatternUtils;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.ContentQueryMap;
26 import android.content.ContentResolver;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.database.Cursor;
30 import android.location.LocationManager;
31 import android.os.Bundle;
32 import android.os.Vibrator;
33 import android.preference.CheckBoxPreference;
34 import android.preference.ListPreference;
35 import android.preference.Preference;
36 import android.preference.Preference.OnPreferenceChangeListener;
37 import android.preference.PreferenceGroup;
38 import android.preference.PreferenceScreen;
39 import android.provider.Settings;
40 import android.security.KeyStore;
41 import android.telephony.TelephonyManager;
42 import android.util.Log;
44 import java.util.ArrayList;
45 import java.util.Observable;
46 import java.util.Observer;
49 * Gesture lock pattern settings.
51 public class SecuritySettings extends SettingsPreferenceFragment
52 implements OnPreferenceChangeListener {
55 private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
56 private static final String KEY_LOCK_ENABLED = "lockenabled";
57 private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
58 private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
59 private static final String KEY_SECURITY_CATEGORY = "security_category";
60 private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout";
61 private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
64 private static final String KEY_LOCATION_CATEGORY = "location_category";
65 private static final String KEY_LOCATION_NETWORK = "location_network";
66 private static final String KEY_LOCATION_GPS = "location_gps";
67 private static final String KEY_ASSISTED_GPS = "assisted_gps";
68 private static final String KEY_USE_LOCATION = "location_use_for_services";
71 private static final String KEY_SIM_LOCK = "sim_lock";
72 private static final String KEY_SHOW_PASSWORD = "show_password";
73 private static final String KEY_RESET_CREDENTIALS = "reset_credentials";
75 private static final String TAG = "SecuritySettings";
77 private CheckBoxPreference mNetwork;
78 private CheckBoxPreference mGps;
79 private CheckBoxPreference mAssistedGps;
80 private CheckBoxPreference mUseLocation;
82 DevicePolicyManager mDPM;
84 // These provide support for receiving notification when Location Manager settings change.
85 // This is necessary because the Network Location Provider can change settings
86 // if the user does not confirm enabling the provider.
87 private ContentQueryMap mContentQueryMap;
89 private ChooseLockSettingsHelper mChooseLockSettingsHelper;
90 private LockPatternUtils mLockPatternUtils;
91 private ListPreference mLockAfter;
93 private Observer mSettingsObserver;
95 private CheckBoxPreference mVisiblePattern;
96 private CheckBoxPreference mTactileFeedback;
98 private CheckBoxPreference mShowPassword;
100 private Preference mResetCredentials;
103 public void onCreate(Bundle savedInstanceState) {
104 super.onCreate(savedInstanceState);
106 mLockPatternUtils = new LockPatternUtils(getActivity());
108 mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
110 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
114 public void onStart() {
116 // listen for Location Manager settings changes
117 Cursor settingsCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, null,
118 "(" + Settings.System.NAME + "=?)",
119 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
121 mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
125 public void onStop() {
127 if (mSettingsObserver != null) {
128 mContentQueryMap.deleteObserver(mSettingsObserver);
132 private PreferenceScreen createPreferenceHierarchy() {
133 PreferenceScreen root = getPreferenceScreen();
137 addPreferencesFromResource(R.xml.security_settings);
138 root = getPreferenceScreen();
140 mNetwork = (CheckBoxPreference) root.findPreference(KEY_LOCATION_NETWORK);
141 mGps = (CheckBoxPreference) root.findPreference(KEY_LOCATION_GPS);
142 mAssistedGps = (CheckBoxPreference) root.findPreference(KEY_ASSISTED_GPS);
143 if (GoogleLocationSettingHelper.isAvailable(getActivity())) {
144 // GSF present, Add setting for 'Use My Location'
145 PreferenceGroup locationCat =
146 (PreferenceGroup) root.findPreference(KEY_LOCATION_CATEGORY);
147 CheckBoxPreference useLocation = new CheckBoxPreference(getActivity());
148 useLocation.setKey(KEY_USE_LOCATION);
149 useLocation.setTitle(R.string.use_location_title);
150 useLocation.setSummaryOn(R.string.use_location_summary_enabled);
151 useLocation.setSummaryOff(R.string.use_location_summary_disabled);
152 useLocation.setChecked(
153 GoogleLocationSettingHelper.getUseLocationForServices(getActivity())
154 == GoogleLocationSettingHelper.USE_LOCATION_FOR_SERVICES_ON);
155 useLocation.setPersistent(false);
156 useLocation.setOnPreferenceChangeListener(this);
157 locationCat.addPreference(useLocation);
158 mUseLocation = useLocation;
161 // Change the summary for wifi-only devices
162 if (Utils.isWifiOnly()) {
163 mNetwork.setSummaryOn(R.string.location_neighborhood_level_wifi);
166 // Add options for lock/unlock screen
168 if (!mLockPatternUtils.isSecure()) {
169 if (mLockPatternUtils.isLockScreenDisabled()) {
170 resid = R.xml.security_settings_lockscreen;
172 resid = R.xml.security_settings_chooser;
175 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
176 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
177 resid = R.xml.security_settings_pattern;
179 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
180 resid = R.xml.security_settings_pin;
182 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
183 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
184 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
185 resid = R.xml.security_settings_password;
189 addPreferencesFromResource(resid);
192 // Add options for device encryption
193 DevicePolicyManager dpm =
194 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
196 switch (dpm.getStorageEncryptionStatus()) {
197 case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
198 // The device is currently encrypted.
199 addPreferencesFromResource(R.xml.security_settings_encrypted);
201 case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
202 // This device supports encryption but isn't encrypted.
203 addPreferencesFromResource(R.xml.security_settings_unencrypted);
207 // lock after preference
208 mLockAfter = (ListPreference) root.findPreference(KEY_LOCK_AFTER_TIMEOUT);
209 if (mLockAfter != null) {
210 setupLockAfterPreference();
211 updateLockAfterPreferenceSummary();
215 mVisiblePattern = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_PATTERN);
217 // tactile feedback. Should be common to all unlock preference screens.
218 mTactileFeedback = (CheckBoxPreference) root.findPreference(KEY_TACTILE_FEEDBACK_ENABLED);
219 if (!((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
220 PreferenceGroup securityCategory = (PreferenceGroup)
221 root.findPreference(KEY_SECURITY_CATEGORY);
222 if (securityCategory != null && mTactileFeedback != null) {
223 securityCategory.removePreference(mTactileFeedback);
227 // Append the rest of the settings
228 addPreferencesFromResource(R.xml.security_settings_misc);
230 // Do not display SIM lock for CDMA phone
231 if (TelephonyManager.PHONE_TYPE_CDMA ==
232 TelephonyManager.getDefault().getCurrentPhoneType()) {
233 root.removePreference(root.findPreference(KEY_SIM_LOCK));
237 mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD);
239 // Credential storage
240 mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS);
245 private void setupLockAfterPreference() {
246 // Compatible with pre-Froyo
247 long currentTimeout = Settings.Secure.getLong(getContentResolver(),
248 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000);
249 mLockAfter.setValue(String.valueOf(currentTimeout));
250 mLockAfter.setOnPreferenceChangeListener(this);
251 final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0);
252 final long displayTimeout = Math.max(0,
253 Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0));
254 if (adminTimeout > 0) {
255 // This setting is a slave to display timeout when a device policy is enforced.
256 // As such, maxLockTimeout = adminTimeout - displayTimeout.
257 // If there isn't enough time, shows "immediately" setting.
258 disableUnusableTimeouts(Math.max(0, adminTimeout - displayTimeout));
262 private void updateLockAfterPreferenceSummary() {
263 // Update summary message with current value
264 long currentTimeout = Settings.Secure.getLong(getContentResolver(),
265 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 0);
266 final CharSequence[] entries = mLockAfter.getEntries();
267 final CharSequence[] values = mLockAfter.getEntryValues();
269 for (int i = 0; i < values.length; i++) {
270 long timeout = Long.valueOf(values[i].toString());
271 if (currentTimeout >= timeout) {
275 mLockAfter.setSummary(getString(R.string.lock_after_timeout_summary, entries[best]));
278 private void disableUnusableTimeouts(long maxTimeout) {
279 final CharSequence[] entries = mLockAfter.getEntries();
280 final CharSequence[] values = mLockAfter.getEntryValues();
281 ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
282 ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
283 for (int i = 0; i < values.length; i++) {
284 long timeout = Long.valueOf(values[i].toString());
285 if (timeout <= maxTimeout) {
286 revisedEntries.add(entries[i]);
287 revisedValues.add(values[i]);
290 if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
291 mLockAfter.setEntries(
292 revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
293 mLockAfter.setEntryValues(
294 revisedValues.toArray(new CharSequence[revisedValues.size()]));
295 final int userPreference = Integer.valueOf(mLockAfter.getValue());
296 if (userPreference <= maxTimeout) {
297 mLockAfter.setValue(String.valueOf(userPreference));
299 // There will be no highlighted selection since nothing in the list matches
300 // maxTimeout. The user can still select anything less than maxTimeout.
301 // TODO: maybe append maxTimeout to the list and mark selected.
304 mLockAfter.setEnabled(revisedEntries.size() > 0);
308 public void onResume() {
311 // Make sure we reload the preference hierarchy since some of these settings
312 // depend on others...
313 createPreferenceHierarchy();
314 updateLocationToggles();
316 if (mSettingsObserver == null) {
317 mSettingsObserver = new Observer() {
318 public void update(Observable o, Object arg) {
319 updateLocationToggles();
322 mContentQueryMap.addObserver(mSettingsObserver);
325 final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
326 if (mVisiblePattern != null) {
327 mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
329 if (mTactileFeedback != null) {
330 mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
333 mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
334 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
336 KeyStore.State state = KeyStore.getInstance().state();
337 mResetCredentials.setEnabled(state != KeyStore.State.UNINITIALIZED);
341 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
342 Preference preference) {
343 final String key = preference.getKey();
345 final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
346 if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
347 startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
348 SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
349 } else if (KEY_LOCK_ENABLED.equals(key)) {
350 lockPatternUtils.setLockPatternEnabled(isToggled(preference));
351 } else if (KEY_VISIBLE_PATTERN.equals(key)) {
352 lockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
353 } else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
354 lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
355 } else if (preference == mShowPassword) {
356 Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
357 mShowPassword.isChecked() ? 1 : 0);
358 } else if (preference == mNetwork) {
359 Settings.Secure.setLocationProviderEnabled(getContentResolver(),
360 LocationManager.NETWORK_PROVIDER, mNetwork.isChecked());
361 } else if (preference == mGps) {
362 boolean enabled = mGps.isChecked();
363 Settings.Secure.setLocationProviderEnabled(getContentResolver(),
364 LocationManager.GPS_PROVIDER, enabled);
365 if (mAssistedGps != null) {
366 mAssistedGps.setEnabled(enabled);
368 } else if (preference == mAssistedGps) {
369 Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSISTED_GPS_ENABLED,
370 mAssistedGps.isChecked() ? 1 : 0);
372 // If we didn't handle it, let preferences handle it.
373 return super.onPreferenceTreeClick(preferenceScreen, preference);
380 * Creates toggles for each available location provider
382 private void updateLocationToggles() {
383 ContentResolver res = getContentResolver();
384 boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled(
385 res, LocationManager.GPS_PROVIDER);
386 mNetwork.setChecked(Settings.Secure.isLocationProviderEnabled(
387 res, LocationManager.NETWORK_PROVIDER));
388 mGps.setChecked(gpsEnabled);
389 if (mAssistedGps != null) {
390 mAssistedGps.setChecked(Settings.Secure.getInt(res,
391 Settings.Secure.ASSISTED_GPS_ENABLED, 2) == 1);
392 mAssistedGps.setEnabled(gpsEnabled);
396 private boolean isToggled(Preference pref) {
397 return ((CheckBoxPreference) pref).isChecked();
401 * @see #confirmPatternThenDisableAndClear
404 public void onActivityResult(int requestCode, int resultCode, Intent data) {
405 super.onActivityResult(requestCode, resultCode, data);
406 createPreferenceHierarchy();
409 public boolean onPreferenceChange(Preference preference, Object value) {
410 if (preference == mLockAfter) {
411 int timeout = Integer.parseInt((String) value);
413 Settings.Secure.putInt(getContentResolver(),
414 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout);
415 } catch (NumberFormatException e) {
416 Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
418 updateLockAfterPreferenceSummary();
419 } else if (preference == mUseLocation) {
420 boolean newValue = (value == null ? false : (Boolean) value);
421 GoogleLocationSettingHelper.setUseLocationForServices(getActivity(), newValue);
422 // We don't want to change the value immediately here, since the user may click
423 // disagree in the dialog that pops up. When the activity we just launched exits, this
424 // activity will be restated and the new value re-read, so the checkbox will get its