diff options
-rw-r--r-- | AndroidManifest.xml | 20 | ||||
-rw-r--r-- | res/layout/credentials_dialog.xml (renamed from res/layout/credentials_password_dialog.xml) | 55 | ||||
-rw-r--r-- | res/layout/credentials_unlock_dialog.xml | 49 | ||||
-rw-r--r-- | res/values/strings.xml | 82 | ||||
-rw-r--r-- | res/values/styles.xml | 6 | ||||
-rw-r--r-- | res/xml/security_settings_misc.xml | 83 | ||||
-rw-r--r-- | src/com/android/settings/CredentialInstaller.java | 85 | ||||
-rw-r--r-- | src/com/android/settings/CredentialStorage.java | 230 | ||||
-rw-r--r-- | src/com/android/settings/SecuritySettings.java | 507 |
9 files changed, 506 insertions, 611 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0f2390c..9caecec 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -626,14 +626,6 @@ android:resource="@id/security_settings" /> </activity> - <activity android:name="CredentialInstaller" - android:theme="@android:style/Theme.Translucent.NoTitleBar"> - <intent-filter> - <action android:name="android.credentials.SYSTEM_INSTALL" /> - <category android:name="android.intent.category.DEFAULT" /> - </intent-filter> - </activity> - <activity android:name="Settings$PrivacySettingsActivity" android:theme="@android:style/Theme.Holo" android:label="@string/privacy_settings_title" @@ -651,6 +643,18 @@ android:resource="@id/privacy_settings" /> </activity> + <activity android:name="CredentialStorage" + android:theme="@style/Transparent" + android:configChanges="orientation|keyboardHidden"> + <intent-filter> + <action android:name="com.android.credentials.UNLOCK" /> + <action android:name="com.android.credentials.INSTALL" /> + <action android:name="com.android.credentials.SET_PASSWORD" /> + <action android:name="com.android.credentials.RESET" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + <activity android:name="DeviceAdminSettings" android:label="@string/device_admin_settings_title" android:theme="@style/TallTitleBarTheme" diff --git a/res/layout/credentials_password_dialog.xml b/res/layout/credentials_dialog.xml index 440a107..506b3d6 100644 --- a/res/layout/credentials_password_dialog.xml +++ b/res/layout/credentials_dialog.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project +<!-- Copyright (C) 2011 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" @@ -27,47 +27,54 @@ <TextView android:id="@+id/hint" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textSize="@dimen/vpn_connect_normal_text_size" - android:text="@string/credentials_first_time_hint" - android:layout_marginBottom="10sp" - android:visibility="gone"/> + android:layout_marginBottom="10sp"/> <TextView android:id="@+id/error" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="10sp" android:textColor="@color/red" android:textStyle="bold" android:visibility="gone"/> <TextView android:id="@+id/old_password_prompt" - android:layout_width="match_parent" + android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/credentials_old_password" android:visibility="gone"/> + <EditText android:id="@+id/old_password" android:layout_width="match_parent" android:layout_height="wrap_content" - android:password="True" - android:singleLine="True" + android:password="true" + android:singleLine="true" android:visibility="gone"/> - <TextView android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/credentials_new_password" /> - <EditText android:id="@+id/new_password" + <LinearLayout android:id="@+id/new_passwords" + android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:password="True" - android:singleLine="True"/> + android:layout_height="match_parent" + android:visibility="gone"> - <TextView android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/credentials_confirm_password" /> - <EditText android:id="@+id/confirm_password" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:password="True" - android:singleLine="True"/> + <TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/credentials_new_password"/> + + <EditText android:id="@+id/new_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:password="true" + android:singleLine="true"/> + + <TextView android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/credentials_confirm_password"/> + <EditText android:id="@+id/confirm_password" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:password="true" + android:singleLine="true"/> + </LinearLayout> </LinearLayout> </ScrollView> diff --git a/res/layout/credentials_unlock_dialog.xml b/res/layout/credentials_unlock_dialog.xml deleted file mode 100644 index a538807..0000000 --- a/res/layout/credentials_unlock_dialog.xml +++ /dev/null @@ -1,49 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2009 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:padding="15dip"> - - <TextView android:id="@+id/hint" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textSize="@dimen/vpn_connect_normal_text_size" - android:text="@string/credentials_unlock_hint" - android:layout_marginBottom="10sp" - android:visibility="gone"/> - - <TextView android:id="@+id/error" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textColor="@color/red" - android:textStyle="bold" - android:visibility="gone"/> - - <EditText android:id="@+id/old_password" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:password="True" - android:singleLine="True"/> - - </LinearLayout> -</ScrollView> diff --git a/res/values/strings.xml b/res/values/strings.xml index 42c846d..5a2ecca 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2830,55 +2830,55 @@ found in the list of installed applications.</string> <!-- A secret edit field's grayed out value when it has not been set --> <string name="vpn_secret_not_set">(not set)</string> - <!-- Title of preference group for credential storage settings --> - <string name="credentials_category">Credential storage</string> - <!-- Title of preference to enable/dislable access to credential storage --> + <!-- Title of preference group for credential storage settings [CHAR LIMIT=30] --> + <string name="credentials_title">Credential storage</string> + <!-- Title of preference to enable/dislable access to credential storage [CHAR LIMIT=30] --> <string name="credentials_access">Use secure credentials</string> - <!-- Summary of preference to enable/dislable access to credential storage --> + <!-- Summary of preference to enable/dislable access to credential storage [CHAR LIMIT=NONE] --> <string name="credentials_access_summary">Allow applications to access secure certificates and other credentials</string> - <!-- Title of dialog to enable/dislable access to credential storage --> - <string name="credentials_unlock">Enter password</string> - <!-- Description of dialog to enable/dislable access to credential storage --> - <string name="credentials_unlock_hint">Enter the credential storage password.</string> - <!-- Title of preference to install certificates from SD card [CHAR LIMIT=25] --> - <string name="credentials_install_certificates" product="nosdcard">Install from USB storage</string> - <!-- Title of preference to install certificates from SD card --> - <string name="credentials_install_certificates" product="default">Install from SD card</string> - <!-- Summary of preference to install certificates from SD card [CHAR LIMIT=25] --> - <string name="credentials_install_certificates_summary" product="nosdcard">Install encrypted certificates from USB storage</string> - <!-- Summary of preference to install certificates from SD card --> - <string name="credentials_install_certificates_summary" product="default">Install encrypted certificates from SD card</string> - <!-- Title of preference to set storage password --> + <!-- Title of preference to install certificates from SD card [CHAR LIMIT=30] --> + <string name="credentials_install" product="nosdcard">Install from USB storage</string> + <!-- Title of preference to install certificates from SD card [CHAR LIMIT=30] --> + <string name="credentials_install" product="default">Install from SD card</string> + <!-- Summary of preference to install certificates from SD card [CHAR LIMIT=NONE] --> + <string name="credentials_install_summary" product="nosdcard">Install certificates from USB storage</string> + <!-- Summary of preference to install certificates from SD card [CHAR LIMIT=NONE] --> + <string name="credentials_install_summary" product="default">Install certificates from SD card</string> + <!-- Title of preference to set the password for credential storage [CHAR LIMIT=30] --> <string name="credentials_set_password">Set password</string> - <!-- Summary of preference to set storage password --> - <string name="credentials_set_password_summary">Set or change the credential storage password</string> - <!-- Title of preference to reset credential storage --> - <string name="credentials_reset">Clear storage</string> - <!-- Summary of preference to reset credential storage --> - <string name="credentials_reset_summary">Clear credential storage of all contents and reset its password</string> - <!-- Description of dialog to reset the credential storage --> - <string name="credentials_reset_hint">Are you sure you want to delete all credentials and reset the credential storage password?</string> - <!-- Description for the old-password input box --> + <!-- Summary of preference to set the password for credential storage [CHAR LIMIT=NONE] --> + <string name="credentials_set_password_summary">Set or change the password for credential storage</string> + <!-- Title of preference to reset credential storage [CHAR LIMIT=30] --> + <string name="credentials_reset">Clear credentials</string> + <!-- Summary of preference to reset credential storage [CHAR LIMIT=NONE] --> + <string name="credentials_reset_summary">Remove all the contents and reset the password</string> + + <!-- Title of dialog to enable credential storage [CHAR LIMIT=30] --> + <string name="credentials_unlock">Enter password</string> + <!-- Description of dialog to enable credential storage [CHAR LIMIT=NONE] --> + <string name="credentials_unlock_hint">Enter the password for credential storage.</string> + <!-- Description of dialog to set the password for credential storage [CHAR LIMIT=NONE] --> + <string name="credentials_password_hint">Set the password for credential storage. It must have at least 8 characters.</string> + <!-- Description of the input box for the old password [CHAR LIMIT=30] --> <string name="credentials_old_password">Current password:</string> - <!-- Description for the new-password input box --> + <!-- Description of the input box for the new password [CHAR LIMIT=30] --> <string name="credentials_new_password">New password:</string> - <!-- Description for the confirm-new-password input box --> + <!-- Description of the input box to confirm the new password [CHAR LIMIT=30] --> <string name="credentials_confirm_password">Confirm new password:</string> - <!-- Description when user set up the storage for the very first time --> - <string name="credentials_first_time_hint">Set a password for the credential storage (at least 8 characters).</string> - <string name="credentials_wrong_password">Please enter the correct password.</string> - <string name="credentials_reset_warning">Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.</string> - <string name="credentials_reset_warning_plural">Please enter the correct password. You have <xliff:g id="number" example="5">%1$d</xliff:g> more tries to enter the correct password before the credential storage is erased.</string> + <!-- Description of dialog to reset credential storage [CHAR LIMIT=NONE] --> + <string name="credentials_reset_hint">All the contents will be removed, and the password will be reset. Are you sure about that?</string> + <!-- Error message [CHAR LIMIT=NONE] --> <string name="credentials_passwords_mismatch">Passwords do not match.</string> - <string name="credentials_passwords_empty">You must enter and confirm a password.</string> - <string name="credentials_password_empty">Please enter the password.</string> - <string name="credentials_password_too_short">The password must have at least 8 characters.</string> - <!-- toast message --> - <string name="credentials_erased">The credential storage is erased.</string> - <!-- toast message --> + <!-- Error message [CHAR LIMIT=NONE] --> + <string name="credentials_wrong_password">Incorrect password.</string> + <!-- Error message [CHAR LIMIT=NONE] --> + <string name="credentials_reset_warning">Incorrect password. You have one more chance before credential storage is erased.</string> + <!-- Error message [CHAR LIMIT=NONE] --> + <string name="credentials_reset_warning_plural">Incorrect password. You have <xliff:g id="number" example="5">%1$d</xliff:g> more chances before credential storage is erased.</string> + <!-- Toast message [CHAR LIMIT=30] --> + <string name="credentials_erased">Credential storage is erased.</string> + <!-- Toast message [CHAR LIMIT=30] --> <string name="credentials_enabled">Credential storage is enabled.</string> - <!-- toast message --> - <string name="credentials_disabled">Credential storage is disabled.</string> <!-- Sound settings screen, setting check box label --> <string name="emergency_tone_title">Emergency tone</string> diff --git a/res/values/styles.xml b/res/values/styles.xml index c361fa9..a49cd0a 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -114,4 +114,10 @@ <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> </style> + + <style name="Transparent"> + <item name="android:windowBackground">@android:color/transparent</item> + <item name="android:windowNoTitle">true</item> + <item name="android:windowIsFloating">true</item> + </style> </resources> diff --git a/res/xml/security_settings_misc.xml b/res/xml/security_settings_misc.xml new file mode 100644 index 0000000..e67542b --- /dev/null +++ b/res/xml/security_settings_misc.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2011 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + + <PreferenceCategory android:key="sim_lock" + android:title="@string/sim_lock_settings_title" + android:persistent="false"> + + <Preference android:title="@string/sim_lock_settings_category" + android:persistent="false"> + <intent android:action="android.intent.action.MAIN" + android:targetPackage="com.android.settings" + android:targetClass="com.android.settings.IccLockSettings"/> + </Preference> + </PreferenceCategory> + + <PreferenceCategory android:title="@string/security_passwords_title" + android:persistent="false"> + + <CheckBoxPreference android:key="show_password" + android:title="@string/show_password" + android:summary="@string/show_password_summary" + android:persistent="false"/> + </PreferenceCategory> + + <PreferenceCategory android:title="@string/device_admin_title" + android:persistent="false"> + <Preference android:title="@string/manage_device_admin" + android:summary="@string/manage_device_admin_summary" + android:persistent="false"> + <intent android:action="android.intent.action.MAIN" + android:targetPackage="com.android.settings" + android:targetClass="com.android.settings.DeviceAdminSettings"/> + </Preference> + </PreferenceCategory> + + <PreferenceCategory android:title="@string/credentials_title" + android:persistent="false"> + <CheckBoxPreference android:key="enable_credentials" + android:title="@string/credentials_access" + android:summary="@string/credentials_access_summary" + android:persistent="false"/> + + <Preference android:title="@string/credentials_install" + android:summary="@string/credentials_install_summary" + android:persistent="false"> + <intent android:action="android.credentials.INSTALL" + android:targetPackage="com.android.certinstaller" + android:targetClass="com.android.certinstaller.CertInstallerMain"/> + </Preference> + + <Preference android:title="@string/credentials_set_password" + android:summary="@string/credentials_set_password_summary" + android:persistent="false"> + <intent android:action="com.android.credentials.SET_PASSWORD" + android:targetPackage="com.android.settings" + android:targetClass="com.android.settings.CredentialStorage"/> + </Preference> + + <Preference android:key="reset_credentials" + android:title="@string/credentials_reset" + android:summary="@string/credentials_reset_summary" + android:persistent="false"> + <intent android:action="com.android.credentials.RESET" + android:targetPackage="com.android.settings" + android:targetClass="com.android.settings.CredentialStorage"/> + </Preference> + </PreferenceCategory> +</PreferenceScreen> diff --git a/src/com/android/settings/CredentialInstaller.java b/src/com/android/settings/CredentialInstaller.java deleted file mode 100644 index 7c63b1c..0000000 --- a/src/com/android/settings/CredentialInstaller.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.security.Credentials; -import android.security.KeyStore; -import android.util.Log; - -/** - * Installs credentials to the system keystore. It reacts to the - * {@link Credentials#SYSTEM_INSTALL_ACTION} intent. All the key-value pairs in - * the intent are installed to the system keystore. For security reason, the - * current implementation limits that only com.android.certinstaller can use - * this service. - */ -public class CredentialInstaller extends Activity { - private static final String TAG = "CredentialInstaller"; - private static final String UNLOCKING = "ulck"; - - private KeyStore mKeyStore = KeyStore.getInstance(); - private boolean mUnlocking = false; - - @Override - protected void onResume() { - super.onResume(); - - if (!"com.android.certinstaller".equals(getCallingPackage())) finish(); - - if (isKeyStoreUnlocked()) { - install(); - } else if (!mUnlocking) { - mUnlocking = true; - Credentials.getInstance().unlock(this); - return; - } - finish(); - } - - @Override - protected void onSaveInstanceState(Bundle outStates) { - super.onSaveInstanceState(outStates); - outStates.putBoolean(UNLOCKING, mUnlocking); - } - - @Override - protected void onRestoreInstanceState(Bundle savedStates) { - super.onRestoreInstanceState(savedStates); - mUnlocking = savedStates.getBoolean(UNLOCKING); - } - - private void install() { - Intent intent = getIntent(); - Bundle bundle = (intent == null) ? null : intent.getExtras(); - if (bundle == null) return; - for (String key : bundle.keySet()) { - byte[] data = bundle.getByteArray(key); - if (data == null) continue; - boolean success = mKeyStore.put(key.getBytes(), data); - Log.d(TAG, "install " + key + ": " + data.length + " success? " + success); - if (!success) return; - } - setResult(RESULT_OK); - } - - private boolean isKeyStoreUnlocked() { - return (mKeyStore.test() == KeyStore.NO_ERROR); - } -} diff --git a/src/com/android/settings/CredentialStorage.java b/src/com/android/settings/CredentialStorage.java new file mode 100644 index 0000000..9d5a603 --- /dev/null +++ b/src/com/android/settings/CredentialStorage.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.security.KeyStore; +import android.text.Editable; +import android.text.TextWatcher; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.UnsupportedEncodingException; + +public class CredentialStorage extends Activity implements TextWatcher, + DialogInterface.OnClickListener, DialogInterface.OnDismissListener { + + public static final String ACTION_UNLOCK = "com.android.credentials.UNLOCK"; + public static final String ACTION_SET_PASSWORD = "com.android.credentials.SET_PASSWORD"; + public static final String ACTION_INSTALL = "com.android.credentials.INSTALL"; + public static final String ACTION_RESET = "com.android.credentials.RESET"; + + private static final String TAG = "CredentialStorage"; + + private KeyStore mKeyStore = KeyStore.getInstance(); + private boolean mSubmit = false; + private Bundle mBundle; + + private TextView mOldPassword; + private TextView mNewPassword; + private TextView mConfirmPassword; + private TextView mError; + private Button mButton; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + String action = intent.getAction(); + int state = mKeyStore.test(); + + if (ACTION_RESET.equals(action)) { + showResetDialog(); + } else if (ACTION_SET_PASSWORD.equals(action)) { + showPasswordDialog(state == KeyStore.UNINITIALIZED); + } else { + if (ACTION_INSTALL.equals(action) && + "com.android.certinstaller".equals(getCallingPackage())) { + mBundle = intent.getExtras(); + } + if (state == KeyStore.UNINITIALIZED) { + showPasswordDialog(true); + } else if (state == KeyStore.LOCKED) { + showUnlockDialog(); + } else { + install(); + finish(); + } + } + } + + private void install() { + if (mBundle != null && !mBundle.isEmpty()) { + try { + for (String key : mBundle.keySet()) { + byte[] value = mBundle.getByteArray(key); + if (value != null && !mKeyStore.put(key.getBytes("UTF-8"), value)) { + Log.e(TAG, "Failed to install " + key); + return; + } + } + setResult(RESULT_OK); + } catch (UnsupportedEncodingException e) { + // Should never happen. + throw new RuntimeException(e); + } + } + } + + private void showResetDialog() { + AlertDialog dialog = new AlertDialog.Builder(this) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(R.string.credentials_reset_hint) + .setNeutralButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + dialog.setOnDismissListener(this); + dialog.show(); + } + + private void showPasswordDialog(boolean firstTime) { + View view = View.inflate(this, R.layout.credentials_dialog, null); + + ((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_password_hint); + if (!firstTime) { + view.findViewById(R.id.old_password_prompt).setVisibility(View.VISIBLE); + mOldPassword = (TextView) view.findViewById(R.id.old_password); + mOldPassword.setVisibility(View.VISIBLE); + mOldPassword.addTextChangedListener(this); + } + view.findViewById(R.id.new_passwords).setVisibility(View.VISIBLE); + mNewPassword = (TextView) view.findViewById(R.id.new_password); + mNewPassword.addTextChangedListener(this); + mConfirmPassword = (TextView) view.findViewById(R.id.confirm_password); + mConfirmPassword.addTextChangedListener(this); + mError = (TextView) view.findViewById(R.id.error); + + AlertDialog dialog = new AlertDialog.Builder(this) + .setView(view) + .setTitle(R.string.credentials_set_password) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + dialog.setOnDismissListener(this); + dialog.show(); + mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); + mButton.setEnabled(false); + } + + private void showUnlockDialog() { + View view = View.inflate(this, R.layout.credentials_dialog, null); + + ((TextView) view.findViewById(R.id.hint)).setText(R.string.credentials_unlock_hint); + mOldPassword = (TextView) view.findViewById(R.id.old_password); + mOldPassword.setVisibility(View.VISIBLE); + mOldPassword.addTextChangedListener(this); + mError = (TextView) view.findViewById(R.id.error); + + AlertDialog dialog = new AlertDialog.Builder(this) + .setView(view) + .setTitle(R.string.credentials_unlock) + .setPositiveButton(android.R.string.ok, this) + .setNegativeButton(android.R.string.cancel, this) + .create(); + dialog.setOnDismissListener(this); + dialog.show(); + mButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); + mButton.setEnabled(false); + } + + public void afterTextChanged(Editable editable) { + if ((mOldPassword == null || mOldPassword.getText().length() > 0) && + (mNewPassword == null || mNewPassword.getText().length() >= 8) && + (mConfirmPassword == null || mConfirmPassword.getText().length() >= 8)) { + mButton.setEnabled(true); + } else { + mButton.setEnabled(false); + } + } + + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + public void onTextChanged(CharSequence s,int start, int before, int count) { + } + + public void onClick(DialogInterface dialog, int button) { + mSubmit = (button == DialogInterface.BUTTON_POSITIVE); + if (button == DialogInterface.BUTTON_NEUTRAL) { + mKeyStore.reset(); + Toast.makeText(this, R.string.credentials_erased, Toast.LENGTH_SHORT).show(); + } + } + + public void onDismiss(DialogInterface dialog) { + if (mSubmit) { + mSubmit = false; + mError.setVisibility(View.VISIBLE); + + if (mNewPassword == null) { + mKeyStore.unlock(mOldPassword.getText().toString()); + } else { + String newPassword = mNewPassword.getText().toString(); + String confirmPassword = mConfirmPassword.getText().toString(); + + if (!newPassword.equals(confirmPassword)) { + mError.setText(R.string.credentials_passwords_mismatch); + ((AlertDialog) dialog).show(); + return; + } else if (mOldPassword == null) { + mKeyStore.password(newPassword); + } else { + mKeyStore.password(mOldPassword.getText().toString(), newPassword); + } + } + + int error = mKeyStore.getLastError(); + if (error == KeyStore.NO_ERROR) { + Toast.makeText(this, R.string.credentials_enabled, Toast.LENGTH_SHORT).show(); + install(); + } else if (error == KeyStore.UNINITIALIZED) { + Toast.makeText(this, R.string.credentials_erased, Toast.LENGTH_SHORT).show(); + } else if (error >= KeyStore.WRONG_PASSWORD) { + int count = error - KeyStore.WRONG_PASSWORD + 1; + if (count > 3) { + mError.setText(R.string.credentials_wrong_password); + } else if (count == 1) { + mError.setText(R.string.credentials_reset_warning); + } else { + mError.setText(getString(R.string.credentials_reset_warning_plural, count)); + } + ((AlertDialog) dialog).show(); + return; + } + } + finish(); + } +} diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index f8ed599..649c012 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -63,39 +63,32 @@ import java.util.Observer; */ public class SecuritySettings extends SettingsPreferenceFragment implements OnPreferenceChangeListener { - private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; - private static final String KEY_ENCRYPTION = "encryption"; // Lock Settings - private static final String PACKAGE = "com.android.settings"; - private static final String ICC_LOCK_SETTINGS = PACKAGE + ".IccLockSettings"; - + private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change"; private static final String KEY_LOCK_ENABLED = "lockenabled"; private static final String KEY_VISIBLE_PATTERN = "visiblepattern"; private static final String KEY_TACTILE_FEEDBACK_ENABLED = "unlock_tactile_feedback"; private static final String KEY_SECURITY_CATEGORY = "security_category"; - - private CheckBoxPreference mVisiblePattern; - private CheckBoxPreference mTactileFeedback; - - private CheckBoxPreference mShowPassword; + private static final String KEY_LOCK_AFTER_TIMEOUT = "lock_after_timeout"; + private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; // Location Settings - private static final String LOCATION_CATEGORY = "location_category"; - private static final String LOCATION_NETWORK = "location_network"; - private static final String LOCATION_GPS = "location_gps"; - private static final String ASSISTED_GPS = "assisted_gps"; - private static final String USE_LOCATION = "location_use_for_services"; - private static final String LOCK_AFTER_TIMEOUT_KEY = "lock_after_timeout"; - private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123; - private static final int FALLBACK_LOCK_AFTER_TIMEOUT_VALUE = 5000; // compatible with pre-Froyo + private static final String KEY_LOCATION_CATEGORY = "location_category"; + private static final String KEY_LOCATION_NETWORK = "location_network"; + private static final String KEY_LOCATION_GPS = "location_gps"; + private static final String KEY_ASSISTED_GPS = "assisted_gps"; + private static final String KEY_USE_LOCATION = "location_use_for_services"; + + // Misc Settings + private static final String KEY_SIM_LOCK = "sim_lock"; + private static final String KEY_SHOW_PASSWORD = "show_password"; + private static final String KEY_ENABLE_CREDENTIALS = "enable_credentials"; + private static final String KEY_RESET_CREDENTIALS = "reset_credentials"; private static final String TAG = "SecuritySettings"; - // Credential storage - private final CredentialStorage mCredentialStorage = new CredentialStorage(); - private CheckBoxPreference mNetwork; private CheckBoxPreference mGps; private CheckBoxPreference mAssistedGps; @@ -112,13 +105,15 @@ public class SecuritySettings extends SettingsPreferenceFragment private LockPatternUtils mLockPatternUtils; private ListPreference mLockAfter; - private SettingsObserver mSettingsObserver; + private Observer mSettingsObserver; - private final class SettingsObserver implements Observer { - public void update(Observable o, Object arg) { - updateToggles(); - } - } + private CheckBoxPreference mVisiblePattern; + private CheckBoxPreference mTactileFeedback; + + private CheckBoxPreference mShowPassword; + + private CheckBoxPreference mEnableCredentials; + private Preference mResetCredentials; @Override public void onCreate(Bundle savedInstanceState) { @@ -129,10 +124,6 @@ public class SecuritySettings extends SettingsPreferenceFragment mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE); mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); - - createPreferenceHierarchy(); - - updateToggles(); } @Override @@ -144,31 +135,33 @@ public class SecuritySettings extends SettingsPreferenceFragment new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, null); mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null); - mContentQueryMap.addObserver(mSettingsObserver = new SettingsObserver()); } @Override public void onStop() { super.onStop(); - mContentQueryMap.deleteObserver(mSettingsObserver); + if (mSettingsObserver != null) { + mContentQueryMap.deleteObserver(mSettingsObserver); + } } private PreferenceScreen createPreferenceHierarchy() { - PreferenceScreen root = this.getPreferenceScreen(); + PreferenceScreen root = getPreferenceScreen(); if (root != null) { root.removeAll(); } addPreferencesFromResource(R.xml.security_settings); - root = this.getPreferenceScreen(); + root = getPreferenceScreen(); - mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK); - mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS); - mAssistedGps = (CheckBoxPreference) getPreferenceScreen().findPreference(ASSISTED_GPS); + mNetwork = (CheckBoxPreference) root.findPreference(KEY_LOCATION_NETWORK); + mGps = (CheckBoxPreference) root.findPreference(KEY_LOCATION_GPS); + mAssistedGps = (CheckBoxPreference) root.findPreference(KEY_ASSISTED_GPS); if (GoogleLocationSettingHelper.isAvailable(getActivity())) { // GSF present, Add setting for 'Use My Location' - PreferenceGroup locationCat = (PreferenceGroup) root.findPreference(LOCATION_CATEGORY); + PreferenceGroup locationCat = + (PreferenceGroup) root.findPreference(KEY_LOCATION_CATEGORY); CheckBoxPreference useLocation = new CheckBoxPreference(getActivity()); - useLocation.setKey(USE_LOCATION); + useLocation.setKey(KEY_USE_LOCATION); useLocation.setTitle(R.string.use_location_title); useLocation.setSummaryOn(R.string.use_location_summary_enabled); useLocation.setSummaryOff(R.string.use_location_summary_disabled); @@ -181,8 +174,6 @@ public class SecuritySettings extends SettingsPreferenceFragment mUseLocation = useLocation; } - PreferenceManager pm = getPreferenceManager(); - // Add options for device encryption // TODO: It still needs to be determined how a device specifies that it supports // encryption. That mechanism needs to be checked before adding the following code @@ -215,98 +206,62 @@ public class SecuritySettings extends SettingsPreferenceFragment addPreferencesFromResource(resid); // lock after preference - mLockAfter = setupLockAfterPreference(pm); - updateLockAfterPreferenceSummary(); + mLockAfter = (ListPreference) root.findPreference(KEY_LOCK_AFTER_TIMEOUT); + if (mLockAfter != null) { + setupLockAfterPreference(); + updateLockAfterPreferenceSummary(); + } // visible pattern - mVisiblePattern = (CheckBoxPreference) pm.findPreference(KEY_VISIBLE_PATTERN); + mVisiblePattern = (CheckBoxPreference) root.findPreference(KEY_VISIBLE_PATTERN); // tactile feedback. Should be common to all unlock preference screens. - mTactileFeedback = (CheckBoxPreference) pm.findPreference(KEY_TACTILE_FEEDBACK_ENABLED); + mTactileFeedback = (CheckBoxPreference) root.findPreference(KEY_TACTILE_FEEDBACK_ENABLED); if (!((Vibrator) getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) { PreferenceGroup securityCategory = (PreferenceGroup) - pm.findPreference(KEY_SECURITY_CATEGORY); + root.findPreference(KEY_SECURITY_CATEGORY); if (securityCategory != null && mTactileFeedback != null) { securityCategory.removePreference(mTactileFeedback); } } - int activePhoneType = TelephonyManager.getDefault().getPhoneType(); - - // do not display SIM lock for CDMA phone - if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) - { - PreferenceScreen simLockPreferences = getPreferenceManager() - .createPreferenceScreen(getActivity()); - simLockPreferences.setTitle(R.string.sim_lock_settings_category); - // Intent to launch SIM lock settings - simLockPreferences.setIntent(new Intent().setClassName(PACKAGE, ICC_LOCK_SETTINGS)); - PreferenceCategory simLockCat = new PreferenceCategory(getActivity()); - simLockCat.setTitle(R.string.sim_lock_settings_title); - root.addPreference(simLockCat); - simLockCat.addPreference(simLockPreferences); + // Append the rest of the settings + addPreferencesFromResource(R.xml.security_settings_misc); + + // Do not display SIM lock for CDMA phone + if (TelephonyManager.PHONE_TYPE_CDMA == TelephonyManager.getDefault().getPhoneType()) { + root.removePreference(root.findPreference(KEY_SIM_LOCK)); } - // Passwords - PreferenceCategory passwordsCat = new PreferenceCategory(getActivity()); - passwordsCat.setTitle(R.string.security_passwords_title); - root.addPreference(passwordsCat); - - CheckBoxPreference showPassword = mShowPassword = new CheckBoxPreference(getActivity()); - showPassword.setKey("show_password"); - showPassword.setTitle(R.string.show_password); - showPassword.setSummary(R.string.show_password_summary); - showPassword.setPersistent(false); - passwordsCat.addPreference(showPassword); - - // Device policies - PreferenceCategory devicePoliciesCat = new PreferenceCategory(getActivity()); - devicePoliciesCat.setTitle(R.string.device_admin_title); - root.addPreference(devicePoliciesCat); - - Preference deviceAdminButton = new Preference(getActivity()); - deviceAdminButton.setTitle(R.string.manage_device_admin); - deviceAdminButton.setSummary(R.string.manage_device_admin_summary); - Intent deviceAdminIntent = new Intent(); - deviceAdminIntent.setClass(getActivity(), DeviceAdminSettings.class); - deviceAdminButton.setIntent(deviceAdminIntent); - devicePoliciesCat.addPreference(deviceAdminButton); + // Show password + mShowPassword = (CheckBoxPreference) root.findPreference(KEY_SHOW_PASSWORD); // Credential storage - PreferenceCategory credentialsCat = new PreferenceCategory(getActivity()); - credentialsCat.setTitle(R.string.credentials_category); - root.addPreference(credentialsCat); - mCredentialStorage.createPreferences(credentialsCat); + mEnableCredentials = (CheckBoxPreference) root.findPreference(KEY_ENABLE_CREDENTIALS); + mEnableCredentials.setOnPreferenceChangeListener(this); + mResetCredentials = root.findPreference(KEY_RESET_CREDENTIALS); return root; } - private ListPreference setupLockAfterPreference(PreferenceManager pm) { - ListPreference result = (ListPreference) pm.findPreference(LOCK_AFTER_TIMEOUT_KEY); - if (result != null) { - int lockAfterValue = Settings.Secure.getInt(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, - FALLBACK_LOCK_AFTER_TIMEOUT_VALUE); - result.setValue(String.valueOf(lockAfterValue)); - result.setOnPreferenceChangeListener(this); - final long adminTimeout = mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0; - final ContentResolver cr = getContentResolver(); - final long displayTimeout = Math.max(0, - Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, 0)); - if (adminTimeout > 0) { - // This setting is a slave to display timeout when a device policy is enforced. - // As such, maxLockTimeout = adminTimeout - displayTimeout. - // If there isn't enough time, shows "immediately" setting. - disableUnusableTimeouts(result, Math.max(0, adminTimeout - displayTimeout)); - } + private void setupLockAfterPreference() { + // Compatible with pre-Froyo + long currentTimeout = Settings.Secure.getLong(getContentResolver(), + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 5000); + mLockAfter.setValue(String.valueOf(currentTimeout)); + mLockAfter.setOnPreferenceChangeListener(this); + final long adminTimeout = (mDPM != null ? mDPM.getMaximumTimeToLock(null) : 0); + final long displayTimeout = Math.max(0, + Settings.System.getInt(getContentResolver(), SCREEN_OFF_TIMEOUT, 0)); + if (adminTimeout > 0) { + // This setting is a slave to display timeout when a device policy is enforced. + // As such, maxLockTimeout = adminTimeout - displayTimeout. + // If there isn't enough time, shows "immediately" setting. + disableUnusableTimeouts(Math.max(0, adminTimeout - displayTimeout)); } - return result; } private void updateLockAfterPreferenceSummary() { - // Not all security types have a "lock after" preference, so ignore those that don't. - if (mLockAfter == null) return; - // Update summary message with current value long currentTimeout = Settings.Secure.getLong(getContentResolver(), Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, 0); @@ -319,14 +274,12 @@ public class SecuritySettings extends SettingsPreferenceFragment best = i; } } - String summary = mLockAfter.getContext() - .getString(R.string.lock_after_timeout_summary, entries[best]); - mLockAfter.setSummary(summary); + mLockAfter.setSummary(getString(R.string.lock_after_timeout_summary, entries[best])); } - private static void disableUnusableTimeouts(ListPreference pref, long maxTimeout) { - final CharSequence[] entries = pref.getEntries(); - final CharSequence[] values = pref.getEntryValues(); + private void disableUnusableTimeouts(long maxTimeout) { + final CharSequence[] entries = mLockAfter.getEntries(); + final CharSequence[] values = mLockAfter.getEntryValues(); ArrayList<CharSequence> revisedEntries = new ArrayList<CharSequence>(); ArrayList<CharSequence> revisedValues = new ArrayList<CharSequence>(); for (int i = 0; i < values.length; i++) { @@ -337,20 +290,20 @@ public class SecuritySettings extends SettingsPreferenceFragment } } if (revisedEntries.size() != entries.length || revisedValues.size() != values.length) { - pref.setEntries( + mLockAfter.setEntries( revisedEntries.toArray(new CharSequence[revisedEntries.size()])); - pref.setEntryValues( + mLockAfter.setEntryValues( revisedValues.toArray(new CharSequence[revisedValues.size()])); - final int userPreference = Integer.valueOf(pref.getValue()); + final int userPreference = Integer.valueOf(mLockAfter.getValue()); if (userPreference <= maxTimeout) { - pref.setValue(String.valueOf(userPreference)); + mLockAfter.setValue(String.valueOf(userPreference)); } else { // There will be no highlighted selection since nothing in the list matches // maxTimeout. The user can still select anything less than maxTimeout. // TODO: maybe append maxTimeout to the list and mark selected. } } - pref.setEnabled(revisedEntries.size() > 0); + mLockAfter.setEnabled(revisedEntries.size() > 0); } @Override @@ -360,6 +313,16 @@ public class SecuritySettings extends SettingsPreferenceFragment // Make sure we reload the preference hierarchy since some of these settings // depend on others... createPreferenceHierarchy(); + updateLocationToggles(); + + if (mSettingsObserver == null) { + mSettingsObserver = new Observer() { + public void update(Observable o, Object arg) { + updateLocationToggles(); + } + }; + mContentQueryMap.addObserver(mSettingsObserver); + } final LockPatternUtils lockPatternUtils = mChooseLockSettingsHelper.utils(); if (mVisiblePattern != null) { @@ -372,7 +335,10 @@ public class SecuritySettings extends SettingsPreferenceFragment mShowPassword.setChecked(Settings.System.getInt(getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1) != 0); - mCredentialStorage.resume(); + int state = KeyStore.getInstance().test(); + mEnableCredentials.setChecked(state == KeyStore.NO_ERROR); + mEnableCredentials.setEnabled(state != KeyStore.UNINITIALIZED); + mResetCredentials.setEnabled(state != KeyStore.UNINITIALIZED); } @Override @@ -419,7 +385,7 @@ public class SecuritySettings extends SettingsPreferenceFragment /* * Creates toggles for each available location provider */ - private void updateToggles() { + private void updateLocationToggles() { ContentResolver res = getContentResolver(); boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled( res, LocationManager.GPS_PROVIDER); @@ -453,7 +419,8 @@ public class SecuritySettings extends SettingsPreferenceFragment public void showPasswordDialog() { View view = View.inflate(SecuritySettings.this.getActivity(), - R.layout.credentials_password_dialog, null); + R.layout.credentials_dialog, null); + view.findViewById(R.id.new_passwords).setVisibility(View.VISIBLE); Dialog dialog = new AlertDialog.Builder(SecuritySettings.this.getActivity()) .setView(view).setTitle(R.string.credentials_set_password) @@ -521,307 +488,39 @@ public class SecuritySettings extends SettingsPreferenceFragment if (formatArgs == null || formatArgs.length == 0) { view.setText(stringId); } else { - view.setText(dialog.getContext().getString(stringId, formatArgs)); - } - view.setVisibility(View.VISIBLE); - } - } - - } - - private class CredentialStorage implements DialogInterface.OnClickListener, - DialogInterface.OnDismissListener, Preference.OnPreferenceChangeListener, - Preference.OnPreferenceClickListener { - private static final int MINIMUM_PASSWORD_LENGTH = 8; - - private final KeyStore mKeyStore = KeyStore.getInstance(); - private int mState; - private boolean mSubmit = false; - private boolean mExternal = false; - - private CheckBoxPreference mAccessCheckBox; - private Preference mInstallButton; - private Preference mPasswordButton; - private Preference mResetButton; - - void resume() { - mState = mKeyStore.test(); - updatePreferences(mState); - - Intent intent = getActivity().getIntent(); - if (!mExternal && intent != null && - Credentials.UNLOCK_ACTION.equals(intent.getAction())) { - mExternal = true; - if (mState == KeyStore.UNINITIALIZED) { - showPasswordDialog(); - } else if (mState == KeyStore.LOCKED) { - showUnlockDialog(); - } else { - // TODO: Verify if this is the right way - SecuritySettings.this.getFragmentManager().popBackStack(); - } - } - } - - private void initialize(String password) { - mKeyStore.password(password); - updatePreferences(KeyStore.NO_ERROR); - } - - private void reset() { - mKeyStore.reset(); - updatePreferences(KeyStore.UNINITIALIZED); - } - - private void lock() { - mKeyStore.lock(); - updatePreferences(KeyStore.LOCKED); - } - - private int unlock(String password) { - mKeyStore.unlock(password); - return mKeyStore.getLastError(); - } - - private int changePassword(String oldPassword, String newPassword) { - mKeyStore.password(oldPassword, newPassword); - return mKeyStore.getLastError(); - } - - public boolean onPreferenceChange(Preference preference, Object value) { - if (preference == mAccessCheckBox) { - if ((Boolean) value) { - showUnlockDialog(); - } else { - lock(); - } - return true; - } - return false; - } - - public boolean onPreferenceClick(Preference preference) { - if (preference == mInstallButton) { - Credentials.getInstance().installFromSdCard(SecuritySettings.this.getActivity()); - } else if (preference == mPasswordButton) { - showPasswordDialog(); - } else if (preference == mResetButton) { - showResetDialog(); - } else { - return false; - } - return true; - } - - public void onClick(DialogInterface dialog, int button) { - mSubmit = (button == DialogInterface.BUTTON_POSITIVE); - if (button == DialogInterface.BUTTON_NEUTRAL) { - reset(); - } - } - - public void onDismiss(DialogInterface dialog) { - // TODO: - //if (mSubmit && !isFinishing()) { - - if (mSubmit) { - mSubmit = false; - if (!checkPassword((Dialog) dialog)) { - ((Dialog) dialog).show(); - return; - } - } - updatePreferences(mState); - if (mExternal) { - // TODO: - // finish(); - } - } - - // Return true if there is no error. - private boolean checkPassword(Dialog dialog) { - String oldPassword = getText(dialog, R.id.old_password); - String newPassword = getText(dialog, R.id.new_password); - String confirmPassword = getText(dialog, R.id.confirm_password); - - if (oldPassword != null && oldPassword.length() == 0) { - showError(dialog, R.string.credentials_password_empty); - return false; - } else if (newPassword == null) { - return !checkError(dialog, unlock(oldPassword)); - } else if (newPassword.length() == 0 || confirmPassword.length() == 0) { - showError(dialog, R.string.credentials_passwords_empty); - } else if (newPassword.length() < MINIMUM_PASSWORD_LENGTH) { - showError(dialog, R.string.credentials_password_too_short); - } else if (!newPassword.equals(confirmPassword)) { - showError(dialog, R.string.credentials_passwords_mismatch); - } else if (oldPassword == null) { - initialize(newPassword); - return true; - } else { - return !checkError(dialog, changePassword(oldPassword, newPassword)); - } - return false; - } - - // Return false if there is no error. - private boolean checkError(Dialog dialog, int error) { - if (error == KeyStore.NO_ERROR) { - updatePreferences(KeyStore.NO_ERROR); - return false; - } - if (error == KeyStore.UNINITIALIZED) { - updatePreferences(KeyStore.UNINITIALIZED); - return false; - } - if (error < KeyStore.WRONG_PASSWORD) { - return false; - } - int count = error - KeyStore.WRONG_PASSWORD + 1; - if (count > 3) { - showError(dialog, R.string.credentials_wrong_password); - } else if (count == 1) { - showError(dialog, R.string.credentials_reset_warning); - } else { - showError(dialog, R.string.credentials_reset_warning_plural, count); - } - return true; - } - - private String getText(Dialog dialog, int viewId) { - TextView view = (TextView) dialog.findViewById(viewId); - return (view == null || view.getVisibility() == View.GONE) ? null : - view.getText().toString(); - } - - private void showError(Dialog dialog, int stringId, Object... formatArgs) { - TextView view = (TextView) dialog.findViewById(R.id.error); - if (view != null) { - if (formatArgs == null || formatArgs.length == 0) { - view.setText(stringId); - } else { - view.setText(dialog.getContext().getString(stringId, formatArgs)); + view.setText(getString(stringId, formatArgs)); } view.setVisibility(View.VISIBLE); } } - private void createPreferences(PreferenceCategory category) { - mAccessCheckBox = new CheckBoxPreference(SecuritySettings.this.getActivity()); - mAccessCheckBox.setTitle(R.string.credentials_access); - mAccessCheckBox.setSummary(R.string.credentials_access_summary); - mAccessCheckBox.setOnPreferenceChangeListener(this); - category.addPreference(mAccessCheckBox); - - mInstallButton = new Preference(SecuritySettings.this.getActivity()); - mInstallButton.setTitle(R.string.credentials_install_certificates); - mInstallButton.setSummary(R.string.credentials_install_certificates_summary); - mInstallButton.setOnPreferenceClickListener(this); - category.addPreference(mInstallButton); - - mPasswordButton = new Preference(SecuritySettings.this.getActivity()); - mPasswordButton.setTitle(R.string.credentials_set_password); - mPasswordButton.setSummary(R.string.credentials_set_password_summary); - mPasswordButton.setOnPreferenceClickListener(this); - category.addPreference(mPasswordButton); - - mResetButton = new Preference(SecuritySettings.this.getActivity()); - mResetButton.setTitle(R.string.credentials_reset); - mResetButton.setSummary(R.string.credentials_reset_summary); - mResetButton.setOnPreferenceClickListener(this); - category.addPreference(mResetButton); - } - - private void updatePreferences(int state) { - mAccessCheckBox.setEnabled(state != KeyStore.UNINITIALIZED); - mAccessCheckBox.setChecked(state == KeyStore.NO_ERROR); - mResetButton.setEnabled(state != KeyStore.UNINITIALIZED); - - // Show a toast message if the state is changed. - if (mState == state) { - return; - } else if (state == KeyStore.NO_ERROR) { - Toast.makeText(SecuritySettings.this.getActivity(), R.string.credentials_enabled, - Toast.LENGTH_SHORT).show(); - } else if (state == KeyStore.UNINITIALIZED) { - Toast.makeText(SecuritySettings.this.getActivity(), R.string.credentials_erased, - Toast.LENGTH_SHORT).show(); - } else if (state == KeyStore.LOCKED) { - Toast.makeText(SecuritySettings.this.getActivity(), R.string.credentials_disabled, - Toast.LENGTH_SHORT).show(); - } - mState = state; - } - - private void showUnlockDialog() { - View view = View.inflate(SecuritySettings.this.getActivity(), - R.layout.credentials_unlock_dialog, null); - - // Show extra hint only when the action comes from outside. - if (mExternal) { - view.findViewById(R.id.hint).setVisibility(View.VISIBLE); - } - - Dialog dialog = new AlertDialog.Builder(SecuritySettings.this.getActivity()) - .setView(view) - .setTitle(R.string.credentials_unlock) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, this) - .create(); - dialog.setOnDismissListener(this); - dialog.show(); - } - - private void showPasswordDialog() { - View view = View.inflate(SecuritySettings.this.getActivity(), - R.layout.credentials_password_dialog, null); - - if (mState == KeyStore.UNINITIALIZED) { - view.findViewById(R.id.hint).setVisibility(View.VISIBLE); - } else { - view.findViewById(R.id.old_password_prompt).setVisibility(View.VISIBLE); - view.findViewById(R.id.old_password).setVisibility(View.VISIBLE); - } - - Dialog dialog = new AlertDialog.Builder(SecuritySettings.this.getActivity()) - .setView(view) - .setTitle(R.string.credentials_set_password) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, this) - .create(); - dialog.setOnDismissListener(this); - dialog.show(); - } - - private void showResetDialog() { - new AlertDialog.Builder(SecuritySettings.this.getActivity()) - .setTitle(android.R.string.dialog_alert_title) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(R.string.credentials_reset_hint) - .setNeutralButton(getResources().getString(android.R.string.ok), this) - .setNegativeButton(getResources().getString(android.R.string.cancel), this) - .create().show(); - } } public boolean onPreferenceChange(Preference preference, Object value) { if (preference == mLockAfter) { - int lockAfter = Integer.parseInt((String) value); + int timeout = Integer.parseInt((String) value); try { Settings.Secure.putInt(getContentResolver(), - Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, lockAfter); + Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, timeout); } catch (NumberFormatException e) { Log.e("SecuritySettings", "could not persist lockAfter timeout setting", e); } updateLockAfterPreferenceSummary(); } else if (preference == mUseLocation) { - boolean newValue = value == null ? false : (Boolean) value; + boolean newValue = (value == null ? false : (Boolean) value); GoogleLocationSettingHelper.setUseLocationForServices(getActivity(), newValue); // We don't want to change the value immediately here, since the user may click // disagree in the dialog that pops up. When the activity we just launched exits, this // activity will be restated and the new value re-read, so the checkbox will get its // new value then. return false; + } else if (preference == mEnableCredentials) { + if (value != null && (Boolean) value) { + getActivity().startActivity(new Intent(CredentialStorage.ACTION_UNLOCK)); + return false; + } else { + KeyStore.getInstance().lock(); + } } return true; } |