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 android.app.admin.DevicePolicyManager;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.os.Bundle;
26 import android.os.Vibrator;
27 import android.preference.CheckBoxPreference;
28 import android.preference.ListPreference;
29 import android.preference.Preference;
30 import android.preference.Preference.OnPreferenceChangeListener;
31 import android.preference.PreferenceGroup;
32 import android.preference.PreferenceScreen;
33 import android.provider.Settings;
34 import android.security.KeyStore;
35 import android.telephony.TelephonyManager;
36 import android.util.Log;
38 import com.android.internal.widget.LockPatternUtils;
40 import java.util.ArrayList;
43 * Gesture lock pattern settings.
45 public class SecuritySettings extends SettingsPreferenceFragment
46 implements OnPreferenceChangeListener {
49 private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
50 private static final String KEY_LOCK_ENABLED = "lockenabled";
51 private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
52 private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
53 private static final String KEY_SECURITY_CATEGORY = "security_category";
54 private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout";
55 private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
58 private static final String KEY_SIM_LOCK = "sim_lock";
59 private static final String KEY_SHOW_PASSWORD = "show_password";
60 private static final String KEY_RESET_CREDENTIALS = "reset_credentials";
62 DevicePolicyManager mDPM;
64 private ChooseLockSettingsHelper mChooseLockSettingsHelper;
65 private LockPatternUtils mLockPatternUtils;
66 private ListPreference mLockAfter;
68 private CheckBoxPreference mVisiblePattern;
69 private CheckBoxPreference mTactileFeedback;
71 private CheckBoxPreference mShowPassword;
73 private Preference mResetCredentials;
76 public void onCreate(Bundle savedInstanceState) {
77 super.onCreate(savedInstanceState);
79 mLockPatternUtils = new LockPatternUtils(getActivity());
81 mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
83 mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
86 private PreferenceScreen createPreferenceHierarchy() {
87 PreferenceScreen root = getPreferenceScreen();
91 addPreferencesFromResource(R.xml.security_settings);
92 root = getPreferenceScreen();
94 // Add options for lock/unlock screen
96 if (!mLockPatternUtils.isSecure()) {
97 if (mLockPatternUtils.isLockScreenDisabled()) {
98 resid = R.xml.security_settings_lockscreen;
100 resid = R.xml.security_settings_chooser;
103 switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
104 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
105 resid = R.xml.security_settings_pattern;
107 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
108 resid = R.xml.security_settings_pin;
110 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
111 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
112 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
113 resid = R.xml.security_settings_password;
117 addPreferencesFromResource(resid);
120 // Add options for device encryption
121 DevicePolicyManager dpm =
122 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
124 switch (dpm.getStorageEncryptionStatus()) {
125 case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
126 // The device is currently encrypted.
127 addPreferencesFromResource(R.xml.security_settings_encrypted);
129 case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
130 // This device supports encryption but isn't encrypted.
131 addPreferencesFromResource(R.xml.security_settings_unencrypted);
135 // lock after preference
136 mLockAfter = (ListPreference) root.findPreference(KEY_LOCK_AFTER_TIMEOUT);
137 if (mLockAfter != null) {
138 setupLockAfterPreference();
139 updateLockAfterPreferenceSummary();
143 mVisiblePattern = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_PATTERN);
145 // tactile feedback. Should be common to all unlock preference screens.
146 mTactileFeedback = (CheckBoxPreference) root.findPreference(KEY_TACTILE_FEEDBACK_ENABLED);
147 if (!((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
148 PreferenceGroup securityCategory = (PreferenceGroup)
149 root.findPreference(KEY_SECURITY_CATEGORY);
150 if (securityCategory != null && mTactileFeedback != null) {
151 securityCategory.removePreference(mTactileFeedback);
155 // Append the rest of the settings
156 addPreferencesFromResource(R.xml.security_settings_misc);
158 // Do not display SIM lock for CDMA phone
159 if (TelephonyManager.PHONE_TYPE_CDMA ==
160 TelephonyManager.getDefault().getCurrentPhoneType()) {
161 root.removePreference(root.findPreference(KEY_SIM_LOCK));
165 mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD);
167 // Credential storage
168 mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS);
173 private void setupLockAfterPreference() {
174 // Compatible with pre-Froyo
175 long currentTimeout = Settings.Secure.getLong(getContentResolver(),
176 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000);
177 mLockAfter.setValue(String.valueOf(currentTimeout));
178 mLockAfter.setOnPreferenceChangeListener(this);
179 final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0);
180 final long displayTimeout = Math.max(0,
181 Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0));
182 if (adminTimeout > 0) {
183 // This setting is a slave to display timeout when a device policy is enforced.
184 // As such, maxLockTimeout = adminTimeout - displayTimeout.
185 // If there isn't enough time, shows "immediately" setting.
186 disableUnusableTimeouts(Math.max(0, adminTimeout - displayTimeout));
190 private void updateLockAfterPreferenceSummary() {
191 // Update summary message with current value
192 long currentTimeout = Settings.Secure.getLong(getContentResolver(),
193 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 0);
194 final CharSequence[] entries = mLockAfter.getEntries();
195 final CharSequence[] values = mLockAfter.getEntryValues();
197 for (int i = 0; i < values.length; i++) {
198 long timeout = Long.valueOf(values[i].toString());
199 if (currentTimeout >= timeout) {
203 mLockAfter.setSummary(getString(R.string.lock_after_timeout_summary, entries[best]));
206 private void disableUnusableTimeouts(long maxTimeout) {
207 final CharSequence[] entries = mLockAfter.getEntries();
208 final CharSequence[] values = mLockAfter.getEntryValues();
209 ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
210 ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
211 for (int i = 0; i < values.length; i++) {
212 long timeout = Long.valueOf(values[i].toString());
213 if (timeout <= maxTimeout) {
214 revisedEntries.add(entries[i]);
215 revisedValues.add(values[i]);
218 if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
219 mLockAfter.setEntries(
220 revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
221 mLockAfter.setEntryValues(
222 revisedValues.toArray(new CharSequence[revisedValues.size()]));
223 final int userPreference = Integer.valueOf(mLockAfter.getValue());
224 if (userPreference <= maxTimeout) {
225 mLockAfter.setValue(String.valueOf(userPreference));
227 // There will be no highlighted selection since nothing in the list matches
228 // maxTimeout. The user can still select anything less than maxTimeout.
229 // TODO: maybe append maxTimeout to the list and mark selected.
232 mLockAfter.setEnabled(revisedEntries.size() > 0);
236 public void onResume() {
239 // Make sure we reload the preference hierarchy since some of these settings
240 // depend on others...
241 createPreferenceHierarchy();
243 final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
244 if (mVisiblePattern != null) {
245 mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
247 if (mTactileFeedback != null) {
248 mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
251 mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
252 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
254 KeyStore.State state = KeyStore.getInstance().state();
255 mResetCredentials.setEnabled(state != KeyStore.State.UNINITIALIZED);
259 public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
260 final String key = preference.getKey();
262 final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
263 if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
264 startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
265 SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
266 } else if (KEY_LOCK_ENABLED.equals(key)) {
267 lockPatternUtils.setLockPatternEnabled(isToggled(preference));
268 } else if (KEY_VISIBLE_PATTERN.equals(key)) {
269 lockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
270 } else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
271 lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
272 } else if (preference == mShowPassword) {
273 Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
274 mShowPassword.isChecked() ? 1 : 0);
276 // If we didn't handle it, let preferences handle it.
277 return super.onPreferenceTreeClick(preferenceScreen, preference);
283 private boolean isToggled(Preference pref) {
284 return ((CheckBoxPreference) pref).isChecked();
288 * see confirmPatternThenDisableAndClear
291 public void onActivityResult(int requestCode, int resultCode, Intent data) {
292 super.onActivityResult(requestCode, resultCode, data);
293 createPreferenceHierarchy();
296 public boolean onPreferenceChange(Preference preference, Object value) {
297 if (preference == mLockAfter) {
298 int timeout = Integer.parseInt((String) value);
300 Settings.Secure.putInt(getContentResolver(),
301 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout);
302 } catch (NumberFormatException e) {
303 Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
305 updateLockAfterPreferenceSummary();