OSDN Git Service

Merge "Add "large text" accessibility option."
[android-x86/packages-apps-Settings.git] / src / com / android / settings / SecuritySettings.java
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
17 package com.android.settings;
18
19
20 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
21
22 import android.app.AlertDialog;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.Context;
25 import android.content.DialogInterface;
26 import android.content.Intent;
27 import android.os.Bundle;
28 import android.os.Vibrator;
29 import android.preference.CheckBoxPreference;
30 import android.preference.ListPreference;
31 import android.preference.Preference;
32 import android.preference.Preference.OnPreferenceChangeListener;
33 import android.preference.PreferenceGroup;
34 import android.preference.PreferenceScreen;
35 import android.provider.Settings;
36 import android.security.KeyStore;
37 import android.telephony.TelephonyManager;
38 import android.util.Log;
39
40 import com.android.internal.widget.LockPatternUtils;
41
42 import java.util.ArrayList;
43
44 /**
45  * Gesture lock pattern settings.
46  */
47 public class SecuritySettings extends SettingsPreferenceFragment
48         implements OnPreferenceChangeListener, DialogInterface.OnClickListener {
49
50     // Lock Settings
51     private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
52     private static final String KEY_LOCK_ENABLED = "lockenabled";
53     private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
54     private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback";
55     private static final String KEY_SECURITY_CATEGORY = "security_category";
56     private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout";
57     private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
58
59     // Misc Settings
60     private static final String KEY_SIM_LOCK = "sim_lock";
61     private static final String KEY_SHOW_PASSWORD = "show_password";
62     private static final String KEY_RESET_CREDENTIALS = "reset_credentials";
63     private static final String KEY_TOGGLE_INSTALL_APPLICATIONS = "toggle_install_applications";
64
65     DevicePolicyManager mDPM;
66
67     private ChooseLockSettingsHelper mChooseLockSettingsHelper;
68     private LockPatternUtils mLockPatternUtils;
69     private ListPreference mLockAfter;
70
71     private CheckBoxPreference mVisiblePattern;
72     private CheckBoxPreference mTactileFeedback;
73
74     private CheckBoxPreference mShowPassword;
75
76     private Preference mResetCredentials;
77
78     private CheckBoxPreference mToggleAppInstallation;
79     private DialogInterface mWarnInstallApps;
80
81     @Override
82     public void onCreate(Bundle savedInstanceState) {
83         super.onCreate(savedInstanceState);
84
85         mLockPatternUtils = new LockPatternUtils(getActivity());
86
87         mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
88
89         mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
90     }
91
92     private PreferenceScreen createPreferenceHierarchy() {
93         PreferenceScreen root = getPreferenceScreen();
94         if (root != null) {
95             root.removeAll();
96         }
97         addPreferencesFromResource(R.xml.security_settings);
98         root = getPreferenceScreen();
99
100         // Add options for lock/unlock screen
101         int resid = 0;
102         if (!mLockPatternUtils.isSecure()) {
103             if (mLockPatternUtils.isLockScreenDisabled()) {
104                 resid = R.xml.security_settings_lockscreen;
105             } else {
106                 resid = R.xml.security_settings_chooser;
107             }
108         } else {
109             switch (mLockPatternUtils.getKeyguardStoredPasswordQuality()) {
110                 case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
111                     resid = R.xml.security_settings_pattern;
112                     break;
113                 case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
114                     resid = R.xml.security_settings_pin;
115                     break;
116                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
117                 case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
118                 case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
119                     resid = R.xml.security_settings_password;
120                     break;
121             }
122         }
123         addPreferencesFromResource(resid);
124
125
126         // Add options for device encryption
127         DevicePolicyManager dpm =
128                 (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
129
130         switch (dpm.getStorageEncryptionStatus()) {
131         case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
132             // The device is currently encrypted.
133             addPreferencesFromResource(R.xml.security_settings_encrypted);
134             break;
135         case DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE:
136             // This device supports encryption but isn't encrypted.
137             addPreferencesFromResource(R.xml.security_settings_unencrypted);
138             break;
139         }
140
141         // lock after preference
142         mLockAfter = (ListPreference) root.findPreference(KEY_LOCK_AFTER_TIMEOUT);
143         if (mLockAfter != null) {
144             setupLockAfterPreference();
145             updateLockAfterPreferenceSummary();
146         }
147
148         // visible pattern
149         mVisiblePattern = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_PATTERN);
150
151         // tactile feedback. Should be common to all unlock preference screens.
152         mTactileFeedback = (CheckBoxPreference) root.findPreference(KEY_TACTILE_FEEDBACK_ENABLED);
153         if (!((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
154             PreferenceGroup securityCategory = (PreferenceGroup)
155                     root.findPreference(KEY_SECURITY_CATEGORY);
156             if (securityCategory != null && mTactileFeedback != null) {
157                 securityCategory.removePreference(mTactileFeedback);
158             }
159         }
160
161         // Append the rest of the settings
162         addPreferencesFromResource(R.xml.security_settings_misc);
163
164         // Do not display SIM lock for CDMA phone
165         if (TelephonyManager.PHONE_TYPE_CDMA ==
166                 TelephonyManager.getDefault().getCurrentPhoneType()) {
167             root.removePreference(root.findPreference(KEY_SIM_LOCK));
168         }
169
170         // Show password
171         mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD);
172
173         // Credential storage
174         mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS);
175
176         mToggleAppInstallation = (CheckBoxPreference) findPreference(
177                 KEY_TOGGLE_INSTALL_APPLICATIONS);
178         mToggleAppInstallation.setChecked(isNonMarketAppsAllowed());
179
180         return root;
181     }
182
183     private boolean isNonMarketAppsAllowed() {
184         return Settings.Secure.getInt(getContentResolver(),
185                                       Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0;
186     }
187
188     private void setNonMarketAppsAllowed(boolean enabled) {
189         // Change the system setting
190         Settings.Secure.putInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS,
191                                 enabled ? 1 : 0);
192     }
193
194     private void warnAppInstallation() {
195         // TODO: DialogFragment?
196         mWarnInstallApps = new AlertDialog.Builder(getActivity()).setTitle(
197                 getResources().getString(R.string.error_title))
198                 .setIcon(com.android.internal.R.drawable.ic_dialog_alert)
199                 .setMessage(getResources().getString(R.string.install_all_warning))
200                 .setPositiveButton(android.R.string.yes, this)
201                 .setNegativeButton(android.R.string.no, null)
202                 .show();
203     }
204
205     public void onClick(DialogInterface dialog, int which) {
206         if (dialog == mWarnInstallApps && which == DialogInterface.BUTTON_POSITIVE) {
207             setNonMarketAppsAllowed(true);
208             mToggleAppInstallation.setChecked(true);
209         }
210     }
211
212     @Override
213     public void onDestroy() {
214         super.onDestroy();
215         if (mWarnInstallApps != null) {
216             mWarnInstallApps.dismiss();
217         }
218     }
219
220     private void setupLockAfterPreference() {
221         // Compatible with pre-Froyo
222         long currentTimeout = Settings.Secure.getLong(getContentResolver(),
223                 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000);
224         mLockAfter.setValue(String.valueOf(currentTimeout));
225         mLockAfter.setOnPreferenceChangeListener(this);
226         final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0);
227         final long displayTimeout = Math.max(0,
228                 Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0));
229         if (adminTimeout > 0) {
230             // This setting is a slave to display timeout when a device policy is enforced.
231             // As such, maxLockTimeout = adminTimeout - displayTimeout.
232             // If there isn't enough time, shows "immediately" setting.
233             disableUnusableTimeouts(Math.max(0, adminTimeout - displayTimeout));
234         }
235     }
236
237     private void updateLockAfterPreferenceSummary() {
238         // Update summary message with current value
239         long currentTimeout = Settings.Secure.getLong(getContentResolver(),
240                 Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 0);
241         final CharSequence[] entries = mLockAfter.getEntries();
242         final CharSequence[] values = mLockAfter.getEntryValues();
243         int best = 0;
244         for (int i = 0; i < values.length; i++) {
245             long timeout = Long.valueOf(values[i].toString());
246             if (currentTimeout >= timeout) {
247                 best = i;
248             }
249         }
250         mLockAfter.setSummary(getString(R.string.lock_after_timeout_summary, entries[best]));
251     }
252
253     private void disableUnusableTimeouts(long maxTimeout) {
254         final CharSequence[] entries = mLockAfter.getEntries();
255         final CharSequence[] values = mLockAfter.getEntryValues();
256         ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>();
257         ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>();
258         for (int i = 0; i < values.length; i++) {
259             long timeout = Long.valueOf(values[i].toString());
260             if (timeout <= maxTimeout) {
261                 revisedEntries.add(entries[i]);
262                 revisedValues.add(values[i]);
263             }
264         }
265         if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) {
266             mLockAfter.setEntries(
267                     revisedEntries.toArray(new CharSequence[revisedEntries.size()]));
268             mLockAfter.setEntryValues(
269                     revisedValues.toArray(new CharSequence[revisedValues.size()]));
270             final int userPreference = Integer.valueOf(mLockAfter.getValue());
271             if (userPreference <= maxTimeout) {
272                 mLockAfter.setValue(String.valueOf(userPreference));
273             } else {
274                 // There will be no highlighted selection since nothing in the list matches
275                 // maxTimeout. The user can still select anything less than maxTimeout.
276                 // TODO: maybe append maxTimeout to the list and mark selected.
277             }
278         }
279         mLockAfter.setEnabled(revisedEntries.size() > 0);
280     }
281
282     @Override
283     public void onResume() {
284         super.onResume();
285
286         // Make sure we reload the preference hierarchy since some of these settings
287         // depend on others...
288         createPreferenceHierarchy();
289
290         final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
291         if (mVisiblePattern != null) {
292             mVisiblePattern.setChecked(lockPatternUtils.isVisiblePatternEnabled());
293         }
294         if (mTactileFeedback != null) {
295             mTactileFeedback.setChecked(lockPatternUtils.isTactileFeedbackEnabled());
296         }
297
298         mShowPassword.setChecked(Settings.System.getInt(getContentResolver(),
299                 Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
300
301         KeyStore.State state = KeyStore.getInstance().state();
302         mResetCredentials.setEnabled(state != KeyStore.State.UNINITIALIZED);
303     }
304
305     @Override
306     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
307         final String key = preference.getKey();
308
309         final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils();
310         if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
311             startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
312                     SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
313         } else if (KEY_LOCK_ENABLED.equals(key)) {
314             lockPatternUtils.setLockPatternEnabled(isToggled(preference));
315         } else if (KEY_VISIBLE_PATTERN.equals(key)) {
316             lockPatternUtils.setVisiblePatternEnabled(isToggled(preference));
317         } else if (KEY_TACTILE_FEEDBACK_ENABLED.equals(key)) {
318             lockPatternUtils.setTactileFeedbackEnabled(isToggled(preference));
319         } else if (preference == mShowPassword) {
320             Settings.System.putInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD,
321                     mShowPassword.isChecked() ? 1 : 0);
322         } else if (preference == mToggleAppInstallation) {
323             if (mToggleAppInstallation.isChecked()) {
324                 mToggleAppInstallation.setChecked(false);
325                 warnAppInstallation();
326             } else {
327                 setNonMarketAppsAllowed(false);
328             }
329         } else {
330             // If we didn't handle it, let preferences handle it.
331             return super.onPreferenceTreeClick(preferenceScreen, preference);
332         }
333
334         return true;
335     }
336
337     private boolean isToggled(Preference pref) {
338         return ((CheckBoxPreference) pref).isChecked();
339     }
340
341     /**
342      * see confirmPatternThenDisableAndClear
343      */
344     @Override
345     public void onActivityResult(int requestCode, int resultCode, Intent data) {
346         super.onActivityResult(requestCode, resultCode, data);
347         createPreferenceHierarchy();
348     }
349
350     public boolean onPreferenceChange(Preference preference, Object value) {
351         if (preference == mLockAfter) {
352             int timeout = Integer.parseInt((String) value);
353             try {
354                 Settings.Secure.putInt(getContentResolver(),
355                         Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout);
356             } catch (NumberFormatException e) {
357                 Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e);
358             }
359             updateLockAfterPreferenceSummary();
360         }
361         return true;
362     }
363 }