Date: Tue, 16 Jun 2009 13:31:22 -0700
Subject: [PATCH 086/126] Make the Quick Launch settings show localized
application names.
It looks like when you look up the name of an application bookmark,
you get the name in whatever locale the device was in when it first
booted. Check the PackageManager to get a name in the current locale,
if possible, to display instead.
---
.../quicklaunch/QuickLaunchSettings.java | 26 ++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java
index 4d44524ac03..40316b567df 100644
--- a/src/com/android/settings/quicklaunch/QuickLaunchSettings.java
+++ b/src/com/android/settings/quicklaunch/QuickLaunchSettings.java
@@ -20,6 +20,8 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Bundle;
@@ -39,6 +41,8 @@ import android.widget.AdapterView;
import com.android.settings.R;
+import java.net.URISyntaxException;
+
/**
* Settings activity for quick launch.
*
@@ -300,7 +304,27 @@ public class QuickLaunchSettings extends PreferenceActivity implements
if (shortcut == 0) continue;
ShortcutPreference pref = getOrCreatePreference(shortcut);
- pref.setTitle(Bookmarks.getTitle(this, c));
+ CharSequence title = Bookmarks.getTitle(this, c);
+
+ /*
+ * The title retrieved from Bookmarks.getTitle() will be in
+ * the original boot locale, not the current locale.
+ * Try to look up a localized title from the PackageManager.
+ */
+ int intentColumn = c.getColumnIndex(Bookmarks.INTENT);
+ String intentUri = c.getString(intentColumn);
+ PackageManager packageManager = getPackageManager();
+ try {
+ Intent intent = Intent.getIntent(intentUri);
+ ResolveInfo info = packageManager.resolveActivity(intent, 0);
+ if (info != null) {
+ title = info.loadLabel(packageManager);
+ }
+ } catch (URISyntaxException e) {
+ // Just use the non-localized title, then.
+ }
+
+ pref.setTitle(title);
pref.setSummary(getString(R.string.quick_launch_shortcut,
String.valueOf(shortcut)));
pref.setHasBookmark(true);
From 14fa2b998630b7032b4e42b0bceb71f0df21fbdf Mon Sep 17 00:00:00 2001
From: Roy West
Date: Tue, 16 Jun 2009 14:07:55 -0700
Subject: [PATCH 087/126] Another edit, now in two places, now that I
understand the workflow of resetting the flow a bit better.
---
res/values/strings.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7b5abde9bff..26d7588c734 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1087,11 +1087,11 @@
Erases all data on phone
- This action will erase information about your Google account, all your settings, and any applications you've downloaded.
+ Factory data reset erases all of your personal information from the phone, including details about your Google account and any other accounts, system and application data and preferences, and any applications that you have downloaded. It does not change the version of the system software and bundled applications. It does not erase any photos, music, or other information stored on an SD card.
Reset phone
- Reset phone, erasing all your data and applications? Action cannot be reversed!
+ Erase all of your personal information and any downloaded applications? It is impossible to reverse this action!
Erase everything
From f06d8698a4a2de1973a25df0c6563bdfcba4eb03 Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Thu, 11 Jun 2009 22:32:33 -0700
Subject: [PATCH 088/126] Add setting for allowing Google to use location for
better search results.
---
res/values/strings.xml | 16 +-
res/xml/security_settings.xml | 11 +-
.../android/settings/SecuritySettings.java | 148 ++++++++++++++++--
3 files changed, 158 insertions(+), 17 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 26d7588c734..3d1b5d56b69 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1130,7 +1130,7 @@
Set options for roaming, networks, APNs
- My Location sources
+ My Location
Use wireless networks
@@ -1143,9 +1143,19 @@
When locating, accurate to street level (deselect to conserve battery)
Locate to street-level (requires more battery plus view of sky)
-
+
+ Share with Google
+
+ Allow Google to use location for improved search results and other services
+
+ Allow Google to use location for improved search results and other services
+
+ Agree
+
+ Disagree
-
+
+
About phone
diff --git a/res/xml/security_settings.xml b/res/xml/security_settings.xml
index 788aae3d65f..8dd9d897b38 100644
--- a/res/xml/security_settings.xml
+++ b/res/xml/security_settings.xml
@@ -17,11 +17,12 @@
@@ -30,7 +31,13 @@
android:title="@string/location_gps"
android:summaryOn="@string/location_street_level"
android:summaryOff="@string/location_gps_disabled"/>
-
+
+
+
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index ccf360ae5cf..41b4148ae25 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -18,10 +18,14 @@ package com.android.settings;
import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.ContentQueryMap;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.location.LocationManager;
import android.net.vpn.VpnManager;
@@ -30,20 +34,22 @@ import android.preference.CheckBoxPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
+import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Settings;
-import android.util.Config;
-import android.util.Log;
+import android.text.method.LinkMovementMethod;
+import android.widget.TextView;
+
+import com.android.internal.widget.LockPatternUtils;
import java.util.Observable;
import java.util.Observer;
-import com.android.internal.widget.LockPatternUtils;
-
/**
* Gesture lock pattern settings.
*/
-public class SecuritySettings extends PreferenceActivity {
+public class SecuritySettings extends PreferenceActivity implements
+ DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
// Lock Settings
@@ -61,10 +67,18 @@ public class SecuritySettings extends PreferenceActivity {
private CheckBoxPreference mShowPassword;
// 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";
+ // Vendor specific
+ private static final String GSETTINGS_PROVIDER = "com.google.android.providers.settings";
+ private static final String USE_LOCATION = "use_location";
+ private static final String KEY_DONE_USE_LOCATION = "doneLocation";
+ private CheckBoxPreference mUseLocation;
+ private boolean mOkClicked;
+ private Dialog mUseLocationDialog;
+
private CheckBoxPreference mNetwork;
private CheckBoxPreference mGps;
@@ -89,6 +103,17 @@ public class SecuritySettings extends PreferenceActivity {
mNetwork = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_NETWORK);
mGps = (CheckBoxPreference) getPreferenceScreen().findPreference(LOCATION_GPS);
+ mUseLocation = (CheckBoxPreference) getPreferenceScreen().findPreference(USE_LOCATION);
+
+ // Vendor specific
+ try {
+ if (mUseLocation != null
+ && getPackageManager().getPackageInfo(GSETTINGS_PROVIDER, 0) == null) {
+ ((PreferenceGroup)findPreference(LOCATION_CATEGORY))
+ .removePreference(mUseLocation);
+ }
+ } catch (NameNotFoundException nnfe) {
+ }
updateToggles();
// listen for Location Manager settings changes
@@ -98,6 +123,11 @@ public class SecuritySettings extends PreferenceActivity {
null);
mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null);
mContentQueryMap.addObserver(new SettingsObserver());
+ boolean doneUseLocation = savedInstanceState != null
+ && savedInstanceState.getBoolean(KEY_DONE_USE_LOCATION, true);
+ if (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false) && !doneUseLocation) {
+ showUseLocationDialog(true);
+ }
}
private PreferenceScreen createPreferenceHierarchy() {
@@ -198,6 +228,23 @@ public class SecuritySettings extends PreferenceActivity {
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
}
+ @Override
+ public void onPause() {
+ if (mUseLocationDialog != null && mUseLocationDialog.isShowing()) {
+ mUseLocationDialog.dismiss();
+ }
+ mUseLocationDialog = null;
+ super.onPause();
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle icicle) {
+ if (mUseLocationDialog != null && mUseLocationDialog.isShowing()) {
+ icicle.putBoolean(KEY_DONE_USE_LOCATION, false);
+ }
+ super.onSaveInstanceState(icicle);
+ }
+
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference) {
@@ -218,25 +265,84 @@ public class SecuritySettings extends PreferenceActivity {
} else if (preference == mGps) {
Settings.Secure.setLocationProviderEnabled(getContentResolver(),
LocationManager.GPS_PROVIDER, mGps.isChecked());
+ } else if (preference == mUseLocation) {
+ //normally called on the toggle click
+ if (mUseLocation.isChecked()) {
+ showUseLocationDialog(false);
+ } else {
+ updateUseLocation();
+ }
}
return false;
}
+ private void showPrivacyPolicy() {
+ Intent intent = new Intent("android.settings.TERMS");
+ startActivity(intent);
+ }
+
+ private void showUseLocationDialog(boolean force) {
+ // Show a warning to the user that location data will be shared
+ mOkClicked = false;
+ if (force) {
+ mUseLocation.setChecked(true);
+ }
+ /*
+ Resources res = getResources();
+ CharSequence msg = new SpannableString(
+ res.getText(R.string.use_location_warning_message));
+ SpannableString spannable = (SpannableString) msg;
+ Annotation[] spans = spannable.getSpans(0, spannable.length(), Annotation.class);
+ if (spans != null && spans.length > 0) {
+ SpannableStringBuilder builder = new SpannableStringBuilder(spannable);
+ int start = spannable.getSpanStart(spans[0]);
+ int end = spannable.getSpanEnd(spans[0]);
+ ClickableSpan link = new ClickableSpan() {
+ @Override
+ public void onClick(View view) {
+ showPrivacyPolicy();
+ }
+ };
+ builder.setSpan(link, start, end, spannable.getSpanFlags(link));
+ msg = builder;
+ }
+ */
+ CharSequence msg = getResources().getText(R.string.use_location_warning_message);
+ mUseLocationDialog = new AlertDialog.Builder(this).setMessage(msg)
+ .setTitle(R.string.use_location_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setPositiveButton(R.string.agree, this)
+ .setNegativeButton(R.string.disagree, this)
+ .show();
+ ((TextView)mUseLocationDialog.findViewById(android.R.id.message))
+ .setMovementMethod(LinkMovementMethod.getInstance());
+ mUseLocationDialog.setOnDismissListener(this);
+ }
+
/*
* Creates toggles for each available location provider
*/
private void updateToggles() {
+ ContentResolver res = getContentResolver();
mNetwork.setChecked(Settings.Secure.isLocationProviderEnabled(
- getContentResolver(), LocationManager.NETWORK_PROVIDER));
+ res, LocationManager.NETWORK_PROVIDER));
mGps.setChecked(Settings.Secure.isLocationProviderEnabled(
- getContentResolver(), LocationManager.GPS_PROVIDER));
+ res, LocationManager.GPS_PROVIDER));
+ mUseLocation.setChecked(Settings.Gservices.getInt(res,
+ Settings.Gservices.USE_LOCATION_FOR_SERVICES, 2) == 1);
}
private boolean isToggled(Preference pref) {
return ((CheckBoxPreference) pref).isChecked();
}
+ private void updateUseLocation() {
+ boolean use = mUseLocation.isChecked();
+ Settings.Gservices.putString(getContentResolver(),
+ Settings.Gservices.USE_LOCATION_FOR_SERVICES, use ? "1" : "0");
+ }
+
/**
* For the user to disable keyguard, we first make them verify their
@@ -272,15 +378,33 @@ public class SecuritySettings extends PreferenceActivity {
* @see #confirmPatternThenDisableAndClear
*/
@Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
final boolean resultOk = resultCode == Activity.RESULT_OK;
- if ((requestCode == CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE) && resultOk) {
+ if ((requestCode == CONFIRM_PATTERN_THEN_DISABLE_AND_CLEAR_REQUEST_CODE)
+ && resultOk) {
mLockPatternUtils.setLockPatternEnabled(false);
mLockPatternUtils.saveLockPattern(null);
}
}
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ //updateProviders();
+ mOkClicked = true;
+ } else {
+ // Reset the toggle
+ mUseLocation.setChecked(false);
+ }
+ updateUseLocation();
+ }
+
+ public void onDismiss(DialogInterface dialog) {
+ // Assuming that onClick gets called first
+ if (!mOkClicked) {
+ mUseLocation.setChecked(false);
+ }
+ }
}
From b2f1c334de30b2185bec53af81984d015436f610 Mon Sep 17 00:00:00 2001
From: Chung-yih Wang
Date: Wed, 17 Jun 2009 15:46:42 +0800
Subject: [PATCH 089/126] Simply the EAP certificate selection in Wifi Setting.
-- use the new keystore APU to save one more selection in WiFi EAP setting.
---
res/layout/wifi_ap_configure.xml | 15 +--
res/values/strings.xml | 2 -
.../settings/wifi/AccessPointDialog.java | 126 ++++++++----------
3 files changed, 60 insertions(+), 83 deletions(-)
diff --git a/res/layout/wifi_ap_configure.xml b/res/layout/wifi_ap_configure.xml
index ecd633744b4..e3ddf35bc6b 100644
--- a/res/layout/wifi_ap_configure.xml
+++ b/res/layout/wifi_ap_configure.xml
@@ -109,15 +109,6 @@
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:singleLine="true" />
-
-
-
-
+
CA certificate
- Private key
-
Private key password
Wireless password
diff --git a/src/com/android/settings/wifi/AccessPointDialog.java b/src/com/android/settings/wifi/AccessPointDialog.java
index 572ca85a552..43081a53c28 100644
--- a/src/com/android/settings/wifi/AccessPointDialog.java
+++ b/src/com/android/settings/wifi/AccessPointDialog.java
@@ -111,16 +111,13 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
private EditText mIdentityEdit;
private TextView mAnonymousIdentityText;
private EditText mAnonymousIdentityEdit;
- private TextView mClientCertText;
- private Spinner mClientCertSpinner;
private TextView mCaCertText;
private Spinner mCaCertSpinner;
- private TextView mPrivateKeyText;
- private Spinner mPrivateKeySpinner;
+ private TextView mClientCertText;
+ private Spinner mClientCertSpinner;
private TextView mPrivateKeyPasswdText;
private EditText mPrivateKeyPasswdEdit;
private EditText[] mEnterpriseTextFields;
- private Spinner[] mEnterpriseSpinnerFields;
// Info-specific views
@@ -330,23 +327,20 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
mEapSpinner.setSelection(getSelectionIndex(
R.array.wifi_eap_entries, mState.getEap()));
mClientCertSpinner.setSelection(getSelectionIndex(
- getAllCertificateKeys(), mState.getEnterpriseField(
+ getAllUserCertificateKeys(), mState.getEnterpriseField(
AccessPointState.CLIENT_CERT)));
mCaCertSpinner.setSelection(getSelectionIndex(
- getAllCertificateKeys(), mState.getEnterpriseField(
+ getAllCaCertificateKeys(), mState.getEnterpriseField(
AccessPointState.CA_CERT)));
- mPrivateKeySpinner.setSelection(getSelectionIndex(
- getAllUserkeyKeys(), mState.getEnterpriseField(
- AccessPointState.PRIVATE_KEY)));
}
}
- private String[] getAllCertificateKeys() {
- return appendEmptyInSelection(mKeystore.getAllCertificateKeys());
+ private String[] getAllCaCertificateKeys() {
+ return appendEmptyInSelection(mKeystore.getAllCaCertificateKeys());
}
- private String[] getAllUserkeyKeys() {
- return appendEmptyInSelection(mKeystore.getAllUserkeyKeys());
+ private String[] getAllUserCertificateKeys() {
+ return appendEmptyInSelection(mKeystore.getAllUserCertificateKeys());
}
private String[] appendEmptyInSelection(String[] keys) {
@@ -367,9 +361,6 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
mClientCertText =
(TextView) view.findViewById(R.id.client_certificate_text);
mCaCertText = (TextView) view.findViewById(R.id.ca_certificate_text);
- mPrivateKeyText = (TextView) view.findViewById(R.id.private_key_text);
- mPrivateKeyPasswdText =
- (TextView) view.findViewById(R.id.private_key_passwd_text);
mPrivateKeyPasswdEdit =
(EditText) view.findViewById(R.id.private_key_passwd_edit);
mEapText = (TextView) view.findViewById(R.id.eap_text);
@@ -389,28 +380,18 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
mClientCertSpinner.setOnItemSelectedListener(this);
mClientCertSpinner.setPromptId(
R.string.please_select_client_certificate);
- setSpinnerAdapter(mClientCertSpinner, getAllCertificateKeys());
+ setSpinnerAdapter(mClientCertSpinner, getAllUserCertificateKeys());
mCaCertSpinner =
(Spinner) view.findViewById(R.id.ca_certificate_spinner);
mCaCertSpinner.setOnItemSelectedListener(this);
mCaCertSpinner.setPromptId(R.string.please_select_ca_certificate);
- setSpinnerAdapter(mCaCertSpinner, getAllCertificateKeys());
-
- mPrivateKeySpinner =
- (Spinner) view.findViewById(R.id.private_key_spinner);
- mPrivateKeySpinner.setOnItemSelectedListener(this);
- mPrivateKeySpinner.setPromptId(R.string.please_select_private_key);
- setSpinnerAdapter(mPrivateKeySpinner, getAllUserkeyKeys());
+ setSpinnerAdapter(mCaCertSpinner, getAllCaCertificateKeys());
mEnterpriseTextFields = new EditText[] {
mIdentityEdit, mAnonymousIdentityEdit, mPrivateKeyPasswdEdit
};
- mEnterpriseSpinnerFields = new Spinner[] {
- mClientCertSpinner, mCaCertSpinner, mPrivateKeySpinner
- };
-
}
private void setSpinnerAdapter(Spinner spinner, String[] items) {
@@ -655,48 +636,55 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
}
private void updateEnterpriseFields(int securityType) {
- int i;
- for (i = AccessPointState.IDENTITY ;
- i < AccessPointState.MAX_ENTRPRISE_FIELD ; i++) {
- String value;
- if (i <= AccessPointState.PRIVATE_KEY_PASSWD) {
- value = mEnterpriseTextFields[i].getText().toString();
- } else {
- Spinner spinner = mEnterpriseSpinnerFields[i -
- AccessPointState.CLIENT_CERT];
- int index = spinner.getSelectedItemPosition();
- if (index == (spinner.getCount() - 1)) {
- value = "";
- } else {
- if (i != AccessPointState.PRIVATE_KEY) {
- value = mKeystore.getCertificate(
- getAllCertificateKeys()[index]);
- } else {
- value = mKeystore.getUserkey(
- getAllUserkeyKeys()[index]);
- }
- }
- }
- if (!TextUtils.isEmpty(value) ||
- (i == AccessPointState.PRIVATE_KEY_PASSWD)) {
- mState.setEnterpriseField(i, value);
- }
+ int i;
+ String value;
+ for (i = AccessPointState.IDENTITY ;
+ i <= AccessPointState.PRIVATE_KEY_PASSWD ; i++) {
+ value = mEnterpriseTextFields[i].getText().toString();
+ if (!TextUtils.isEmpty(value) ||
+ (i == AccessPointState.PRIVATE_KEY_PASSWD)) {
+ mState.setEnterpriseField(i, value);
}
-
- switch (securityType) {
- case SECURITY_WPA_EAP: {
- mState.setSecurity(AccessPointState.WPA_EAP);
- mState.setEap(mEapSpinner.getSelectedItemPosition());
- break;
- }
- case SECURITY_IEEE8021X: {
- mState.setSecurity(AccessPointState.IEEE8021X);
- mState.setEap(mEapSpinner.getSelectedItemPosition());
- break;
- }
- default:
- mState.setSecurity(AccessPointState.OPEN);
+ }
+ Spinner spinner = mClientCertSpinner;
+ int index = spinner.getSelectedItemPosition();
+ if (index != (spinner.getCount() - 1)) {
+ String key = getAllUserCertificateKeys()[index];
+ value = mKeystore.getUserCertificate(key);
+ if (!TextUtils.isEmpty(value)) {
+ mState.setEnterpriseField(AccessPointState.CLIENT_CERT,
+ value);
}
+ value = mKeystore.getUserPrivateKey(key);
+ if (!TextUtils.isEmpty(value)) {
+ mState.setEnterpriseField(AccessPointState.PRIVATE_KEY,
+ value);
+ }
+ }
+ spinner = mCaCertSpinner;
+ index = spinner.getSelectedItemPosition();
+ if (index != (spinner.getCount() - 1)) {
+ String key = getAllCaCertificateKeys()[index];
+ value = mKeystore.getCaCertificate(key);
+ if (!TextUtils.isEmpty(value)) {
+ mState.setEnterpriseField(AccessPointState.CA_CERT,
+ value);
+ }
+ }
+ switch (securityType) {
+ case SECURITY_WPA_EAP: {
+ mState.setSecurity(AccessPointState.WPA_EAP);
+ mState.setEap(mEapSpinner.getSelectedItemPosition());
+ break;
+ }
+ case SECURITY_IEEE8021X: {
+ mState.setSecurity(AccessPointState.IEEE8021X);
+ mState.setEap(mEapSpinner.getSelectedItemPosition());
+ break;
+ }
+ default:
+ mState.setSecurity(AccessPointState.OPEN);
+ }
}
/**
From 19e134e494a561324394fcc030ee8e30bb41c614 Mon Sep 17 00:00:00 2001
From: Chung-yih Wang
Date: Wed, 17 Jun 2009 18:27:18 +0800
Subject: [PATCH 090/126] Use new Keystore APIs in vpn profile editor.
---
.../android/settings/vpn/L2tpIpsecEditor.java | 23 ++-----------------
1 file changed, 2 insertions(+), 21 deletions(-)
diff --git a/src/com/android/settings/vpn/L2tpIpsecEditor.java b/src/com/android/settings/vpn/L2tpIpsecEditor.java
index 2dee92e2cfb..bb637721d4d 100644
--- a/src/com/android/settings/vpn/L2tpIpsecEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecEditor.java
@@ -34,7 +34,6 @@ class L2tpIpsecEditor extends VpnProfileEditor {
private ListPreference mUserCertificate;
private ListPreference mCaCertificate;
- private ListPreference mUserkey;
private L2tpIpsecProfile mProfile;
@@ -46,7 +45,6 @@ class L2tpIpsecEditor extends VpnProfileEditor {
@Override
protected void loadExtraPreferencesTo(PreferenceGroup subpanel) {
Context c = subpanel.getContext();
- subpanel.addPreference(createUserkeyPreference(c));
subpanel.addPreference(createUserCertificatePreference(c));
subpanel.addPreference(createCaCertificatePreference(c));
}
@@ -56,8 +54,6 @@ class L2tpIpsecEditor extends VpnProfileEditor {
String result = super.validate(c);
if (result != null) {
return result;
- } else if (Util.isNullOrEmpty(mUserkey.getValue())) {
- return c.getString(R.string.vpn_error_userkey_not_selected);
} else if (Util.isNullOrEmpty(mUserCertificate.getValue())) {
return c.getString(R.string.vpn_error_user_certificate_not_selected);
} else if (Util.isNullOrEmpty(mCaCertificate.getValue())) {
@@ -71,7 +67,7 @@ class L2tpIpsecEditor extends VpnProfileEditor {
mUserCertificate = createListPreference(c,
R.string.vpn_user_certificate_title,
mProfile.getUserCertificate(),
- Keystore.getInstance().getAllCertificateKeys(),
+ Keystore.getInstance().getAllUserCertificateKeys(),
new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(
Preference pref, Object newValue) {
@@ -86,7 +82,7 @@ class L2tpIpsecEditor extends VpnProfileEditor {
mCaCertificate = createListPreference(c,
R.string.vpn_ca_certificate_title,
mProfile.getCaCertificate(),
- Keystore.getInstance().getAllCertificateKeys(),
+ Keystore.getInstance().getAllCaCertificateKeys(),
new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(
Preference pref, Object newValue) {
@@ -97,21 +93,6 @@ class L2tpIpsecEditor extends VpnProfileEditor {
return mCaCertificate;
}
- private Preference createUserkeyPreference(Context c) {
- mUserkey = createListPreference(c,
- R.string.vpn_userkey_title,
- mProfile.getUserkey(),
- Keystore.getInstance().getAllUserkeyKeys(),
- new Preference.OnPreferenceChangeListener() {
- public boolean onPreferenceChange(
- Preference pref, Object newValue) {
- mProfile.setUserkey((String) newValue);
- return onPreferenceChangeCommon(pref, newValue);
- }
- });
- return mUserkey;
- }
-
private ListPreference createListPreference(Context c, int titleResId,
String text, String[] keys,
Preference.OnPreferenceChangeListener listener) {
From 2fb22c03bd587b373519f605feece1f846867cf6 Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Wed, 17 Jun 2009 11:57:42 -0700
Subject: [PATCH 091/126] Fixed auto-uncap of Wifi status messages.
Fixes #1852765. Change strings to lowercase and capitalize on demand.
---
res/values/strings.xml | 30 +++++++++----------
.../settings/wifi/AccessPointState.java | 19 ++++++------
2 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 492ffe58f62..2fedceb8ea7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -625,18 +625,18 @@
Unknown
-
- Open network
-
- Secured with WEP
-
- Secured with WPA
-
- Secured with WPA2
-
- Secured with WPA-EAP
-
- Secured with IEEE 802.1x
+
+ open network
+
+ secured with WEP
+
+ secured with WPA
+
+ secured with WPA2
+
+ secured with WPA-EAP
+
+ secured with IEEE 802.1x
IP address
@@ -683,10 +683,10 @@
Show password.
Scan
-
+
Not in range
-
- Remembered
+
+ remembered
Connection unsuccessful, select to try again
diff --git a/src/com/android/settings/wifi/AccessPointState.java b/src/com/android/settings/wifi/AccessPointState.java
index d0507670160..7ea2dc91bdf 100644
--- a/src/com/android/settings/wifi/AccessPointState.java
+++ b/src/com/android/settings/wifi/AccessPointState.java
@@ -815,22 +815,23 @@ public final class AccessPointState implements Comparable, Par
return null;
}
}
-
- private void buildSummary(StringBuilder sb, String string, boolean autoLowerCaseFirstLetter) {
+
+ private void buildSummary(StringBuilder sb, String string, boolean autoUpperCaseFirstLetter) {
if (sb.length() == 0) {
- sb.append(string);
- } else {
- sb.append(", ");
- if (autoLowerCaseFirstLetter) {
- // Convert first letter to lowercase
- sb.append(Character.toLowerCase(string.charAt(0))).append(string, 1,
+ if (autoUpperCaseFirstLetter && string.length() > 1
+ && Character.isLowerCase(string.charAt(0))
+ && !Character.isUpperCase(string.charAt(1))) {
+ sb.append(Character.toUpperCase(string.charAt(0))).append(string, 1,
string.length());
} else {
sb.append(string);
}
+ } else {
+ sb.append(", ");
+ sb.append(string);
}
}
-
+
public int compareTo(AccessPointState other) {
// This ranks the states for displaying in the AP list, not for
// connecting to (wpa_supplicant does that using the WifiConfiguration's
From dd14ee3d1698450f26ec31fdd2d1dd9a6ea81fc4 Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Wed, 17 Jun 2009 16:57:30 -0700
Subject: [PATCH 092/126] Remove extra subtitle for legal preferences.
Fixes #1894381
---
res/xml/device_info_settings.xml | 3 ---
1 file changed, 3 deletions(-)
diff --git a/res/xml/device_info_settings.xml b/res/xml/device_info_settings.xml
index bb7c5313d23..380450046ee 100644
--- a/res/xml/device_info_settings.xml
+++ b/res/xml/device_info_settings.xml
@@ -37,9 +37,6 @@
-
-
-
Sets the language-specific voice for the spoken text
+
+ Listen to an example
+
+ Play a short demonstration of speech synthesis
+
+ This is an example of speech synthesis.
+
+ Your settings have changed. This is an example of how they sound.
Power Control
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 991c1f106dd..5a7aaa2205e 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -17,6 +17,12 @@
+
+
resolveInfos = pm.queryIntentActivities(intent, 0);
+ // query only the package that matches that of the default engine
+ for (int i = 0; i < resolveInfos.size(); i++) {
+ ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
+ if (mDefaultEng.equals(currentActivityInfo.packageName)) {
+ intent.setClassName(mDefaultEng, currentActivityInfo.name);
+ this.startActivityForResult(intent, VOICE_DATA_INTEGRITY_CHECK);
+ }
+ }
+ }
+
+
+ /**
+ * Called when the TTS engine is initialized.
+ */
+ public void onInit(int status) {
+ if (status == TextToSpeech.TTS_SUCCESS) {
+ Log.v(TAG, "TTS engine for settings screen initialized.");
+ mEnableDemo = true;
+ } else {
+ Log.v(TAG, "TTS engine for settings screen failed to initialize successfully.");
+ mEnableDemo = false;
+ }
+ mPlayExample.setEnabled(mEnableDemo);
+ }
+
+
+ /**
+ * Called when voice data integrity check returns
+ */
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == VOICE_DATA_INTEGRITY_CHECK) {
+ if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
+ Log.v(TAG, "Voice data check passed");
+ if (mTts == null) {
+ mTts = new TextToSpeech(this, this);
+ }
+ } else {
+ Log.v(TAG, "Voice data check failed");
+
+ }
+ }
+ }
+
+
public boolean onPreferenceChange(Preference preference, Object objValue) {
if (KEY_TTS_USE_DEFAULT.equals(preference.getKey())) {
// "Use Defaults"
@@ -131,7 +228,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist default TTS pitch setting", e);
}
- }else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
+ } else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
// Default language
String value = (String) objValue;
Settings.Secure.putString(getContentResolver(),
@@ -142,4 +239,16 @@ public class TextToSpeechSettings extends PreferenceActivity implements
return true;
}
+
+ public boolean onPreferenceClick(Preference preference) {
+ if (preference == mPlayExample) {
+ if (mTts != null) {
+ mTts.speak(getResources().getString(R.string.tts_demo),
+ TextToSpeech.TTS_QUEUE_FLUSH, null);
+ }
+ return true;
+ }
+ return false;
+ }
+
}
From 41b6daa69213f58d6e0de1ff6c6c720731c971d2 Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Fri, 19 Jun 2009 12:42:10 -0700
Subject: [PATCH 094/126] Use new location of USE_LOCATION_FOR_SERVICES setting
(Secure).
Due to the need to access the bit from SetupWizard, had to move
the setting to Settings.Secure from Settings.Gservices.
---
.../android/settings/SecuritySettings.java | 29 ++++---------------
1 file changed, 5 insertions(+), 24 deletions(-)
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 41b4148ae25..c17e2a059df 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -288,26 +288,7 @@ public class SecuritySettings extends PreferenceActivity implements
if (force) {
mUseLocation.setChecked(true);
}
- /*
- Resources res = getResources();
- CharSequence msg = new SpannableString(
- res.getText(R.string.use_location_warning_message));
- SpannableString spannable = (SpannableString) msg;
- Annotation[] spans = spannable.getSpans(0, spannable.length(), Annotation.class);
- if (spans != null && spans.length > 0) {
- SpannableStringBuilder builder = new SpannableStringBuilder(spannable);
- int start = spannable.getSpanStart(spans[0]);
- int end = spannable.getSpanEnd(spans[0]);
- ClickableSpan link = new ClickableSpan() {
- @Override
- public void onClick(View view) {
- showPrivacyPolicy();
- }
- };
- builder.setSpan(link, start, end, spannable.getSpanFlags(link));
- msg = builder;
- }
- */
+
CharSequence msg = getResources().getText(R.string.use_location_warning_message);
mUseLocationDialog = new AlertDialog.Builder(this).setMessage(msg)
.setTitle(R.string.use_location_title)
@@ -329,8 +310,8 @@ public class SecuritySettings extends PreferenceActivity implements
res, LocationManager.NETWORK_PROVIDER));
mGps.setChecked(Settings.Secure.isLocationProviderEnabled(
res, LocationManager.GPS_PROVIDER));
- mUseLocation.setChecked(Settings.Gservices.getInt(res,
- Settings.Gservices.USE_LOCATION_FOR_SERVICES, 2) == 1);
+ mUseLocation.setChecked(Settings.Secure.getInt(res,
+ Settings.Secure.USE_LOCATION_FOR_SERVICES, 2) == 1);
}
private boolean isToggled(Preference pref) {
@@ -339,8 +320,8 @@ public class SecuritySettings extends PreferenceActivity implements
private void updateUseLocation() {
boolean use = mUseLocation.isChecked();
- Settings.Gservices.putString(getContentResolver(),
- Settings.Gservices.USE_LOCATION_FOR_SERVICES, use ? "1" : "0");
+ Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.USE_LOCATION_FOR_SERVICES, use ? 1 : 0);
}
From d22da2096bd738346be5e24eb964ae34d60fcd5e Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Mon, 15 Jun 2009 20:24:38 +0800
Subject: [PATCH 095/126] Add save-username checkbox in the connect dialog.
* changes
+ Add checkbox to layout file and handling code in related classes.
+ Add new methods to VpnProfileActor.
+ Move dialog handling to VpnSettings from AuthenticatorActor in order
to support screen orientation change.
+ Hide "Connect" in the context menu if the profile is connecting.
+ Enable connecting profile in case it was disabled in last call.
---
res/layout/vpn_connect_dialog_view.xml | 6 +
res/values/strings.xml | 6 +-
.../settings/vpn/AuthenticationActor.java | 187 ++++----------
.../android/settings/vpn/VpnProfileActor.java | 44 ++--
src/com/android/settings/vpn/VpnSettings.java | 230 +++++++++++++++---
5 files changed, 294 insertions(+), 179 deletions(-)
diff --git a/res/layout/vpn_connect_dialog_view.xml b/res/layout/vpn_connect_dialog_view.xml
index 540b404b21f..be66c2fcadc 100644
--- a/res/layout/vpn_connect_dialog_view.xml
+++ b/res/layout/vpn_connect_dialog_view.xml
@@ -45,4 +45,10 @@
android:singleLine="True"/>
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9e28761a6d5..05c65472341 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1755,6 +1755,7 @@ found in the list of installed applications.
Password:
User name
Password
+ Remember me
You missed a field!
Please fill up \"%s\".
@@ -1800,10 +1801,11 @@ found in the list of installed applications.
Select to connect
- Connect to
+ Connect to %s
+ nowhere
VPN Name
- Give a name to this VPN;
+ Give a name to this VPN
'%s' is added
Changes are made to '%s'
diff --git a/src/com/android/settings/vpn/AuthenticationActor.java b/src/com/android/settings/vpn/AuthenticationActor.java
index 364fd373f29..c56317ce4d8 100644
--- a/src/com/android/settings/vpn/AuthenticationActor.java
+++ b/src/com/android/settings/vpn/AuthenticationActor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -18,48 +18,32 @@ package com.android.settings.vpn;
import com.android.settings.R;
-import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.content.ServiceConnection;
import android.net.vpn.IVpnService;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
-import android.os.Bundle;
import android.os.IBinder;
-import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
-import android.widget.EditText;
+import android.widget.CheckBox;
import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.IOException;
/**
+ * A {@link VpnProfileActor} that provides an authentication view for users to
+ * input username and password before connecting to the VPN server.
*/
-public class AuthenticationActor implements VpnProfileActor,
- DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
+public class AuthenticationActor implements VpnProfileActor {
private static final String TAG = AuthenticationActor.class.getName();
private static final int ONE_SECOND = 1000; // ms
- private static final String STATE_IS_DIALOG_OPEN = "is_dialog_open";
- private static final String STATE_USERNAME = "username";
- private static final String STATE_PASSWORD = "password";
-
private Context mContext;
- private TextView mUsernameView;
- private TextView mPasswordView;
-
private VpnProfile mProfile;
- private View mView;
private VpnManager mVpnManager;
- private AlertDialog mConnectDialog;
- private AlertDialog mDisconnectDialog;
public AuthenticationActor(Context context, VpnProfile p) {
mContext = context;
@@ -73,77 +57,54 @@ public class AuthenticationActor implements VpnProfileActor,
}
//@Override
- public synchronized void connect() {
- connect("", "");
+ public boolean isConnectDialogNeeded() {
+ return true;
}
//@Override
- public void onClick(DialogInterface dialog, int which) {
- dismissConnectDialog();
- switch (which) {
- case DialogInterface.BUTTON1: // connect
- if (validateInputs()) {
- broadcastConnectivity(VpnState.CONNECTING);
- connectInternal();
- }
- break;
-
- case DialogInterface.BUTTON2: // cancel
- broadcastConnectivity(VpnState.CANCELLED);
- break;
- }
- }
-
- //@Override
- public void onCancel(DialogInterface dialog) {
- dismissConnectDialog();
- broadcastConnectivity(VpnState.CANCELLED);
- }
-
- private void connect(String username, String password) {
+ public String validateInputs(Dialog d) {
+ TextView usernameView = (TextView) d.findViewById(R.id.username_value);
+ TextView passwordView = (TextView) d.findViewById(R.id.password_value);
Context c = mContext;
- mConnectDialog = new AlertDialog.Builder(c)
- .setView(createConnectView(username, password))
- .setTitle(c.getString(R.string.vpn_connect_to) + " "
- + mProfile.getName())
- .setPositiveButton(c.getString(R.string.vpn_connect_button),
- this)
- .setNegativeButton(c.getString(R.string.vpn_cancel_button),
- this)
- .setOnCancelListener(this)
- .create();
- mConnectDialog.show();
- }
-
- //@Override
- public synchronized void onSaveState(Bundle outState) {
- outState.putBoolean(STATE_IS_DIALOG_OPEN, (mConnectDialog != null));
- if (mConnectDialog != null) {
- assert(mConnectDialog.isShowing());
- outState.putBoolean(STATE_IS_DIALOG_OPEN, (mConnectDialog != null));
- outState.putString(STATE_USERNAME,
- mUsernameView.getText().toString());
- outState.putString(STATE_PASSWORD,
- mPasswordView.getText().toString());
- dismissConnectDialog();
+ if (Util.isNullOrEmpty(usernameView.getText().toString())) {
+ return c.getString(R.string.vpn_username);
+ } else if (Util.isNullOrEmpty(passwordView.getText().toString())) {
+ return c.getString(R.string.vpn_password);
+ } else {
+ return null;
}
}
//@Override
- public synchronized void onRestoreState(final Bundle savedState) {
- boolean isDialogOpen = savedState.getBoolean(STATE_IS_DIALOG_OPEN);
- if (isDialogOpen) {
- connect(savedState.getString(STATE_USERNAME),
- savedState.getString(STATE_PASSWORD));
+ public void connect(Dialog d) {
+ TextView usernameView = (TextView) d.findViewById(R.id.username_value);
+ TextView passwordView = (TextView) d.findViewById(R.id.password_value);
+ CheckBox saveUsername = (CheckBox) d.findViewById(R.id.save_username);
+
+ // save username
+ if (saveUsername.isChecked()) {
+ mProfile.setSavedUsername(usernameView.getText().toString());
+ } else {
+ mProfile.setSavedUsername("");
}
+ connect(usernameView.getText().toString(),
+ passwordView.getText().toString());
+ passwordView.setText("");
}
- private synchronized void dismissConnectDialog() {
- mConnectDialog.dismiss();
- mConnectDialog = null;
+ //@Override
+ public View createConnectView() {
+ return View.inflate(mContext, R.layout.vpn_connect_dialog_view, null);
}
- private void connectInternal() {
+ //@Override
+ public void updateConnectView(Dialog d) {
+ String username = mProfile.getSavedUsername();
+ if (username == null) username = "";
+ updateConnectView(d, username, "", !Util.isNullOrEmpty(username));
+ }
+
+ private void connect(final String username, final String password) {
mVpnManager.startVpnService();
ServiceConnection c = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
@@ -151,10 +112,7 @@ public class AuthenticationActor implements VpnProfileActor,
boolean success = false;
try {
success = IVpnService.Stub.asInterface(service)
- .connect(mProfile,
- mUsernameView.getText().toString(),
- mPasswordView.getText().toString());
- mPasswordView.setText("");
+ .connect(mProfile, username, password);
} catch (Throwable e) {
Log.e(TAG, "connect()", e);
checkStatus();
@@ -230,61 +188,20 @@ public class AuthenticationActor implements VpnProfileActor,
return mVpnManager.bindVpnService(c);
}
+ private void updateConnectView(Dialog d, String username,
+ String password, boolean toSaveUsername) {
+ TextView usernameView = (TextView) d.findViewById(R.id.username_value);
+ TextView passwordView = (TextView) d.findViewById(R.id.password_value);
+ CheckBox saveUsername = (CheckBox) d.findViewById(R.id.save_username);
+ usernameView.setText(username);
+ passwordView.setText(password);
+ saveUsername.setChecked(toSaveUsername);
+ }
+
private void broadcastConnectivity(VpnState s) {
mVpnManager.broadcastConnectivity(mProfile.getName(), s);
}
- // returns true if inputs pass validation
- private boolean validateInputs() {
- Context c = mContext;
- String error = null;
- if (Util.isNullOrEmpty(mUsernameView.getText().toString())) {
- error = c.getString(R.string.vpn_username);
- } else if (Util.isNullOrEmpty(mPasswordView.getText().toString())) {
- error = c.getString(R.string.vpn_password);
- }
- if (error == null) {
- return true;
- } else {
- new AlertDialog.Builder(c)
- .setTitle(c.getString(R.string.vpn_you_miss_a_field))
- .setMessage(String.format(
- c.getString(R.string.vpn_please_fill_up), error))
- .setPositiveButton(c.getString(R.string.vpn_back_button),
- createBackButtonListener())
- .show();
- return false;
- }
- }
-
- private View createConnectView(String username, String password) {
- View v = View.inflate(mContext, R.layout.vpn_connect_dialog_view, null);
- mUsernameView = (TextView) v.findViewById(R.id.username_value);
- mPasswordView = (TextView) v.findViewById(R.id.password_value);
- mUsernameView.setText(username);
- mPasswordView.setText(password);
- copyFieldsFromOldView(v);
- mView = v;
- return v;
- }
-
- private void copyFieldsFromOldView(View newView) {
- if (mView == null) return;
- mUsernameView.setText(
- ((TextView) mView.findViewById(R.id.username_value)).getText());
- mPasswordView.setText(
- ((TextView) mView.findViewById(R.id.password_value)).getText());
- }
-
- private DialogInterface.OnClickListener createBackButtonListener() {
- return new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- connect();
- }
- };
- }
-
private void wait(Object o, int ms) {
synchronized (o) {
try {
diff --git a/src/com/android/settings/vpn/VpnProfileActor.java b/src/com/android/settings/vpn/VpnProfileActor.java
index fb0e2781001..1e71e864c6b 100644
--- a/src/com/android/settings/vpn/VpnProfileActor.java
+++ b/src/com/android/settings/vpn/VpnProfileActor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -16,8 +16,9 @@
package com.android.settings.vpn;
+import android.app.Dialog;
import android.net.vpn.VpnProfile;
-import android.os.Bundle;
+import android.view.View;
/**
* The interface to act on a {@link VpnProfile}.
@@ -26,9 +27,34 @@ public interface VpnProfileActor {
VpnProfile getProfile();
/**
- * Establishes a VPN connection.
+ * Returns true if a connect dialog is needed before establishing a
+ * connection.
*/
- void connect();
+ boolean isConnectDialogNeeded();
+
+ /**
+ * Creates the view in the connect dialog.
+ */
+ View createConnectView();
+
+ /**
+ * Updates the view in the connect dialog.
+ * @param dialog the recycled connect dialog.
+ */
+ void updateConnectView(Dialog dialog);
+
+ /**
+ * Validates the inputs in the dialog.
+ * @param dialog the connect dialog
+ * @return an error message if the inputs are not valid
+ */
+ String validateInputs(Dialog dialog);
+
+ /**
+ * Establishes a VPN connection.
+ * @param dialog the connect dialog
+ */
+ void connect(Dialog dialog);
/**
* Tears down the connection.
@@ -41,14 +67,4 @@ public interface VpnProfileActor {
* broadcast receiver and to receives the broadcast events.
*/
void checkStatus();
-
- /**
- * Called to save the states when the device is rotated.
- */
- void onSaveState(Bundle outState);
-
- /**
- * Called to restore the states on the rotated screen.
- */
- void onRestoreState(Bundle savedState);
}
diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java
index 97a14404a6a..06f0e25bbca 100644
--- a/src/com/android/settings/vpn/VpnSettings.java
+++ b/src/com/android/settings/vpn/VpnSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -19,6 +19,7 @@ package com.android.settings.vpn;
import com.android.settings.R;
import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -28,6 +29,7 @@ import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
import android.net.vpn.VpnType;
import android.os.Bundle;
+import android.os.Parcel;
import android.os.Parcelable;
import android.preference.Preference;
import android.preference.PreferenceActivity;
@@ -58,7 +60,8 @@ import java.util.Map;
/**
* The preference activity for configuring VPN settings.
*/
-public class VpnSettings extends PreferenceActivity {
+public class VpnSettings extends PreferenceActivity implements
+ DialogInterface.OnClickListener {
// Key to the field exchanged for profile editing.
static final String KEY_VPN_PROFILE = "vpn_profile";
@@ -83,6 +86,8 @@ public class VpnSettings extends PreferenceActivity {
private static final int CONTEXT_MENU_EDIT_ID = ContextMenu.FIRST + 2;
private static final int CONTEXT_MENU_DELETE_ID = ContextMenu.FIRST + 3;
+ private static final int CONNECT_BUTTON = DialogInterface.BUTTON1;
+
private PreferenceScreen mAddVpn;
private PreferenceCategory mVpnListContainer;
@@ -95,8 +100,8 @@ public class VpnSettings extends PreferenceActivity {
// profile engaged in a connection
private VpnProfile mActiveProfile;
- // actor engaged in an action
- private VpnProfileActor mActiveActor;
+ // actor engaged in connecting
+ private VpnProfileActor mConnectingActor;
private VpnManager mVpnManager = new VpnManager(this);
@@ -112,7 +117,6 @@ public class VpnSettings extends PreferenceActivity {
// restore VpnProfile list and construct VpnPreference map
mVpnListContainer = (PreferenceCategory) findPreference(PREF_VPN_LIST);
- retrieveVpnListFromStorage();
// set up the "add vpn" preference
mAddVpn = (PreferenceScreen) findPreference(PREF_ADD_VPN);
@@ -132,12 +136,21 @@ public class VpnSettings extends PreferenceActivity {
}
@Override
- protected synchronized void onSaveInstanceState(Bundle outState) {
- if (mActiveActor == null) return;
+ public void onResume() {
+ super.onResume();
+
+ if ((mVpnProfileList == null) || mVpnProfileList.isEmpty()) {
+ retrieveVpnListFromStorage();
+ checkVpnConnectionStatusInBackground();
+ }
+ }
+
+ @Override
+ protected synchronized void onSaveInstanceState(Bundle outState) {
+ if (mConnectingActor == null) return;
- mActiveActor.onSaveState(outState);
outState.putString(STATE_ACTIVE_ACTOR,
- mActiveActor.getProfile().getName());
+ mConnectingActor.getProfile().getName());
}
@Override
@@ -145,9 +158,10 @@ public class VpnSettings extends PreferenceActivity {
String profileName = savedState.getString(STATE_ACTIVE_ACTOR);
if (Util.isNullOrEmpty(profileName)) return;
- final VpnProfile p = mVpnPreferenceMap.get(profileName).mProfile;
- mActiveActor = getActor(p);
- mActiveActor.onRestoreState(savedState);
+ retrieveVpnListFromStorage();
+
+ VpnProfile p = mVpnPreferenceMap.get(profileName).mProfile;
+ mConnectingActor = getActor(p);
}
@Override
@@ -157,6 +171,33 @@ public class VpnSettings extends PreferenceActivity {
mVpnManager.unregisterConnectivityReceiver(mConnectivityReceiver);
}
+ @Override
+ protected Dialog onCreateDialog (int id) {
+ if (mConnectingActor == null) {
+ Log.e(TAG, "no connecting actor to create the dialog");
+ }
+ String name = (mConnectingActor == null)
+ ? getString(R.string.vpn_default_profile_name)
+ : mConnectingActor.getProfile().getName();
+ Dialog d = new AlertDialog.Builder(this)
+ .setView(mConnectingActor.createConnectView())
+ .setTitle(String.format(getString(R.string.vpn_connect_to),
+ name))
+ .setPositiveButton(getString(R.string.vpn_connect_button),
+ this)
+ .setNegativeButton(getString(R.string.vpn_cancel_button),
+ this)
+ .create();
+ return d;
+ }
+
+ @Override
+ protected void onPrepareDialog (int id, Dialog dialog) {
+ if (mConnectingActor != null) {
+ mConnectingActor.updateConnectView(dialog);
+ }
+ }
+
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
@@ -174,7 +215,7 @@ public class VpnSettings extends PreferenceActivity {
menu.add(0, CONTEXT_MENU_CONNECT_ID, 0, R.string.vpn_menu_connect)
.setEnabled(isIdle && (mActiveProfile == null));
menu.add(0, CONTEXT_MENU_DISCONNECT_ID, 0, R.string.vpn_menu_disconnect)
- .setEnabled(!isIdle);
+ .setEnabled(state == VpnState.CONNECTED);
menu.add(0, CONTEXT_MENU_EDIT_ID, 0, R.string.vpn_menu_edit)
.setEnabled(isNotConnect);
menu.add(0, CONTEXT_MENU_DELETE_ID, 0, R.string.vpn_menu_delete)
@@ -214,7 +255,7 @@ public class VpnSettings extends PreferenceActivity {
mIndexOfEditedProfile = -1;
if ((resultCode == RESULT_CANCELED) || (data == null)) {
- Log.v(TAG, "no result returned by editor");
+ Log.d(TAG, "no result returned by editor");
return;
}
@@ -264,6 +305,35 @@ public class VpnSettings extends PreferenceActivity {
}
}
+ // Called when the buttons on the connect dialog are clicked.
+ //@Override
+ public synchronized void onClick(DialogInterface dialog, int which) {
+ dismissDialog(0);
+ if (which == CONNECT_BUTTON) {
+ Dialog d = (Dialog) dialog;
+ String error = mConnectingActor.validateInputs(d);
+ if (error == null) {
+ changeState(mConnectingActor.getProfile(), VpnState.CONNECTING);
+ mConnectingActor.connect(d);
+ return;
+ } else {
+ // show error dialog
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.vpn_you_miss_a_field)
+ .setMessage(String.format(
+ getString(R.string.vpn_please_fill_up), error))
+ .setPositiveButton(R.string.vpn_back_button,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog,
+ int which) {
+ showDialog(0);
+ }
+ })
+ .show();
+ }
+ }
+ }
+
// Replaces the profile at index in mVpnProfileList with p.
// Returns true if p's name is a duplicate.
private boolean checkDuplicateName(VpnProfile p, int index) {
@@ -353,13 +423,17 @@ public class VpnSettings extends PreferenceActivity {
VpnPreference pref = mVpnPreferenceMap.get(p.getName());
switch (p.getState()) {
case IDLE:
- changeState(p, VpnState.CONNECTING);
- mActiveActor = getActor(p);
- mActiveActor.connect();
+ mConnectingActor = getActor(new VpnProfileWrapper(p));
+ if (mConnectingActor.isConnectDialogNeeded()) {
+ showDialog(0);
+ } else {
+ changeState(p, VpnState.CONNECTING);
+ mConnectingActor.connect(null);
+ }
break;
case CONNECTING:
- // TODO: bring up a dialog to confirm disconnect
+ // do nothing
break;
case CONNECTED:
@@ -376,14 +450,13 @@ public class VpnSettings extends PreferenceActivity {
VpnState oldState = p.getState();
if (oldState == state) return;
- Log.d(TAG, "changeState: " + p.getName() + ": " + state);
p.setState(state);
mVpnPreferenceMap.get(p.getName()).setSummary(
getProfileSummaryString(p));
switch (state) {
case CONNECTED:
- mActiveActor = null;
+ mConnectingActor = null;
// pass through
case CONNECTING:
mActiveProfile = p;
@@ -403,7 +476,7 @@ public class VpnSettings extends PreferenceActivity {
case IDLE:
assert(mActiveProfile != p);
mActiveProfile = null;
- mActiveActor = null;
+ mConnectingActor = null;
enableProfilePreferences();
if (oldState == VpnState.CONNECTING) mConnectingError = true;
@@ -432,10 +505,13 @@ public class VpnSettings extends PreferenceActivity {
for (VpnProfile p : mVpnProfileList) {
switch (p.getState()) {
- case DISCONNECTING:
- case IDLE:
- mVpnPreferenceMap.get(p.getName()).setEnabled(false);
- break;
+ case DISCONNECTING:
+ case IDLE:
+ mVpnPreferenceMap.get(p.getName()).setEnabled(false);
+ break;
+
+ default:
+ mVpnPreferenceMap.get(p.getName()).setEnabled(true);
}
}
}
@@ -466,6 +542,7 @@ public class VpnSettings extends PreferenceActivity {
private void retrieveVpnListFromStorage() {
mVpnPreferenceMap = new LinkedHashMap();
mVpnProfileList = new ArrayList();
+ mVpnListContainer.removeAll();
File root = new File(PROFILES_ROOT);
String[] dirs = root.list();
@@ -476,6 +553,7 @@ public class VpnSettings extends PreferenceActivity {
if (!f.exists()) continue;
try {
VpnProfile p = deserialize(f);
+ if (p == null) continue;
if (!checkIdConsistency(dir, p)) continue;
mVpnProfileList.add(p);
@@ -485,7 +563,6 @@ public class VpnSettings extends PreferenceActivity {
}
}
disableProfilePreferencesIfOneActive();
- checkVpnConnectionStatusInBackground();
}
private void checkVpnConnectionStatusInBackground() {
@@ -502,7 +579,7 @@ public class VpnSettings extends PreferenceActivity {
// are consistent.
private boolean checkIdConsistency(String dirName, VpnProfile p) {
if (!dirName.equals(p.getId())) {
- Log.v(TAG, "ID inconsistent: " + dirName + " vs " + p.getId());
+ Log.d(TAG, "ID inconsistent: " + dirName + " vs " + p.getId());
return false;
} else {
return true;
@@ -517,7 +594,8 @@ public class VpnSettings extends PreferenceActivity {
ois.close();
return p;
} catch (ClassNotFoundException e) {
- throw new RuntimeException(e);
+ Log.d(TAG, "deserialize a profile", e);
+ return null;
}
}
@@ -582,4 +660,100 @@ public class VpnSettings extends PreferenceActivity {
}
}
}
+
+ // to catch saved user name in the connect dialog
+ private class VpnProfileWrapper extends VpnProfile {
+ private VpnProfile mProfile;
+
+ VpnProfileWrapper(VpnProfile p) {
+ mProfile = p;
+ }
+
+ @Override
+ public void setSavedUsername(String name) {
+ if ((name != null) && !name.equals(mProfile.getSavedUsername())) {
+ mProfile.setSavedUsername(name);
+ try {
+ saveProfileToStorage(mProfile);
+ } catch (IOException e) {
+ Log.d(TAG, "save username", e);
+ // harmless
+ }
+ }
+ }
+
+ @Override
+ public String getSavedUsername() {
+ return mProfile.getSavedUsername();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ mProfile.writeToParcel(parcel, flags);
+ }
+
+ @Override
+ public void setName(String name) {
+ }
+
+ @Override
+ public String getName() {
+ return mProfile.getName();
+ }
+
+ @Override
+ public void setId(String id) {
+ }
+
+ @Override
+ public String getId() {
+ return mProfile.getId();
+ }
+
+ @Override
+ public void setServerName(String name) {
+ }
+
+ @Override
+ public String getServerName() {
+ return mProfile.getServerName();
+ }
+
+ @Override
+ public void setDomainSuffices(String entries) {
+ }
+
+ @Override
+ public String getDomainSuffices() {
+ return mProfile.getDomainSuffices();
+ }
+
+ @Override
+ public void setRouteList(String entries) {
+ }
+
+ @Override
+ public String getRouteList() {
+ return mProfile.getRouteList();
+ }
+
+ @Override
+ public void setState(VpnState state) {
+ }
+
+ @Override
+ public VpnState getState() {
+ return mProfile.getState();
+ }
+
+ @Override
+ public boolean isIdle() {
+ return mProfile.isIdle();
+ }
+
+ @Override
+ public VpnType getType() {
+ return mProfile.getType();
+ }
+ }
}
From db33eb01cd5f83dcb3d5d12287113a0700363588 Mon Sep 17 00:00:00 2001
From: Roy West
Date: Fri, 19 Jun 2009 15:24:28 -0700
Subject: [PATCH 096/126] Use sentence style for "System tutorial" Bug 1742121
---
res/values/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 05c65472341..69aaff1708b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1172,7 +1172,7 @@
Terms and conditions
- System Tutorial
+ System tutorial
Learn how to use your phone
From 1e6a45a2d029f9e711e2de9a43bde50607b082c0 Mon Sep 17 00:00:00 2001
From: Jean-Michel Trivi
Date: Mon, 22 Jun 2009 16:03:40 -0700
Subject: [PATCH 097/126] Updated TTS settings to support language, country and
variant settings. Disable/enable entries based on whether language files are
installed on the phone. Added entry to install the language files on the
phone.
---
res/values/arrays.xml | 12 +-
res/values/strings.xml | 10 +-
res/xml/tts_settings.xml | 6 +
.../settings/TextToSpeechSettings.java | 201 ++++++++++++++----
4 files changed, 182 insertions(+), 47 deletions(-)
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 06bf7879b1f..9bfeb1309d4 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -122,12 +122,12 @@
- - en-rUS
- - en-rGB
- - fr-rFR
- - de-rDE
- - it-rIT
- - es-rES
+ - eng-USA
+ - eng-GBR
+ - fra-FRA
+ - deu-DEU
+ - ita-ITA
+ - spa-ESP
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 69aaff1708b..e7bad742b37 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1737,10 +1737,16 @@ found in the list of installed applications.
Language
Sets the language-specific voice for the spoken text
-
+
Listen to an example
-
+
Play a short demonstration of speech synthesis
+
+ Install voice data
+
+ Install the voice data required for speech synthesis
+
+ Voices required for speech synthesis already properly installed
This is an example of speech synthesis.
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 5a7aaa2205e..4ec2a4d801c 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -22,6 +22,12 @@
android:persistent="false"
android:title="@string/tts_play_example_title"
android:summary="@string/tts_play_example_summary" />
+
+
Date: Tue, 23 Jun 2009 13:39:55 -0700
Subject: [PATCH 098/126] First part of fix to bug 1813461, changing "Factory
reset" to "Uninstall updates"
---
res/values/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e7bad742b37..768033affe2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1312,7 +1312,7 @@
Clear data
- Factory reset
+ Uninstall updates
You have selected to launch this application by default for some actions.
From 4b007cb7323b41d66ddce7ec26573bce9e79cda0 Mon Sep 17 00:00:00 2001
From: Roy West
Date: Tue, 23 Jun 2009 16:53:37 -0700
Subject: [PATCH 099/126] Fix bug 1937431.
Shorten cut-off location permission string.
---
res/values/strings.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 768033affe2..753b5c643a9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1144,7 +1144,7 @@
Share with Google
- Allow Google to use location for improved search results and other services
+ Allow Google to use location for improved search and other services
Allow Google to use location for improved search results and other services
From 972fc2989aba6757e5128aaf8d800fed04f8400f Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Mon, 22 Jun 2009 23:04:45 -0700
Subject: [PATCH 100/126] Description and suggestion strings for Battery Usage
detail screens.
---
res/values/strings.xml | 74 ++++++++++++++++++++++++++++++------------
1 file changed, 53 insertions(+), 21 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 753b5c643a9..24da20783f6 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1637,44 +1637,38 @@ found in the list of installed applications.
- Battery usage
+ Battery use
- Battery usage since unplugged
+ Battery use since unplugged
- Battery usage since reset
+ Battery use since reset
- Usage duration - %1$s
-
- Device awake time
-
- WiFi on time
-
- WiFi on time
+ Use duration - %1$s
%1$s" - "
%2$s"%%"
- Battery usage details
+ Battery use details
- Usage details
+ Use details
- Controls
+ Adjust power use
Included packages
- Screen on
+ Display
- WiFi
+ Wi-Fi
Bluetooth
- Cell
+ Cell standby
- Voice
+ Voice calls
- Standby
+ Phone idle
CPU total
@@ -1692,12 +1686,14 @@ found in the list of installed applications.
Audio
Video
-
+
On time
Force stop
- App details
+ Application info
+
+ Application settings
Display settings
@@ -1705,8 +1701,44 @@ found in the list of installed applications.
Bluetooth settings
+
+ Battery used when phone is idle
+
+
+ Battery used by cell radio
+
+ Switch to airplane mode to save power in areas with no cell coverage
+
+
+ Battery used by the display and backlight
+
+ Reduce the screen brightness and/or screen timeout
+
+
+ Battery used by Wi-Fi
+
+ Turn off WiFi when not using it or where it is not available
+
+
+ Battery used by bluetooth
+
+ Turn off bluetooth when you aren't using it
+
+ Try connecting to a different bluetooth device
+
+
+ Battery used by applications when running
+
+ Stop or uninstall the application
+
+ Turn off GPS when you're not using it
+
+ The application may offer settings to reduce battery use
+
- Usage since unplugged
+ %1$s since unplugged
+
+ While last unplugged for %1$s
Usage totals
From 74b53da2532e3c611f712d80a50445ae5c7863a0 Mon Sep 17 00:00:00 2001
From: Roy West
Date: Wed, 24 Jun 2009 09:25:12 -0700
Subject: [PATCH 101/126] Additional edits to strings when uninstalling system
app updates.
Fixes bug 1940257.
---
res/values/strings.xml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 24da20783f6..359c2be7278 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1359,9 +1359,9 @@ found in the list of installed applications.
Unable to clear application data.
- Factory reset system app
+ Uninstall updates
- Do you want to fallback to factory version of system application?
+ Do you want to uninstall all updates to this Android system application?
Clear data
From a54672f3a983766cf1dce754b3887807fcb723fa Mon Sep 17 00:00:00 2001
From: Dianne Hackborn
Date: Wed, 24 Jun 2009 12:45:09 -0700
Subject: [PATCH 102/126] Some cleanup of settings launching, adding shortcuts.
- Move the battery usage item from applications to phone info.
- Give the battery usage item a summary.
- Fiddle with the manifest to make it so we can launch parts of the settings
app without messing up launching of the main app. (That is, remove
affinities so they each are treated as different tasks.)
- Add the ability to make shortcuts to some key settings panels.
---
AndroidManifest.xml | 41 +++++++++++++++++---
res/values/strings.xml | 4 ++
res/xml/application_settings.xml | 8 ----
res/xml/device_info_settings.xml | 9 +++++
src/com/android/settings/CreateShortcut.java | 25 ++++++++++++
5 files changed, 73 insertions(+), 14 deletions(-)
create mode 100644 src/com/android/settings/CreateShortcut.java
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 03978cc756a..39d501970fa 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -36,11 +36,14 @@
-
+
@@ -51,6 +54,13 @@
+
+
+
+
+
+
+
@@ -76,6 +87,7 @@
+
@@ -102,11 +114,13 @@
+
@@ -155,12 +169,14 @@
+
@@ -172,18 +188,21 @@
-
+
+
@@ -192,6 +211,7 @@
+
@@ -225,6 +245,7 @@
@@ -233,6 +254,7 @@
+
@@ -244,13 +266,16 @@
-
+
+
@@ -369,7 +394,7 @@
-
@@ -527,10 +552,14 @@
+ android:label="@string/power_usage_summary_title"
+ android:clearTaskOnLaunch="true"
+ >
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 359c2be7278..2dd2f84fc2f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -424,6 +424,8 @@
Settings
+
+ Settings
Airplane mode
@@ -1638,6 +1640,8 @@ found in the list of installed applications.
Battery use
+
+ What has been using the battery
Battery use since unplugged
diff --git a/res/xml/application_settings.xml b/res/xml/application_settings.xml
index 4da20365050..8d0a7cb5153 100644
--- a/res/xml/application_settings.xml
+++ b/res/xml/application_settings.xml
@@ -35,14 +35,6 @@
android:targetClass="com.android.settings.quicklaunch.QuickLaunchSettings" />
-
-
-
-
diff --git a/res/xml/device_info_settings.xml b/res/xml/device_info_settings.xml
index 380450046ee..80370e2e7ff 100644
--- a/res/xml/device_info_settings.xml
+++ b/res/xml/device_info_settings.xml
@@ -33,6 +33,15 @@
android:targetClass="com.android.settings.deviceinfo.Status" />
+
+
+
+
Date: Fri, 19 Jun 2009 09:27:35 -0700
Subject: [PATCH 103/126] Track native processes.
Add gauge to detail screen and make it look like the item from summary screen.
Some string changes.
---
res/layout/power_usage_details.xml | 81 +++++++++++--------
res/layout/preference_powergauge.xml | 2 +-
res/values/strings.xml | 18 ++++-
res/xml/power_usage_summary.xml | 5 +-
.../settings/fuelgauge/PercentageBar.java | 67 +++++++++++++++
.../fuelgauge/PowerGaugePreference.java | 44 +---------
.../settings/fuelgauge/PowerUsageDetail.java | 78 +++++++++++++++---
.../settings/fuelgauge/PowerUsageSummary.java | 51 +++++++++---
8 files changed, 240 insertions(+), 106 deletions(-)
create mode 100644 src/com/android/settings/fuelgauge/PercentageBar.java
diff --git a/res/layout/power_usage_details.xml b/res/layout/power_usage_details.xml
index 8aa625f669e..ea7cfb34698 100644
--- a/res/layout/power_usage_details.xml
+++ b/res/layout/power_usage_details.xml
@@ -22,55 +22,70 @@
android:id="@+id/all_details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:paddingRight="6dip"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:orientation="vertical">
-
-
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:gravity="center_vertical"
+ android:paddingLeft="12dip"
+ android:paddingRight="?android:attr/scrollbarSize">
-
-
+ android:layout_marginRight="6dip"
+ android:layout_gravity="center" />
+
+
+
-
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
-
-
-
-
-
-
+ android:singleLine="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignBottom="@+id/name"
+ android:layout_gravity="bottom"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textStyle="bold"/>
+
+
+
+
Battery use since reset
- Use duration - %1$s
+ %1$s since unplugged
+
+ Device awake time
+
+ WiFi on time
+
+ WiFi on time
%1$s" - "
%2$s"%%"
@@ -1705,6 +1711,9 @@ found in the list of installed applications.
Bluetooth settings
+
+ Battery used by voice calls
+
Battery used when phone is idle
@@ -1747,7 +1756,12 @@ found in the list of installed applications.
Usage totals
Refresh
-
+
+
+ Android OS
+
+ Mediaserver
+
Speech synthesis
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index 450e438c435..b49b1409f59 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -15,7 +15,6 @@
-->
-
+ android:title="@string/battery_since_unplugged"
+ android:key="app_list">
diff --git a/src/com/android/settings/fuelgauge/PercentageBar.java b/src/com/android/settings/fuelgauge/PercentageBar.java
new file mode 100644
index 00000000000..1c4478bf49e
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/PercentageBar.java
@@ -0,0 +1,67 @@
+/*
+ * 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.fuelgauge;
+
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+
+/**
+ * A drawable for drawing a bar with a background.
+ */
+class PercentageBar extends Drawable {
+
+ Drawable bar;
+ double percent;
+ int lastWidth = -1;
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (lastWidth == -1) {
+ lastWidth = getBarWidth();
+ bar.setBounds(0, 0, lastWidth, bar.getIntrinsicHeight());
+ }
+ bar.draw(canvas);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ // Ignore
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ // Ignore
+ }
+
+ private int getBarWidth() {
+ int width = (int) ((this.getBounds().width() * percent) / 100);
+ int intrinsicWidth = bar.getIntrinsicWidth();
+ return Math.max(width, intrinsicWidth);
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return bar.getIntrinsicHeight();
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
index 5778b39bce3..68f294c39d2 100644
--- a/src/com/android/settings/fuelgauge/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/PowerGaugePreference.java
@@ -37,7 +37,7 @@ import com.android.settings.fuelgauge.PowerUsageSummary.BatterySipper;
public class PowerGaugePreference extends Preference {
private Drawable mIcon;
- private GaugeDrawable mGauge;
+ private PercentageBar mGauge;
private double mValue;
private BatterySipper mInfo;
private double mPercent;
@@ -46,7 +46,7 @@ public class PowerGaugePreference extends Preference {
super(context);
setLayoutResource(R.layout.preference_powergauge);
mIcon = icon;
- mGauge = new GaugeDrawable();
+ mGauge = new PercentageBar();
mGauge.bar = context.getResources().getDrawable(R.drawable.app_gauge);
mInfo = info;
}
@@ -90,44 +90,4 @@ public class PowerGaugePreference extends Preference {
percentView.setText((int) (Math.ceil(mPercent)) + "%");
}
- static class GaugeDrawable extends Drawable {
- Drawable bar;
- double percent;
- int lastWidth = -1;
-
- @Override
- public void draw(Canvas canvas) {
- if (lastWidth == -1) {
- lastWidth = getBarWidth();
- bar.setBounds(0, 0, lastWidth, bar.getIntrinsicHeight());
- }
- bar.draw(canvas);
- }
-
- @Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- @Override
- public void setAlpha(int alpha) {
- // Ignore
- }
-
- @Override
- public void setColorFilter(ColorFilter cf) {
- // Ignore
- }
-
- private int getBarWidth() {
- int width = (int) ((this.getBounds().width() * percent) / 100);
- int intrinsicWidth = bar.getIntrinsicWidth();
- return Math.max(width, intrinsicWidth);
- }
-
- @Override
- public int getIntrinsicHeight() {
- return bar.getIntrinsicHeight();
- }
- }
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageDetail.java b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
index e36a8bc776d..e78e0411e71 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageDetail.java
@@ -27,10 +27,12 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.ImageView;
import android.widget.TextView;
import com.android.settings.InstalledAppDetails;
@@ -48,6 +50,17 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
APP
}
+ // Note: Must match the sequence of the DrainType
+ private static int[] sDrainTypeDesciptions = new int[] {
+ R.string.battery_desc_standby,
+ R.string.battery_desc_radio,
+ R.string.battery_desc_voice,
+ R.string.battery_desc_wifi,
+ R.string.battery_desc_bluetooth,
+ R.string.battery_desc_display,
+ R.string.battery_desc_apps
+ };
+
public static final int ACTION_DISPLAY_SETTINGS = 1;
public static final int ACTION_WIFI_SETTINGS = 2;
public static final int ACTION_BLUETOOTH_SETTINGS = 3;
@@ -59,16 +72,18 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
public static final String EXTRA_TITLE = "title";
public static final String EXTRA_PERCENT = "percent";
+ public static final String EXTRA_GAUGE = "gauge";
public static final String EXTRA_UID = "uid";
public static final String EXTRA_USAGE_SINCE = "since";
public static final String EXTRA_USAGE_DURATION = "duration";
- public static final String EXTRA_DETAIL_TYPES = "types";
- public static final String EXTRA_DETAIL_VALUES = "values";
- public static final String EXTRA_DRAIN_TYPE = "drainType";
+ public static final String EXTRA_DETAIL_TYPES = "types"; // Array of usage types (cpu, gps, etc)
+ public static final String EXTRA_DETAIL_VALUES = "values"; // Array of doubles
+ public static final String EXTRA_DRAIN_TYPE = "drainType"; // DrainType
+ public static final String EXTRA_ICON_PACKAGE = "iconPackage"; // String
+ public static final String EXTRA_ICON_ID = "iconId"; // Int
private static final boolean DEBUG = true;
private String mTitle;
- private double mPercentage;
private int mUsageSince;
private int[] mTypes;
private int mUid;
@@ -79,6 +94,8 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
private DrainType mDrainType;
private int mAction1;
private int mAction2;
+ private PercentageBar mGauge;
+ private Drawable mAppIcon;
private static final String TAG = "PowerUsageDetail";
private Button mButton1;
@@ -106,20 +123,51 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
private void createDetails() {
final Intent intent = getIntent();
mTitle = intent.getStringExtra(EXTRA_TITLE);
- mPercentage = intent.getDoubleExtra(EXTRA_PERCENT, -1);
+ final int percentage = intent.getIntExtra(EXTRA_PERCENT, 1);
+ final int gaugeValue = intent.getIntExtra(EXTRA_GAUGE, 1);
mUsageSince = intent.getIntExtra(EXTRA_USAGE_SINCE, USAGE_SINCE_UNPLUGGED);
mUid = intent.getIntExtra(EXTRA_UID, 0);
mDrainType = (DrainType) intent.getSerializableExtra(EXTRA_DRAIN_TYPE);
+ String iconPackage = intent.getStringExtra(EXTRA_ICON_PACKAGE);
+ int iconId = intent.getIntExtra(EXTRA_ICON_ID, 0);
+ if (!TextUtils.isEmpty(iconPackage)) {
+ try {
+ final PackageManager pm = getPackageManager();
+ ApplicationInfo ai = pm.getPackageInfo(iconPackage, 0).applicationInfo;
+ if (ai != null) {
+ mAppIcon = ai.loadIcon(pm);
+ }
+ } catch (NameNotFoundException nnfe) {
+ // Use default icon
+ }
+ } else if (iconId != 0) {
+ mAppIcon = getResources().getDrawable(iconId);
+ }
+ if (mAppIcon == null) {
+ mAppIcon = getPackageManager().getDefaultActivityIcon();
+ }
+ // Set the description
+ String summary = getDescriptionForDrainType();
+ ((TextView)findViewById(R.id.summary)).setText(summary);
+
mTypes = intent.getIntArrayExtra(EXTRA_DETAIL_TYPES);
mValues = intent.getDoubleArrayExtra(EXTRA_DETAIL_VALUES);
mTitleView = (TextView) findViewById(R.id.name);
mTitleView.setText(mTitle);
- // TODO: I18N
((TextView)findViewById(R.id.battery_percentage))
- .setText(String.format("%3.2f%% of battery usage since last unplugged", mPercentage));
+ .setText(String.format("%d%%", percentage));
+ ImageView gaugeImage = (ImageView) findViewById(R.id.gauge);
+ mGauge = new PercentageBar();
+ mGauge.percent = gaugeValue;
+ mGauge.bar = getResources().getDrawable(R.drawable.app_gauge);
+ gaugeImage.setImageDrawable(mGauge);
+
+ ImageView iconImage = (ImageView) findViewById(R.id.icon);
+ iconImage.setImageDrawable(mAppIcon);
+
mDetailsParent = (ViewGroup) findViewById(R.id.details);
LayoutInflater inflater = getLayoutInflater();
if (mTypes != null && mValues != null) {
@@ -181,7 +229,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
mAction1 = 0;
mAction2 = 0;
PackageManager pm = getPackageManager();
- String[] packages = pm.getPackagesForUid(mUid);
+ String[] packages = pm.getPackagesForUid(uid);
PackageInfo pi = null;
try {
pi = packages != null ? pm.getPackageInfo(packages[0], 0) : null;
@@ -189,12 +237,14 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
ApplicationInfo ai = pi != null? pi.applicationInfo : null;
boolean isSystem = ai != null? (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0 : false;
- if (uid == 0 || !isSystem) {
+ if (uid < 1000 || !isSystem) {
switch (mDrainType) {
case APP:
//label1 = getString(R.string.battery_action_stop);
- label2 = getString(R.string.battery_action_app_details);
- mAction2 = ACTION_APP_DETAILS;
+ if (packages != null) {
+ label2 = getString(R.string.battery_action_app_details);
+ mAction2 = ACTION_APP_DETAILS;
+ }
break;
case SCREEN:
label2 = getString(R.string.battery_action_display);
@@ -246,7 +296,7 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
}
private void fillPackagesSection(int uid) {
- if (uid == 0) {
+ if (uid < 1) {
removePackagesSection();
return;
}
@@ -283,4 +333,8 @@ public class PowerUsageDetail extends Activity implements Button.OnClickListener
}
}
}
+
+ private String getDescriptionForDrainType() {
+ return getResources().getString(sDrainTypeDesciptions[mDrainType.ordinal()]);
+ }
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index b8919eefe14..d36dce77511 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -85,14 +85,19 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
private PowerProfile mPowerProfile;
- private HashMap mNameCache = new HashMap();
- private HashMap mIconCache = new HashMap();
+ private HashMap mUidCache = new HashMap();
/** Queue for fetching name and icon for an application */
private ArrayList mRequestQueue = new ArrayList();
private Thread mRequestThread;
private boolean mAbort;
+ static class UidToDetail {
+ String name;
+ String packageName;
+ Drawable icon;
+ }
+
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -126,7 +131,12 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
BatterySipper sipper = pgp.getInfo();
Intent intent = new Intent(this, PowerUsageDetail.class);
intent.putExtra(PowerUsageDetail.EXTRA_TITLE, sipper.name);
- intent.putExtra(PowerUsageDetail.EXTRA_PERCENT, sipper.getSortValue() * 100 / mTotalPower);
+ intent.putExtra(PowerUsageDetail.EXTRA_PERCENT, (int)
+ Math.ceil(sipper.getSortValue() * 100 / mTotalPower));
+ intent.putExtra(PowerUsageDetail.EXTRA_GAUGE, (int)
+ Math.ceil(sipper.getSortValue() * 100 / mMaxPower));
+ intent.putExtra(PowerUsageDetail.EXTRA_ICON_PACKAGE, sipper.defaultPackageName);
+ intent.putExtra(PowerUsageDetail.EXTRA_ICON_ID, sipper.iconId);
if (sipper.uidObj != null) {
intent.putExtra(PowerUsageDetail.EXTRA_UID, sipper.uidObj.getUid());
}
@@ -266,7 +276,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
private void updateStatsPeriod(long duration) {
String durationString = Utils.formatElapsedTime(this, duration / 1000);
String label = getString(R.string.battery_stats_duration, durationString);
- mAppListGroup.setTitle(label);
+ setTitle(label);
}
private void processAppUsage() {
@@ -475,8 +485,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
addWiFiUsage(uSecNow);
addBluetoothUsage(uSecNow);
addIdleUsage(uSecNow); // Not including cellular idle power
- //addRadioUsage(uSecNow); // Cannot include this because airplane mode is not tracked yet
- // and we don't know if the radio is currently running on 2/3G.
+ addRadioUsage(uSecNow);
}
private void addEntry(String label, DrainType drainType, long time, int iconId, double power) {
@@ -484,6 +493,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
mTotalPower += power;
BatterySipper bs = new BatterySipper(label, drainType, iconId, null, new double[] {power});
bs.usageTime = time;
+ bs.iconId = iconId;
mUsageList.add(bs);
}
@@ -503,6 +513,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
class BatterySipper implements Comparable {
String name;
Drawable icon;
+ int iconId; // For passing to the detail screen.
Uid uidObj;
double value;
double[] values;
@@ -512,6 +523,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
long gpsTime;
long cpuFgTime;
double percent;
+ String defaultPackageName;
BatterySipper(String label, DrainType drainType, int iconId, Uid uid, double[] values) {
this.values = values;
@@ -548,20 +560,28 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
void getQuickNameIconForUid(Uid uidObj) {
final int uid = uidObj.getUid();
final String uidString = Integer.toString(uid);
- if (mNameCache.containsKey(uidString)) {
- name = mNameCache.get(uidString);
- icon = mIconCache.get(uidString);
+ if (mUidCache.containsKey(uidString)) {
+ UidToDetail utd = mUidCache.get(uidString);
+ defaultPackageName = utd.packageName;
+ name = utd.name;
+ icon = utd.icon;
return;
}
PackageManager pm = getPackageManager();
final Drawable defaultActivityIcon = pm.getDefaultActivityIcon();
String[] packages = pm.getPackagesForUid(uid);
+ icon = pm.getDefaultActivityIcon();
if (packages == null) {
- name = Integer.toString(uid);
+ //name = Integer.toString(uid);
+ if (uid == 0) {
+ name = getResources().getString(R.string.process_kernel_label);
+ } else if (name.equals("mediaserver")) {
+ name = getResources().getString(R.string.process_mediaserver_label);
+ }
+ return;
} else {
//name = packages[0];
}
- icon = pm.getDefaultActivityIcon();
synchronized (mRequestQueue) {
mRequestQueue.add(this);
}
@@ -596,6 +616,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
packageLabels[i] = label.toString();
}
if (ai.icon != 0) {
+ defaultPackageName = packages[i];
icon = ai.loadIcon(pm);
break;
}
@@ -617,6 +638,7 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
if (nm != null) {
name = nm.toString();
if (pi.applicationInfo.icon != 0) {
+ defaultPackageName = pkgName;
icon = pi.applicationInfo.loadIcon(pm);
}
break;
@@ -627,8 +649,11 @@ public class PowerUsageSummary extends PreferenceActivity implements Runnable {
}
}
final String uidString = Integer.toString(uidObj.getUid());
- mNameCache.put(uidString, name);
- mIconCache.put(uidString, icon);
+ UidToDetail utd = new UidToDetail();
+ utd.name = name;
+ utd.icon = icon;
+ utd.packageName = defaultPackageName;
+ mUidCache.put(uidString, utd);
mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_NAME_ICON, this));
}
}
From 2acc02e94272f7796a50fe0821e46c6643968646 Mon Sep 17 00:00:00 2001
From: Jean-Michel Trivi
Date: Thu, 25 Jun 2009 10:03:43 -0700
Subject: [PATCH 104/126] Remove pitch selection from TTS settings. Use the
settings name for the locale property rather than the UI key. Add prefs entry
to install the voice data.
---
res/xml/tts_settings.xml | 8 --
.../settings/TextToSpeechSettings.java | 90 ++++++++++---------
2 files changed, 50 insertions(+), 48 deletions(-)
diff --git a/res/xml/tts_settings.xml b/res/xml/tts_settings.xml
index 4ec2a4d801c..d94d5754cc6 100644
--- a/res/xml/tts_settings.xml
+++ b/res/xml/tts_settings.xml
@@ -45,14 +45,6 @@
android:persistent="false"
android:entries="@array/tts_rate_entries"
android:entryValues="@array/tts_rate_values" />
-
-
resolveInfos = pm.queryIntentActivities(intent, 0);
+ // query only the package that matches that of the default engine
+ for (int i = 0; i < resolveInfos.size(); i++) {
+ ActivityInfo currentActivityInfo = resolveInfos.get(i).activityInfo;
+ if (mDefaultEng.equals(currentActivityInfo.packageName)) {
+ intent.setClassName(mDefaultEng, currentActivityInfo.name);
+ this.startActivityForResult(intent, VOICE_DATA_INSTALLATION);
+ }
+ }
+ }
+
+
/**
* Called when the TTS engine is initialized.
*/
@@ -273,7 +293,8 @@ public class TextToSpeechSettings extends PreferenceActivity implements
}
} else {
Log.v(TAG, "Voice data check failed");
-
+ mEnableDemo = false;
+ updateWidgetState();
}
}
}
@@ -299,16 +320,6 @@ public class TextToSpeechSettings extends PreferenceActivity implements
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist default TTS rate setting", e);
}
- } else if (KEY_TTS_DEFAULT_PITCH.equals(preference.getKey())) {
- // Default pitch
- int value = Integer.parseInt((String) objValue);
- try {
- Settings.Secure.putInt(getContentResolver(),
- TTS_DEFAULT_PITCH, value);
- Log.i(TAG, "TTS default pitch is "+value);
- } catch (NumberFormatException e) {
- Log.e(TAG, "could not persist default TTS pitch setting", e);
- }
} else if (KEY_TTS_DEFAULT_LANG.equals(preference.getKey())) {
// Default locale
ContentResolver resolver = getContentResolver();
@@ -337,9 +348,9 @@ public class TextToSpeechSettings extends PreferenceActivity implements
return true;
}
if (preference == mInstallData) {
- // Install data
- // TODO launch request for installer
-
+ installVoiceData();
+ // quit this activity so it needs to be restarted after installation of the voice data
+ finish();
return true;
}
return false;
@@ -350,7 +361,6 @@ public class TextToSpeechSettings extends PreferenceActivity implements
mPlayExample.setEnabled(mEnableDemo);
mUseDefaultPref.setEnabled(mEnableDemo);
mDefaultRatePref.setEnabled(mEnableDemo);
- mDefaultPitchPref.setEnabled(mEnableDemo);
mDefaultLocPref.setEnabled(mEnableDemo);
mInstallData.setEnabled(!mEnableDemo);
From b7e46e89d77574dbb51855144ea3d46fcf220bbb Mon Sep 17 00:00:00 2001
From: Mike Lockwood
Date: Thu, 25 Jun 2009 13:36:00 -0400
Subject: [PATCH 105/126] Display a warning dialog when the user enables USB
debugging.
Signed-off-by: Mike Lockwood
---
res/values/strings.xml | 6 ++-
.../android/settings/DevelopmentSettings.java | 40 +++++++++++++++++--
2 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 63b343d58c1..5df6cf595b7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1457,7 +1457,7 @@ found in the list of installed applications.
No shortcut
Search + %1$s
-
+
Clear
Your shortcut for %1$s (%2$s) will be cleared.
@@ -1498,6 +1498,10 @@ found in the list of installed applications.
Allow mock locations
Allow mock locations
+
+ Enable USB debugging?
+
+ USB debugging is intended for development purposes only. It can be used to copy data between your computer and your device, install applications on your device without notification, and read log data.
Search
- Manage system search, web search and search history
+ Manage search settings and history
From 386278a338d740dce95b7fa1514662b0eb5683e4 Mon Sep 17 00:00:00 2001
From: Chouting Zhang
Date: Wed, 24 Jun 2009 14:25:43 -0500
Subject: [PATCH 108/126] CDMA Settings additions
This patch implement CDMA Settings features
1. Add code to get MEID, MIN, and PRL value if the phone is a CDMA Phone
2. Display MEID, MIN, and PRL on Settings screen if it is a CDMA phone
3. Do not display IMSI, IMEI, and IMEI SV for a CDMA phone
---
res/values/arrays.xml | 14 +++++++++
res/values/strings.xml | 15 ++++++++--
res/xml/device_info_status.xml | 18 ++++++++++++
res/xml/sound_and_display_settings.xml | 7 +++++
.../android/settings/SecuritySettings.java | 29 ++++++++++++-------
.../settings/SoundAndDisplaySettings.java | 25 ++++++++++++++++
.../android/settings/deviceinfo/Status.java | 24 ++++++++++++---
7 files changed, 115 insertions(+), 17 deletions(-)
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 9bfeb1309d4..750b0835719 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -241,4 +241,18 @@
- GTC
+
+
+ - Off
+ - Alert
+ - Vibrate
+
+
+
+
+ - 0
+ - 1
+ - 2
+
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c99610dbe74..b049a2a4334 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -965,7 +965,7 @@
Status
- IMEI, phone number, signal, etc.
+ Phone number, signal, etc.
SD card & phone storage
@@ -975,7 +975,13 @@
IMEI SV
- Phone number
+ My phone number
+
+ MIN
+
+ PRL Version
+
+ MEID
Mobile network type
@@ -1879,4 +1885,9 @@ found in the list of installed applications.
VPN
VPN
Set up & manage VPN configurations, connections
+
+
+ Emergency tone
+
+ Set behavior when an emergency call is placed
diff --git a/res/xml/device_info_status.xml b/res/xml/device_info_status.xml
index 2d4c772391f..dee606d6fb8 100644
--- a/res/xml/device_info_status.xml
+++ b/res/xml/device_info_status.xml
@@ -32,6 +32,24 @@
android:title="@string/status_number"
android:summary="@string/device_info_not_available"
android:persistent="false" />
+
+
+
+
+
+
+
+
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index c17e2a059df..ffeac3406d5 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -41,6 +41,7 @@ import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
+import android.telephony.TelephonyManager;
import java.util.Observable;
import java.util.Observer;
@@ -166,18 +167,24 @@ public class SecuritySettings extends PreferenceActivity implements
mChoosePattern.setIntent(intent);
inlinePrefCat.addPreference(mChoosePattern);
- PreferenceScreen simLockPreferences = getPreferenceManager()
- .createPreferenceScreen(this);
- simLockPreferences.setTitle(R.string.sim_lock_settings_category);
- // Intent to launch SIM lock settings
- intent = new Intent();
- intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
- simLockPreferences.setIntent(intent);
+ int activePhoneType = TelephonyManager.getDefault().getPhoneType();
+
+ // do not display SIM lock for CDMA phone
+ if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType)
+ {
+ PreferenceScreen simLockPreferences = getPreferenceManager()
+ .createPreferenceScreen(this);
+ simLockPreferences.setTitle(R.string.sim_lock_settings_category);
+ // Intent to launch SIM lock settings
+ intent = new Intent();
+ intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
+ simLockPreferences.setIntent(intent);
- PreferenceCategory simLockCat = new PreferenceCategory(this);
- simLockCat.setTitle(R.string.sim_lock_settings_title);
- root.addPreference(simLockCat);
- simLockCat.addPreference(simLockPreferences);
+ PreferenceCategory simLockCat = new PreferenceCategory(this);
+ simLockCat.setTitle(R.string.sim_lock_settings_title);
+ root.addPreference(simLockCat);
+ simLockCat.addPreference(simLockPreferences);
+ }
// Passwords
PreferenceCategory passwordsCat = new PreferenceCategory(this);
diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundAndDisplaySettings.java
index 41114506a9d..3d3a5d0606e 100644
--- a/src/com/android/settings/SoundAndDisplaySettings.java
+++ b/src/com/android/settings/SoundAndDisplaySettings.java
@@ -37,6 +37,7 @@ import android.preference.CheckBoxPreference;
import android.provider.Settings;
import android.util.Log;
import android.view.IWindowManager;
+import android.telephony.TelephonyManager;
public class SoundAndDisplaySettings extends PreferenceActivity implements
Preference.OnPreferenceChangeListener {
@@ -44,6 +45,7 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
/** If there is no setting in the provider, use this. */
private static final int FALLBACK_SCREEN_TIMEOUT_VALUE = 30000;
+ private static final int FALLBACK_EMERGENCY_TONE_VALUE = 0;
private static final String KEY_SILENT = "silent";
private static final String KEY_VIBRATE = "vibrate";
@@ -54,6 +56,7 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
private static final String KEY_ACCELEROMETER = "accelerometer";
private static final String KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS = "play_media_notification_sounds";
private static final String KEY_COMPATIBILITY_MODE = "compatibility_mode";
+ private static final String KEY_EMERGENCY_TONE ="emergency_tone";
private CheckBoxPreference mSilent;
@@ -91,6 +94,7 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ContentResolver resolver = getContentResolver();
+ int activePhoneType = TelephonyManager.getDefault().getPhoneType();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
@@ -99,6 +103,11 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
addPreferencesFromResource(R.xml.sound_and_display_settings);
+ if (TelephonyManager.PHONE_TYPE_CDMA != activePhoneType) {
+ // device is not CDMA, do not display CDMA emergency_tone
+ getPreferenceScreen().removePreference(findPreference(KEY_EMERGENCY_TONE));
+ }
+
mSilent = (CheckBoxPreference) findPreference(KEY_SILENT);
mPlayMediaNotificationSounds = (CheckBoxPreference) findPreference(KEY_PLAY_MEDIA_NOTIFICATION_SOUNDS);
@@ -125,6 +134,14 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
screenTimeoutPreference.setValue(String.valueOf(Settings.System.getInt(
resolver, SCREEN_OFF_TIMEOUT, FALLBACK_SCREEN_TIMEOUT_VALUE)));
screenTimeoutPreference.setOnPreferenceChangeListener(this);
+
+ if (TelephonyManager.PHONE_TYPE_CDMA == activePhoneType) {
+ ListPreference emergencyTonePreference =
+ (ListPreference) findPreference(KEY_EMERGENCY_TONE);
+ emergencyTonePreference.setValue(String.valueOf(Settings.System.getInt(
+ resolver, Settings.System.EMERGENCY_TONE, FALLBACK_EMERGENCY_TONE_VALUE)));
+ emergencyTonePreference.setOnPreferenceChangeListener(this);
+ }
}
@Override
@@ -273,6 +290,14 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
} catch (NumberFormatException e) {
Log.e(TAG, "could not persist screen timeout setting", e);
}
+ } else if (KEY_EMERGENCY_TONE.equals(preference.getKey())) {
+ int value = Integer.parseInt((String) objValue);
+ try {
+ Settings.System.putInt(getContentResolver(),
+ Settings.System.EMERGENCY_TONE, value);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "could not persist emergency tone setting", e);
+ }
}
return true;
diff --git a/src/com/android/settings/deviceinfo/Status.java b/src/com/android/settings/deviceinfo/Status.java
index ece53465a86..a165754104b 100644
--- a/src/com/android/settings/deviceinfo/Status.java
+++ b/src/com/android/settings/deviceinfo/Status.java
@@ -182,11 +182,27 @@ public class Status extends PreferenceActivity {
mUptime = findPreference("up_time");
//NOTE "imei" is the "Device ID" since it represents the IMEI in GSM and the MEID in CDMA
- setSummaryText("imei", mPhone.getDeviceId());
-
- setSummaryText("imei_sv",
- ((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
+ if (mPhone.getPhoneName().equals("CDMA")) {
+ setSummaryText("meid_number", mPhone.getMeid());
+ setSummaryText("min_number", mPhone.getCdmaMin());
+ setSummaryText("prl_version", mPhone.getCdmaPrlVersion());
+
+ // device is not GSM/UMTS, do not display GSM/UMTS features
+ getPreferenceScreen().removePreference(findPreference("imei"));
+ getPreferenceScreen().removePreference(findPreference("imei_sv"));
+ } else {
+ setSummaryText("imei", mPhone.getDeviceId());
+
+ setSummaryText("imei_sv",
+ ((TelephonyManager) getSystemService(TELEPHONY_SERVICE))
.getDeviceSoftwareVersion());
+
+ // device is not CDMA, do not display CDMA features
+ getPreferenceScreen().removePreference(findPreference("prl_version"));
+ getPreferenceScreen().removePreference(findPreference("meid_number"));
+ getPreferenceScreen().removePreference(findPreference("min_number"));
+ }
+
setSummaryText("number", mPhone.getLine1Number());
mPhoneStateReceiver = new PhoneStateIntentReceiver(this, mHandler);
From e7565f3c48e6c90e65d9c15e33d20673a187c156 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Fri, 26 Jun 2009 14:24:50 +0800
Subject: [PATCH 109/126] Add L2TP secret, L2TP/IPSec PSK support. Fix screen
orientation.
* Changes
+ Add L2tpActor, L2tpEditor, L2tpIpsecPskActor.
+ Make L2tpIpsecEditor extend L2tpEditor.
+ Revise the code for saving username. Make
VpnSettings.saveProfileToStorage() static.
+ Fix support for screen orientation change in both VpnSettings and
VpnEditor.
Patch Set 2:
+ Remove Util.isNullOrEmpty(). Use TextUtils.isEmpty() instead.
+ Remove unused imports. Wrap lines longer than 80 chars.
Patch Set 3:
+ Fix all the strings according to UI feedback.
+ Remove all the added actor subclasses and move password to editor.
+ Remove VPN entry in Security & location.
Patch Set 4:
+ Misc string fixes.
Patch Set 5:
+ Add strings for credential storage settings.
+ Changed the error dialog icon.
+ Fix "Remember me" indentation in connect dialog.
Patch Set 6:
+ resolve res/values/strings.xml
---
res/layout/vpn_connect_dialog_view.xml | 105 ++++----
res/values/dimens.xml | 5 +-
res/values/strings.xml | 172 ++++++++----
res/xml/vpn_edit.xml | 5 +-
res/xml/vpn_settings.xml | 2 +-
res/xml/vpn_type.xml | 2 +-
.../android/settings/SecuritySettings.java | 12 -
.../settings/vpn/AuthenticationActor.java | 33 ++-
src/com/android/settings/vpn/L2tpEditor.java | 119 ++++++++
.../android/settings/vpn/L2tpIpsecEditor.java | 42 +--
src/com/android/settings/vpn/Util.java | 9 +-
src/com/android/settings/vpn/VpnEditor.java | 109 ++++----
.../settings/vpn/VpnProfileEditor.java | 150 +++++++++--
src/com/android/settings/vpn/VpnSettings.java | 255 +++++++++---------
.../settings/vpn/VpnTypeSelection.java | 9 +-
15 files changed, 660 insertions(+), 369 deletions(-)
create mode 100644 src/com/android/settings/vpn/L2tpEditor.java
diff --git a/res/layout/vpn_connect_dialog_view.xml b/res/layout/vpn_connect_dialog_view.xml
index be66c2fcadc..062f881c202 100644
--- a/res/layout/vpn_connect_dialog_view.xml
+++ b/res/layout/vpn_connect_dialog_view.xml
@@ -1,54 +1,69 @@
+
+
+
+ android:layout_height="wrap_content">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_marginLeft="66dip"
+ android:text="@string/vpn_save_username" />
+
-
-
-
-
-
-
-
-
-
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 56bd60cef64..790f86b4162 100755
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -1,9 +1,6 @@
- 5sp
- 5sp
+ 10sp
16sp
90sp
- 200sp
- 5sp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b049a2a4334..7c6529d9cee 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1817,74 +1817,150 @@ found in the list of installed applications.
VPN settings
- User name:
+
+ Connect to %s
+
+ Username:
Password:
- User name
- Password
+ username
+ password
+
+
Remember me
- You missed a field!
- Please fill up \"%s\".
Connect
- Cancel
Yes
No
Back
No, it's a mistake
- Save
-
- Discard
- Connect
- Disconnect
- Edit
- Delete
+ Save
+ Cancel
+ Revert
+ Connect to network
+ Disconnect network
+ Edit network
+ Delete network
-
- Attention
- VPN Name cannot be empty.
- The Server Name field cannot be empty.
- The VPN Name \'%s\' already exists. Find another name.
- Need to select a user certificate.
- Need to select a CA certificate.
- Need to select a userkey.
- Are you sure you don\'t want to create this profile?
+
+ You must enter a %s.
+ You must select a %s.
+ The VPN name \'%s\' already exists. Find another name.
+ Are you sure you want to delete this VPN?
+ Are you sure you don\'t want to create this profile?
+ Are you sure you want to discard the changes made to this profile?
The previous connection attempt failed. Do you want to try again?
- Add new VPN
- Add new %s VPN
- Edit %s VPN
- Select VPN type
- VPN networks
-
- Click to set the value
-
+
+ Add VPN
+
+ Add VPN
+
+ Add %s VPN
+
+ %s details
+
+ VPNs
+
Connecting...
-
+
Disconnecting...
-
+
Connected
-
- Select to connect
-
- Connect to %s
+
+ Connect to network
+
nowhere
- VPN Name
- Give a name to this VPN
+
+ VPN name
- '%s' is added
- Changes are made to '%s'
+
+ '%s' is added
+
+ Changes are made to '%s'
- User Certificate
- CA Certificate
- User Key
- Server Name
- DNS Search List
+
+ Set user certificate
+
+ User certificate
- VPN
- VPN
- Set up & manage VPN configurations, connections
+
+ Set CA certificate
+
+ Certificate authority (CA) certificate
+
+ Set L2TP secret
+
+ L2TP secret
+
+
+ Set IPSec pre-shared key
+
+ IPSec pre-shared key
+
+
+ Set VPN server
+
+ VPN server
+
+ VPN server name
+
+
+ DNS search domains
+
+ DNS search domains
+
+
+ %s is set
+
+ %s not set
+
+ %s not set (optional)
+
+
+ Enable %s
+
+ Disable %s
+
+
+ %s is enabled
+
+ %s is disabled
+
+
+ VPN settings
+
+ Set up & manage Virtual Private Networks (VPNs)
+
+
+ Credential storage
+
+ Use secure credentials
+
+ Allow applications to access secure certificates and other credentials
+
+
+ Set storage password
+
+ Set or change the secure credential storage password
+
+ Set password
+
+
+ Clear storage
+
+ Clear credential storage of all contents and reset its password
+ Are you sure you want to delete all certificates and other stored credentials and reset the password?
+
+
+ Current password:
+
+ New password:
+
+ Confirm new password:
+
+ You must set a password for credential storage before you can store secure certificates and other credentials in it.
Emergency tone
diff --git a/res/xml/vpn_edit.xml b/res/xml/vpn_edit.xml
index 7976242160d..a3cab9c2ecf 100644
--- a/res/xml/vpn_edit.xml
+++ b/res/xml/vpn_edit.xml
@@ -1,5 +1,5 @@
-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
+ android:drawable="@drawable/appwidget_inner_default" />
+ android:drawable="@drawable/appwidget_inner_pressed" />
+ android:drawable="@drawable/appwidget_inner_selected" />
+ android:drawable="@drawable/appwidget_inner_default" />
+ android:drawable="@drawable/appwidget_inner_default" />
diff --git a/res/drawable/appwidget_inner_default.9.png b/res/drawable/appwidget_inner_default.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..2c37b898107278fd54c082b2f9fd9f053428051f
GIT binary patch
literal 179
zcmeAS@N?(olHy`uVBq!ia0vp^tUzqe!3HFc+--0MQjEnx?oJHr&dIz4a@dl*-CY>|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfO*UCEA)U6sxNxA5v8Rh;h{fsT
z1c!$IJSP;&AFk9(@l<2eNeC$b!3d6j%RPSAmoU$e0D}L<57-JU8T`L+9$nk(pa9g)
N;OXk;vd$@?2>?vLF~I-;
literal 0
HcmV?d00001
diff --git a/res/drawable/appwidget_inner_pressed.9.png b/res/drawable/appwidget_inner_pressed.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..b23c3ae51d6e82275c293527fceb94a39c94d231
GIT binary patch
literal 301
zcmeAS@N?(olHy`uVBq!ia0vp^tUzqe!3HFc+--0MQjEnx?oJHr&dIz4a@dl*-CY>|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfO*UC^M$;zoyGB5vwVp1HAr`0K
zUf#%i$UuPgLVbGk6rPi8JO{XP4qEv*xVraG(BL>(tM$gA?qSoU)oY$_-d{7RG3v;k
zZS9ZeJ&(QlWs`BtiOX#a6S(`XZ(3tkK)*
z@Y2W6er~SqE9|!=%vFyT6k2O~VvXqC(DbPN{~zxOUa)k{yFX4$8zO^j-)%dxWmA8;
skis70igeaqhM@Tqf9;v!EP0RnW2}c3@3NzLK!-DUy85}Sb4q9e0Du5|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfO*UC^Ch?l6^P)hZO`a}}Ar`0K
zUOvcs$bg6S!u@M}3s!A5WK`bZvE9MvfYh5Niv|YM%(F|qf}hGOo%@lpw`ObSVg_%?
zOIGvN)$Y>RxLbyYVbxzr!H>I+mK{7l_rV8+7xyi1z3?{VS^A=T^1-4xOgE-UY
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/drawable/appwidget_outer_default.9.png b/res/drawable/appwidget_outer_default.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..d84e56a407075655823964872297a80838e1ff4a
GIT binary patch
literal 179
zcmeAS@N?(olHy`uVBq!ia0vp^tUzqe!3HFc+--0MQjEnx?oJHr&dIz4a@dl*-CY>|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfO*UCEBNbV`Psf2m#-1*YAr_~T
z6C4`;^PEs9f2f)Au3n8zCn2N&1S2^9E%*3cU&1^?0to&aKVU1cWcYBJ)4ILv*|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfO*UC^R&~)snRP&+1)eUBAr`0K
zUf9Tc$UuPgLj5*JuE_?WW(f?(8VhGAgr;>&(BSwc>v}-tqkEC#$*J%E{q$zDOP+E5
zVM*iH<9kFHHmp0Vd2_xX14Cg%jNgoPJozkN;}*SaPDomze9$96STkta5?3irDQouZ
z=_PWgq|m
literal 0
HcmV?d00001
diff --git a/res/drawable/appwidget_outer_selected.9.png b/res/drawable/appwidget_outer_selected.9.png
new file mode 100644
index 0000000000000000000000000000000000000000..c6d5df77b2fb42e97aac5e86bc58797e63b802a6
GIT binary patch
literal 298
zcmeAS@N?(olHy`uVBq!ia0vp^tUzqe!3HFc+--0MQjEnx?oJHr&dIz4a@dl*-CY>|
zgW!U_%O?XxI14-?iy0WWg+Z8+Vb&Z8pdfpRr>`sfO*UC^Hl9hrhyMbFR(ZNOhFF|_
zdwC=8Ap?QdhtHqLICR{c(I6Pn7%L!bz@)odflFY)jgNr>J-YTPmy4f1|1YE+)No$o
zQe=Mrg~MucQVbXVYK5ikY-V7{Tb}c|wcq&QKc@?Ky{{a+y6AoO#n9<--aK+|ym%rd
zGbC5d_dNY)R))i~ep8SA%ctx=`u>Ihi}O^og^4<;(;k$%cwb0)`rFk=@kZI2Eo-I-
orADn=J$L%+Wzi8wr+2dZPiA$gN)Flj4CrbGPgg&ebxsLQ0F{7ocK`qY
literal 0
HcmV?d00001
diff --git a/res/drawable/widget_bg.9.png b/res/drawable/widget_bg.9.png
deleted file mode 100644
index a2007ad92e0512c58ce3373937b72f80d8277268..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 777
zcmV+k1NQuhP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iXJ<
z6&e)e93Jcd00N0gL_t(&-tC&fN*hrWhQB-2icT;Mfz(w&+eN#WSy|`{2&J1oMYqAF
zP!Yrwe22bADY$AkwoBUxmKZ6`s+A!bG0A8$bGmS}lc|n@HpvX!1DAwJnECF>fB$ni
zHwr*R08mO@y}vG$Qa6A24+l%%3(R#bx+4cS4JP1TaIeb4jZ?`+U_4?7eZQF~08D$#ak6p-Z
zRVvF}&)W|~WD=w6dHY+H$}*6<4Om&0wbb>zgGs?gpbsp|S^`uOaIRLXZAeO@R;z6Q
zxhQblCCr6|g_mh@gpkFIF1I-FoN1a?T7W~Axg;N+QA$mx1vq4xNdh*~Ufhh(u&*YS
zLSUu$5*kD?3k3`0WR0uitdMkiT3vp@+Id0t?`Cao*gE
zJaeF!skB$Nc<6?<2F^P0P`k2=Kc|d7hB1I)NycR*xAOc3)&lInn^mIf00000NkvXX
Hu0mjf!meeD
diff --git a/res/drawable/widget_btn_default.9.png b/res/drawable/widget_btn_default.9.png
deleted file mode 100644
index 3908327d9eef24ff8f2a49e7f22255c2c995e2e2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 3365
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
diff --git a/res/drawable/widget_btn_pressed.9.png b/res/drawable/widget_btn_pressed.9.png
deleted file mode 100644
index 112a8eb9af06e54b0cb8d8f0be2462ed12bbd9c8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 3720
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/widget.xml b/res/layout/widget.xml
index dea290e2a5c..3a223b63c78 100644
--- a/res/layout/widget.xml
+++ b/res/layout/widget.xml
@@ -16,62 +16,47 @@
+ android:background="@drawable/appwidget_bg" >
diff --git a/res/xml/appwidget_info.xml b/res/xml/appwidget_info.xml
index 02a1dfd4a1d..2186dab6592 100644
--- a/res/xml/appwidget_info.xml
+++ b/res/xml/appwidget_info.xml
@@ -15,7 +15,7 @@
-->
From 88ec7ebfe935c0541df3289c31574adbc01bd8bb Mon Sep 17 00:00:00 2001
From: Jean-Michel Trivi
Date: Tue, 30 Jun 2009 15:09:23 -0700
Subject: [PATCH 112/126] Fix bug 1943785 where the default country string
could be accessed while still being null. This was due to
Settings.Secure.getString() returning null when a property isn't found,
instead of a string with the value "null".
---
src/com/android/settings/TextToSpeechSettings.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index 94b256f6290..ec0fc8cde66 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -188,7 +188,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
if (country == null) {
// country wasn't initialized yet because a default language was found
country = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
- if (country.compareTo("null") != 0) {
+ if (country != null) {
mDefaultCountry = country;
} else {
// default country setting not found, initialize it, as well as the variant;
@@ -201,7 +201,7 @@ public class TextToSpeechSettings extends PreferenceActivity implements
if (variant == null) {
// variant wasn't initialized yet because a default country was found
variant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
- if (variant.compareTo("null") != 0) {
+ if (variant != null) {
mDefaultLocVariant = variant;
} else {
// default variant setting not found, initialize it
From e5b9e4bddf1aed4f647da3966d831a165a064f80 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Wed, 1 Jul 2009 11:06:45 +0800
Subject: [PATCH 113/126] Add L2tpIpsecPskEditor.
* Changes
+ Add L2tpIpsecPskEditor.java.
+ Save profile name in VpnEditor to be used in saveSecrets().
---
res/values/strings.xml | 7 ++
.../settings/vpn/L2tpIpsecPskEditor.java | 78 +++++++++++++++++++
src/com/android/settings/vpn/VpnEditor.java | 10 +++
3 files changed, 95 insertions(+)
create mode 100644 src/com/android/settings/vpn/L2tpIpsecPskEditor.java
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7c6529d9cee..fb806c9349c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1894,6 +1894,11 @@ found in the list of installed applications.
L2TP secret
+
+ Set IPSec pre-shared key
+
+ IPSec pre-shared key
+
Set IPSec pre-shared key
@@ -1961,6 +1966,8 @@ found in the list of installed applications.
Confirm new password:
You must set a password for credential storage before you can store secure certificates and other credentials in it.
+ Passwords do not match.
+ Please fill up all the fields.
Emergency tone
diff --git a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
new file mode 100644
index 00000000000..9c1d02c3903
--- /dev/null
+++ b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
@@ -0,0 +1,78 @@
+/*
+ * 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.vpn;
+
+import com.android.settings.R;
+
+import android.content.Context;
+import android.net.vpn.L2tpIpsecPskProfile;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.PreferenceGroup;
+
+/**
+ * The class for editing {@link L2tpIpsecPskProfile}.
+ */
+class L2tpIpsecPskEditor extends L2tpEditor {
+ private EditTextPreference mPresharedKey;
+
+ public L2tpIpsecPskEditor(L2tpIpsecPskProfile p) {
+ super(p);
+ }
+
+ @Override
+ protected void loadExtraPreferencesTo(PreferenceGroup subpanel) {
+ Context c = subpanel.getContext();
+ subpanel.addPreference(createPresharedKeyPreference(c));
+ super.loadExtraPreferencesTo(subpanel);
+ }
+
+ @Override
+ public String validate() {
+ String result = super.validate();
+
+ return ((result != null)
+ ? result
+ : validate(mPresharedKey, R.string.vpn_ipsec_presharedkey));
+ }
+
+ @Override
+ public void saveSecrets(String originalProfileName) {
+ L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
+ profile.getPresharedKey();
+ // TODO: fill up the implementation after keystore is available
+ }
+
+ private Preference createPresharedKeyPreference(Context c) {
+ final L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
+ mPresharedKey = createSecretPreference(c,
+ R.string.vpn_ipsec_presharedkey_title,
+ R.string.vpn_ipsec_presharedkey,
+ profile.getPresharedKey(),
+ new Preference.OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(
+ Preference pref, Object newValue) {
+ profile.setPresharedKey((String) newValue);
+ setSecretSummary(mPresharedKey,
+ R.string.vpn_ipsec_presharedkey,
+ (String) newValue);
+ return true;
+ }
+ });
+ return mPresharedKey;
+ }
+}
diff --git a/src/com/android/settings/vpn/VpnEditor.java b/src/com/android/settings/vpn/VpnEditor.java
index 9df98a61e38..e33ce550904 100644
--- a/src/com/android/settings/vpn/VpnEditor.java
+++ b/src/com/android/settings/vpn/VpnEditor.java
@@ -22,6 +22,7 @@ import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.vpn.L2tpIpsecProfile;
+import android.net.vpn.L2tpIpsecPskProfile;
import android.net.vpn.L2tpProfile;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnType;
@@ -41,9 +42,11 @@ public class VpnEditor extends PreferenceActivity {
private static final int MENU_SAVE = Menu.FIRST;
private static final int MENU_CANCEL = Menu.FIRST + 1;
private static final String KEY_PROFILE = "profile";
+ private static final String KEY_ORIGINAL_PROFILE_NAME = "orig_profile_name";
private VpnProfileEditor mProfileEditor;
private boolean mAddingProfile;
+ private String mOriginalProfileName;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -51,6 +54,9 @@ public class VpnEditor extends PreferenceActivity {
VpnProfile p = (VpnProfile) ((savedInstanceState == null)
? getIntent().getParcelableExtra(VpnSettings.KEY_VPN_PROFILE)
: savedInstanceState.getParcelable(KEY_PROFILE));
+ mOriginalProfileName = (savedInstanceState == null)
+ ? p.getName()
+ : savedInstanceState.getString(KEY_ORIGINAL_PROFILE_NAME);
mProfileEditor = getEditor(p);
mAddingProfile = TextUtils.isEmpty(p.getName());
@@ -65,6 +71,7 @@ public class VpnEditor extends PreferenceActivity {
if (mProfileEditor == null) return;
outState.putParcelable(KEY_PROFILE, getProfile());
+ outState.putString(KEY_ORIGINAL_PROFILE_NAME, mOriginalProfileName);
}
@Override
@@ -119,6 +126,7 @@ public class VpnEditor extends PreferenceActivity {
return false;
}
+ mProfileEditor.saveSecrets(mOriginalProfileName);
setResult(getProfile());
return true;
}
@@ -136,6 +144,8 @@ public class VpnEditor extends PreferenceActivity {
return new L2tpIpsecEditor((L2tpIpsecProfile) p);
case L2TP_IPSEC_PSK:
+ return new L2tpIpsecPskEditor((L2tpIpsecPskProfile) p);
+
case L2TP:
return new L2tpEditor((L2tpProfile) p);
From 132b21440b1b930322fc129a504afa6107835f8e Mon Sep 17 00:00:00 2001
From: Michael Chan
Date: Wed, 1 Jul 2009 14:06:43 -0700
Subject: [PATCH 114/126] Disable the individual remote Bluetooth devices when
BT is off
---
.../android/settings/bluetooth/BluetoothDevicePreference.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index f0a818909a3..7053ff5fd74 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -104,6 +104,9 @@ public class BluetoothDevicePreference extends Preference implements LocalBlueto
protected void onBindView(View view) {
super.onBindView(view);
+ // Disable this view if the bluetooth enable/disable preference view is off
+ setDependency("bt_checkbox");
+
ImageView btClass = (ImageView) view.findViewById(R.id.btClass);
btClass.setImageResource(mLocalDevice.getBtClassDrawable());
btClass.setAlpha(isEnabled() ? 255 : sDimAlpha);
From 7031ab0d756327496ac3ce1e082b53c94be2f3b1 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Thu, 2 Jul 2009 00:26:46 +0800
Subject: [PATCH 115/126] Add credential storage settings.
* Changes
+ Initial implementation of credential storage settings.
+ Use alert icon on delete and reconnect dialogs in VpnSettings.
(piggy-backed)
Patch Set 12:
+ Add password length and no-space verification.
+ Simplify dialog view xml files.
---
.../cstor_name_credential_dialog_view.xml | 58 ++
res/layout/cstor_set_password_dialog_view.xml | 76 +++
res/layout/cstor_unlock_dialog_view.xml | 40 ++
res/values/colors.xml | 1 +
res/values/strings.xml | 35 +-
.../android/settings/SecuritySettings.java | 538 +++++++++++++++++-
src/com/android/settings/vpn/VpnSettings.java | 2 +
7 files changed, 737 insertions(+), 13 deletions(-)
create mode 100644 res/layout/cstor_name_credential_dialog_view.xml
create mode 100644 res/layout/cstor_set_password_dialog_view.xml
create mode 100644 res/layout/cstor_unlock_dialog_view.xml
diff --git a/res/layout/cstor_name_credential_dialog_view.xml b/res/layout/cstor_name_credential_dialog_view.xml
new file mode 100644
index 00000000000..e5ccb3675db
--- /dev/null
+++ b/res/layout/cstor_name_credential_dialog_view.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/cstor_set_password_dialog_view.xml b/res/layout/cstor_set_password_dialog_view.xml
new file mode 100644
index 00000000000..eda317ab538
--- /dev/null
+++ b/res/layout/cstor_set_password_dialog_view.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/cstor_unlock_dialog_view.xml b/res/layout/cstor_unlock_dialog_view.xml
new file mode 100644
index 00000000000..66a21754d4a
--- /dev/null
+++ b/res/layout/cstor_unlock_dialog_view.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/values/colors.xml b/res/values/colors.xml
index a170c9214f3..193388c8aea 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -16,5 +16,6 @@
#000
+ #F00
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fb806c9349c..07863b53a60 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1944,11 +1944,13 @@ found in the list of installed applications.
Use secure credentials
Allow applications to access secure certificates and other credentials
+
+ Enter password
- Set storage password
+ Set password
- Set or change the secure credential storage password
+ Set or change the credential storage password
Set password
@@ -1956,7 +1958,16 @@ found in the list of installed applications.
Clear storage
Clear credential storage of all contents and reset its password
- Are you sure you want to delete all certificates and other stored credentials and reset the password?
+ Are you sure you want to delete all credentials and reset the credential storage password?
+
+
+ Name the certificate
+
+ Certificate name:
+
+ Certificate details:
+ The name can contain only letters and numbers.
+
Current password:
@@ -1965,9 +1976,21 @@ found in the list of installed applications.
Confirm new password:
- You must set a password for credential storage before you can store secure certificates and other credentials in it.
- Passwords do not match.
- Please fill up all the fields.
+ You must set a password for the credential storage.
+ Please enter the correct password.
+ Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.
+ Please enter the correct password. You have %d more tries to enter the correct password before the credential storage is erased.
+ Passwords do not match.
+ You must enter and confirm a password.
+ Please enter the password.
+ Please enter the password again. The password must have at least 8 characters and must not contain spaces.
+ Please enter a name.
+ Please enter a name that contains only letters and numbers.
+
+
+ Credential storage is enabled.
+
+ %s is added.
Emergency tone
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index e0d0cc1233c..b5efaada3a6 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -30,18 +30,26 @@ import android.database.Cursor;
import android.location.LocationManager;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.provider.Settings;
+import android.security.Keystore;
+import android.text.Html;
+import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
+import android.view.View;
import android.widget.TextView;
+import android.widget.Toast;
import com.android.internal.widget.LockPatternUtils;
import android.telephony.TelephonyManager;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Observable;
import java.util.Observer;
@@ -52,7 +60,7 @@ public class SecuritySettings extends PreferenceActivity implements
DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
// Lock Settings
-
+
private static final String KEY_LOCK_ENABLED = "lockenabled";
private static final String KEY_VISIBLE_PATTERN = "visiblepattern";
private static final String KEY_TACTILE_FEEDBACK_ENABLED = "tactilefeedback";
@@ -65,12 +73,31 @@ public class SecuritySettings extends PreferenceActivity implements
private Preference mChoosePattern;
private CheckBoxPreference mShowPassword;
-
+
// 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";
+ // Credential storage
+ private static final String ACTION_ADD_CREDENTIAL =
+ "android.security.ADD_CREDENTIAL";
+ private static final String ACTION_UNLOCK_CREDENTIAL_STORAGE =
+ "android.security.UNLOCK_CREDENTIAL_STORAGE";
+ private static final String KEY_CSTOR_TYPE_NAME = "typeName";
+ private static final String KEY_CSTOR_ITEM = "item";
+ private static final String KEY_CSTOR_NAMESPACE = "namespace";
+ private static final String KEY_CSTOR_DESCRIPTION = "description";
+ private static final int CSTOR_MIN_PASSWORD_LENGTH = 8;
+
+ private static final int CSTOR_INIT_DIALOG = 1;
+ private static final int CSTOR_CHANGE_PASSWORD_DIALOG = 2;
+ private static final int CSTOR_UNLOCK_DIALOG = 3;
+ private static final int CSTOR_RESET_DIALOG = 4;
+ private static final int CSTOR_NAME_CREDENTIAL_DIALOG = 5;
+
+ private CstorHelper mCstorHelper = new CstorHelper();
+
// Vendor specific
private static final String GSETTINGS_PROVIDER = "com.google.android.providers.settings";
private static final String USE_LOCATION = "use_location";
@@ -128,6 +155,8 @@ public class SecuritySettings extends PreferenceActivity implements
if (getIntent().getBooleanExtra("SHOW_USE_LOCATION", false) && !doneUseLocation) {
showUseLocationDialog(true);
}
+
+ mCstorHelper.handleCstorIntents(getIntent());
}
private PreferenceScreen createPreferenceHierarchy() {
@@ -165,7 +194,7 @@ public class SecuritySettings extends PreferenceActivity implements
mChoosePattern = getPreferenceManager().createPreferenceScreen(this);
mChoosePattern.setIntent(intent);
inlinePrefCat.addPreference(mChoosePattern);
-
+
int activePhoneType = TelephonyManager.getDefault().getPhoneType();
// do not display SIM lock for CDMA phone
@@ -178,7 +207,7 @@ public class SecuritySettings extends PreferenceActivity implements
intent = new Intent();
intent.setClassName("com.android.settings", "com.android.settings.IccLockSettings");
simLockPreferences.setIntent(intent);
-
+
PreferenceCategory simLockCat = new PreferenceCategory(this);
simLockCat.setTitle(R.string.sim_lock_settings_title);
root.addPreference(simLockCat);
@@ -189,14 +218,22 @@ public class SecuritySettings extends PreferenceActivity implements
PreferenceCategory passwordsCat = new PreferenceCategory(this);
passwordsCat.setTitle(R.string.security_passwords_title);
root.addPreference(passwordsCat);
-
+
CheckBoxPreference showPassword = mShowPassword = new CheckBoxPreference(this);
showPassword.setKey("show_password");
showPassword.setTitle(R.string.show_password);
showPassword.setSummary(R.string.show_password_summary);
showPassword.setPersistent(false);
passwordsCat.addPreference(showPassword);
-
+
+ // Credential storage
+ PreferenceCategory credStoreCat = new PreferenceCategory(this);
+ credStoreCat.setTitle(R.string.cstor_settings_category);
+ root.addPreference(credStoreCat);
+ credStoreCat.addPreference(mCstorHelper.createAccessCheckBox());
+ credStoreCat.addPreference(mCstorHelper.createSetPasswordPreference());
+ credStoreCat.addPreference(mCstorHelper.createResetPreference());
+
return root;
}
@@ -217,7 +254,7 @@ public class SecuritySettings extends PreferenceActivity implements
R.string.lockpattern_settings_change_lock_pattern :
R.string.lockpattern_settings_choose_lock_pattern;
mChoosePattern.setTitle(chooseStringRes);
-
+
mShowPassword
.setChecked(Settings.System.getInt(getContentResolver(),
Settings.System.TEXT_SHOW_PASSWORD, 1) != 0);
@@ -383,4 +420,491 @@ public class SecuritySettings extends PreferenceActivity implements
mUseLocation.setChecked(false);
}
}
+
+ @Override
+ protected Dialog onCreateDialog (int id) {
+ switch (id) {
+ case CSTOR_INIT_DIALOG:
+ case CSTOR_CHANGE_PASSWORD_DIALOG:
+ return mCstorHelper.createSetPasswordDialog(id);
+
+ case CSTOR_UNLOCK_DIALOG:
+ return mCstorHelper.createUnlockDialog();
+
+ case CSTOR_RESET_DIALOG:
+ return mCstorHelper.createResetDialog();
+
+ case CSTOR_NAME_CREDENTIAL_DIALOG:
+ return mCstorHelper.createNameCredentialDialog();
+
+ default:
+ return null;
+ }
+ }
+
+ private class CstorHelper implements
+ DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+ private Keystore mKeystore = Keystore.getInstance();
+ private View mView;
+ private int mDialogId;
+ private boolean mConfirm = true;
+
+ private CheckBoxPreference mAccessCheckBox;
+ private Preference mResetButton;
+
+ private Intent mSpecialIntent;
+ private CstorAddCredentialHelper mCstorAddCredentialHelper;
+
+ void handleCstorIntents(Intent intent) {
+ if (intent == null) return;
+ String action = intent.getAction();
+
+ if (ACTION_ADD_CREDENTIAL.equals(action)) {
+ mCstorAddCredentialHelper = new CstorAddCredentialHelper(intent);
+ showDialog(CSTOR_NAME_CREDENTIAL_DIALOG);
+ } else if (ACTION_UNLOCK_CREDENTIAL_STORAGE.equals(action)) {
+ mSpecialIntent = intent;
+ showDialog(mCstorHelper.isCstorInitialized()
+ ? CSTOR_UNLOCK_DIALOG
+ : CSTOR_INIT_DIALOG);
+ }
+ }
+
+ private boolean isCstorUnlocked() {
+ return (mKeystore.getState() == Keystore.UNLOCKED);
+ }
+
+ private boolean isCstorInitialized() {
+ return (mKeystore.getState() != Keystore.UNINITIALIZED);
+ }
+
+ private void lockCstor() {
+ mKeystore.lock();
+ mAccessCheckBox.setChecked(false);
+ }
+
+ private int unlockCstor(String passwd) {
+ int ret = mKeystore.unlock(passwd);
+ if (ret == -1) resetCstor();
+ if (ret == 0) {
+ Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled,
+ Toast.LENGTH_SHORT).show();
+ }
+ return ret;
+ }
+
+ private int changeCstorPassword(String oldPasswd, String newPasswd) {
+ int ret = mKeystore.changePassword(oldPasswd, newPasswd);
+ if (ret == -1) resetCstor();
+ return ret;
+ }
+
+ private void initCstor(String passwd) {
+ mKeystore.setPassword(passwd);
+ enablePreferences(true);
+ mAccessCheckBox.setChecked(true);
+ Toast.makeText(SecuritySettings.this, R.string.cstor_is_enabled,
+ Toast.LENGTH_SHORT).show();
+ }
+
+ private void resetCstor() {
+ mKeystore.reset();
+ enablePreferences(false);
+ mAccessCheckBox.setChecked(false);
+ }
+
+ private void addCredential() {
+ String message = String.format(getString(R.string.cstor_is_added),
+ mCstorAddCredentialHelper.getName());
+ Toast.makeText(SecuritySettings.this, message, Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_NEGATIVE) {
+ if (mCstorAddCredentialHelper != null) finish();
+ return;
+ }
+
+ switch (mDialogId) {
+ case CSTOR_INIT_DIALOG:
+ case CSTOR_CHANGE_PASSWORD_DIALOG:
+ mConfirm = checkPasswords((Dialog) dialog);
+ break;
+
+ case CSTOR_UNLOCK_DIALOG:
+ mConfirm = checkUnlockPassword((Dialog) dialog);
+ break;
+
+ case CSTOR_RESET_DIALOG:
+ resetCstor();
+ break;
+
+ case CSTOR_NAME_CREDENTIAL_DIALOG:
+ mConfirm = checkAddCredential();
+ break;
+ }
+ }
+
+ public void onDismiss(DialogInterface dialog) {
+ if (!mConfirm) {
+ mConfirm = true;
+ showDialog(mDialogId);
+ } else {
+ removeDialog(mDialogId);
+
+ if (mCstorAddCredentialHelper != null) {
+ if (!isCstorInitialized()) {
+ showDialog(CSTOR_INIT_DIALOG);
+ } else if (!isCstorUnlocked()) {
+ showDialog(CSTOR_UNLOCK_DIALOG);
+ } else {
+ addCredential();
+ finish();
+ }
+ } else if (mSpecialIntent != null) {
+ finish();
+ }
+ }
+ }
+
+ private void showResetWarning(int count) {
+ TextView v = showError(count <= 3
+ ? R.string.cstor_password_error_reset_warning
+ : R.string.cstor_password_error);
+ if (count <= 3) {
+ if (count == 1) {
+ v.setText(getString(
+ R.string.cstor_password_error_reset_warning));
+ } else {
+ String format = getString(
+ R.string.cstor_password_error_reset_warning_plural);
+ v.setText(String.format(format, count));
+ }
+ }
+ }
+
+ private boolean checkAddCredential() {
+ hideError();
+
+ String name = getText(R.id.cstor_credential_name);
+ if (TextUtils.isEmpty(name)) {
+ showError(R.string.cstor_name_empty_error);
+ return false;
+ }
+
+ for (int i = 0, len = name.length(); i < len; i++) {
+ if (!Character.isLetterOrDigit(name.charAt(i))) {
+ showError(R.string.cstor_name_char_error);
+ return false;
+ }
+ }
+
+ mCstorAddCredentialHelper.setName(name);
+ return true;
+ }
+
+ // returns true if the password is long enough and does not contain
+ // characters that we don't like
+ private boolean verifyPassword(String passwd) {
+ if (passwd == null) {
+ showError(R.string.cstor_passwords_empty_error);
+ return false;
+ } else if ((passwd.length() < CSTOR_MIN_PASSWORD_LENGTH)
+ || passwd.contains(" ")) {
+ showError(R.string.cstor_password_verification_error);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ // returns true if the password is ok
+ private boolean checkUnlockPassword(Dialog d) {
+ hideError();
+
+ String passwd = getText(R.id.cstor_password);
+ if (TextUtils.isEmpty(passwd)) {
+ showError(R.string.cstor_password_empty_error);
+ return false;
+ }
+
+ int count = unlockCstor(passwd);
+ if (count > 0) {
+ showResetWarning(count);
+ return false;
+ } else {
+ // done or reset
+ return true;
+ }
+ }
+
+ // returns true if the passwords are ok
+ private boolean checkPasswords(Dialog d) {
+ hideError();
+
+ String oldPasswd = getText(R.id.cstor_old_password);
+ String newPasswd = getText(R.id.cstor_new_password);
+ String confirmPasswd = getText(R.id.cstor_confirm_password);
+
+ if ((mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG)
+ && TextUtils.isEmpty(oldPasswd)) {
+ showError(R.string.cstor_password_empty_error);
+ return false;
+ }
+
+ if (TextUtils.isEmpty(newPasswd)
+ && TextUtils.isEmpty(confirmPasswd)) {
+ showError(R.string.cstor_passwords_empty_error);
+ return false;
+ }
+
+ if (!verifyPassword(newPasswd)) {
+ return false;
+ } else if (!newPasswd.equals(confirmPasswd)) {
+ showError(R.string.cstor_passwords_error);
+ return false;
+ }
+
+ if (mDialogId == CSTOR_CHANGE_PASSWORD_DIALOG) {
+ int count = changeCstorPassword(oldPasswd, newPasswd);
+ if (count > 0) {
+ showResetWarning(count);
+ return false;
+ } else {
+ // done or reset
+ return true;
+ }
+ } else {
+ initCstor(newPasswd);
+ return true;
+ }
+ }
+
+ private TextView showError(int messageId) {
+ TextView v = (TextView) mView.findViewById(R.id.cstor_error);
+ v.setText(messageId);
+ if (v != null) v.setVisibility(View.VISIBLE);
+ return v;
+ }
+
+ private void hideError() {
+ View v = mView.findViewById(R.id.cstor_error);
+ if (v != null) v.setVisibility(View.GONE);
+ }
+
+ private String getText(int viewId) {
+ return ((TextView) mView.findViewById(viewId)).getText().toString();
+ }
+
+ private void setText(int viewId, String text) {
+ TextView v = (TextView) mView.findViewById(viewId);
+ if (v != null) v.setText(text);
+ }
+
+ private void enablePreferences(boolean enabled) {
+ mAccessCheckBox.setEnabled(enabled);
+ mResetButton.setEnabled(enabled);
+ }
+
+ private Preference createAccessCheckBox() {
+ CheckBoxPreference pref = new CheckBoxPreference(
+ SecuritySettings.this);
+ pref.setTitle(R.string.cstor_access_title);
+ pref.setSummary(R.string.cstor_access_summary);
+ pref.setChecked(isCstorUnlocked());
+ pref.setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
+ public boolean onPreferenceChange(
+ Preference pref, Object value) {
+ if (((Boolean) value)) {
+ showDialog(isCstorInitialized()
+ ? CSTOR_UNLOCK_DIALOG
+ : CSTOR_INIT_DIALOG);
+ } else {
+ lockCstor();
+ }
+ return true;
+ }
+ });
+ pref.setEnabled(isCstorInitialized());
+ mAccessCheckBox = pref;
+ return pref;
+ }
+
+ private Preference createSetPasswordPreference() {
+ Preference pref = new Preference(SecuritySettings.this);
+ pref.setTitle(R.string.cstor_set_passwd_title);
+ pref.setSummary(R.string.cstor_set_passwd_summary);
+ pref.setOnPreferenceClickListener(
+ new Preference.OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference pref) {
+ showDialog(isCstorInitialized()
+ ? CSTOR_CHANGE_PASSWORD_DIALOG
+ : CSTOR_INIT_DIALOG);
+ return true;
+ }
+ });
+ return pref;
+ }
+
+ private Preference createResetPreference() {
+ Preference pref = new Preference(SecuritySettings.this);
+ pref.setTitle(R.string.cstor_reset_title);
+ pref.setSummary(R.string.cstor_reset_summary);
+ pref.setOnPreferenceClickListener(
+ new Preference.OnPreferenceClickListener() {
+ public boolean onPreferenceClick(Preference pref) {
+ showDialog(CSTOR_RESET_DIALOG);
+ return true;
+ }
+ });
+ pref.setEnabled(isCstorInitialized());
+ mResetButton = pref;
+ return pref;
+ }
+
+ private Dialog createUnlockDialog() {
+ mDialogId = CSTOR_UNLOCK_DIALOG;
+ mView = View.inflate(SecuritySettings.this,
+ R.layout.cstor_unlock_dialog_view, null);
+ hideError();
+
+ Dialog d = new AlertDialog.Builder(SecuritySettings.this)
+ .setView(mView)
+ .setTitle(R.string.cstor_access_dialog_title)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .setCancelable(false)
+ .create();
+ d.setOnDismissListener(this);
+ return d;
+ }
+
+ private Dialog createSetPasswordDialog(int id) {
+ mDialogId = id;
+ mView = View.inflate(SecuritySettings.this,
+ R.layout.cstor_set_password_dialog_view, null);
+ hideError();
+
+ switch (id) {
+ case CSTOR_INIT_DIALOG:
+ mView.findViewById(R.id.cstor_old_password_block)
+ .setVisibility(View.GONE);
+ break;
+
+ case CSTOR_CHANGE_PASSWORD_DIALOG:
+ mView.findViewById(R.id.cstor_first_time_hint)
+ .setVisibility(View.GONE);
+ break;
+
+ default:
+ throw new RuntimeException(
+ "Unknown dialog id: " + mDialogId);
+ }
+
+ Dialog d = new AlertDialog.Builder(SecuritySettings.this)
+ .setView(mView)
+ .setTitle(R.string.cstor_set_passwd_dialog_title)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .setCancelable(false)
+ .create();
+ d.setOnDismissListener(this);
+ return d;
+ }
+
+ private Dialog createResetDialog() {
+ mDialogId = CSTOR_RESET_DIALOG;
+ return new AlertDialog.Builder(SecuritySettings.this)
+ .setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
+ .setMessage(R.string.cstor_reset_hint)
+ .setPositiveButton(getString(android.R.string.ok), this)
+ .setNegativeButton(getString(android.R.string.cancel), this)
+ .create();
+ }
+
+ private Dialog createNameCredentialDialog() {
+ mDialogId = CSTOR_NAME_CREDENTIAL_DIALOG;
+ mView = View.inflate(SecuritySettings.this,
+ R.layout.cstor_name_credential_dialog_view, null);
+ hideError();
+
+ setText(R.id.cstor_credential_name_title,
+ getString(R.string.cstor_credential_name));
+ setText(R.id.cstor_credential_info_title,
+ getString(R.string.cstor_credential_info));
+ setText(R.id.cstor_credential_info,
+ mCstorAddCredentialHelper.getDescription().toString());
+
+ Dialog d = new AlertDialog.Builder(SecuritySettings.this)
+ .setView(mView)
+ .setTitle(R.string.cstor_name_credential_dialog_title)
+ .setPositiveButton(android.R.string.ok, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .setCancelable(false)
+ .create();
+ d.setOnDismissListener(this);
+ return d;
+ }
+ }
+
+ private class CstorAddCredentialHelper {
+ private String mTypeName;
+ private List mItemList;
+ private List mNamespaceList;
+ private String mDescription;
+ private String mName;
+
+ CstorAddCredentialHelper(Intent intent) {
+ parse(intent);
+ }
+
+ String getTypeName() {
+ return mTypeName;
+ }
+
+ byte[] getItem(int i) {
+ return mItemList.get(i);
+ }
+
+ String getNamespace(int i) {
+ return mNamespaceList.get(i);
+ }
+
+ CharSequence getDescription() {
+ return Html.fromHtml(mDescription);
+ }
+
+ void setName(String name) {
+ mName = name;
+ }
+
+ String getName() {
+ return mName;
+ }
+
+ private void parse(Intent intent) {
+ mTypeName = intent.getStringExtra(KEY_CSTOR_TYPE_NAME);
+ mItemList = new ArrayList();
+ mNamespaceList = new ArrayList();
+ for (int i = 0; ; i++) {
+ byte[] blob = intent.getByteArrayExtra(KEY_CSTOR_ITEM + i);
+ if (blob == null) break;
+ mItemList.add(blob);
+ mNamespaceList.add(intent.getStringExtra(
+ KEY_CSTOR_NAMESPACE + i));
+ }
+
+ // build description string
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; ; i++) {
+ String s = intent.getStringExtra(KEY_CSTOR_DESCRIPTION + i);
+ if (s == null) break;
+ sb.append(s).append("
");
+ }
+ mDescription = sb.toString();
+ }
+ }
}
diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java
index 1603998fafa..bbbe9b92a5b 100644
--- a/src/com/android/settings/vpn/VpnSettings.java
+++ b/src/com/android/settings/vpn/VpnSettings.java
@@ -407,6 +407,7 @@ public class VpnSettings extends PreferenceActivity implements
};
new AlertDialog.Builder(this)
.setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.vpn_confirm_profile_deletion)
.setPositiveButton(android.R.string.ok, onClickListener)
.setNegativeButton(R.string.vpn_no_button, onClickListener)
@@ -539,6 +540,7 @@ public class VpnSettings extends PreferenceActivity implements
private void showReconnectDialog(final VpnProfile p) {
new AlertDialog.Builder(this)
.setTitle(android.R.string.dialog_alert_title)
+ .setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.vpn_confirm_reconnect)
.setPositiveButton(R.string.vpn_yes_button,
new DialogInterface.OnClickListener() {
From 6a0544be5cf7ed8b19628f292e4045e1f3f7cb2f Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Sat, 4 Jul 2009 00:39:58 +0800
Subject: [PATCH 116/126] Fix strings.
* Changes
+ "Disconnect from network"
+ "Remember username"
+ "Unable to connect to the network"
---
res/values/strings.xml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 07863b53a60..13e154bfe62 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1826,7 +1826,7 @@ found in the list of installed applications.
password
- Remember me
+ Remember username
Connect
Yes
@@ -1838,7 +1838,7 @@ found in the list of installed applications.
Cancel
Revert
Connect to network
- Disconnect network
+ Disconnect from network
Edit network
Delete network
@@ -1849,7 +1849,7 @@ found in the list of installed applications.
Are you sure you want to delete this VPN?
Are you sure you don\'t want to create this profile?
Are you sure you want to discard the changes made to this profile?
- The previous connection attempt failed. Do you want to try again?
+ Unable to connect to the network. Do you want to try again?
Add VPN
From d40b9c5dff4b8866f188ba8166cba4fb657fafb2 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Sat, 4 Jul 2009 10:16:07 +0800
Subject: [PATCH 117/126] Add UNLOCK_CREDENTIAL_STORAGE and ADD_CREDENTIAL
Add UNLOCK_CREDENTIAL_STORAGE and ADD_CREDENTIAL intents to manifest.
---
AndroidManifest.xml | 2 ++
1 file changed, 2 insertions(+)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0bf41e8c11a..2092321a279 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -276,6 +276,8 @@
+
+
From 4e45d392ada4e84fbeed06874caebfd3c7759073 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Sun, 5 Jul 2009 02:45:26 +0800
Subject: [PATCH 118/126] Add certificate to keystore for the ADD intent
---
res/values/strings.xml | 1 +
.../android/settings/SecuritySettings.java | 27 +++++++++++--------
2 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 13e154bfe62..64cc5003ae3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1991,6 +1991,7 @@ found in the list of installed applications.
Credential storage is enabled.
%s is added.
+ Failed to add %s.
Emergency tone
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index b5efaada3a6..4e77d6b3c14 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -80,9 +80,9 @@ public class SecuritySettings extends PreferenceActivity implements
private static final String LOCATION_GPS = "location_gps";
// Credential storage
- private static final String ACTION_ADD_CREDENTIAL =
+ public static final String ACTION_ADD_CREDENTIAL =
"android.security.ADD_CREDENTIAL";
- private static final String ACTION_UNLOCK_CREDENTIAL_STORAGE =
+ public static final String ACTION_UNLOCK_CREDENTIAL_STORAGE =
"android.security.UNLOCK_CREDENTIAL_STORAGE";
private static final String KEY_CSTOR_TYPE_NAME = "typeName";
private static final String KEY_CSTOR_ITEM = "item";
@@ -514,7 +514,10 @@ public class SecuritySettings extends PreferenceActivity implements
}
private void addCredential() {
- String message = String.format(getString(R.string.cstor_is_added),
+ String formatString = mCstorAddCredentialHelper.saveToStorage() < 0
+ ? getString(R.string.cstor_add_error)
+ : getString(R.string.cstor_is_added);
+ String message = String.format(formatString,
mCstorAddCredentialHelper.getName());
Toast.makeText(SecuritySettings.this, message, Toast.LENGTH_SHORT)
.show();
@@ -865,14 +868,6 @@ public class SecuritySettings extends PreferenceActivity implements
return mTypeName;
}
- byte[] getItem(int i) {
- return mItemList.get(i);
- }
-
- String getNamespace(int i) {
- return mNamespaceList.get(i);
- }
-
CharSequence getDescription() {
return Html.fromHtml(mDescription);
}
@@ -885,6 +880,16 @@ public class SecuritySettings extends PreferenceActivity implements
return mName;
}
+ int saveToStorage() {
+ Keystore ks = Keystore.getInstance();
+ for (int i = 0, count = mItemList.size(); i < count; i++) {
+ byte[] blob = mItemList.get(i);
+ int ret = ks.put(mNamespaceList.get(i), mName, new String(blob));
+ if (ret < 0) return ret;
+ }
+ return 0;
+ }
+
private void parse(Intent intent) {
mTypeName = intent.getStringExtra(KEY_CSTOR_TYPE_NAME);
mItemList = new ArrayList();
From eb7836f11ec4e9753db7c6ecd9414e153bb7bdbe Mon Sep 17 00:00:00 2001
From: Chung-yih Wang
Date: Mon, 6 Jul 2009 17:03:53 +0800
Subject: [PATCH 119/126] Apply the new keystore and certtool library in Wifi
setting.
1. Certificate related APIs were moved to CertTool. Therefore,
we have to migrate to CertTool instead.
2. Unlock the keystore if it is not unlocked yet(send the intent
out to credential storage) for EAP access points.
3. Add Password field for WPA_EAP and IEEE8021X(this is for
phase 2 auth.)
---
res/layout/wifi_ap_configure.xml | 46 +++---
.../settings/wifi/AccessPointDialog.java | 154 +++++++++---------
.../settings/wifi/AccessPointState.java | 22 ++-
.../android/settings/wifi/WifiSettings.java | 10 +-
4 files changed, 123 insertions(+), 109 deletions(-)
diff --git a/res/layout/wifi_ap_configure.xml b/res/layout/wifi_ap_configure.xml
index e3ddf35bc6b..f8eb39a62bd 100644
--- a/res/layout/wifi_ap_configure.xml
+++ b/res/layout/wifi_ap_configure.xml
@@ -66,7 +66,7 @@
-
-
-
-
+
+
+
+
diff --git a/src/com/android/settings/wifi/AccessPointDialog.java b/src/com/android/settings/wifi/AccessPointDialog.java
index 43081a53c28..bf2007a9a5a 100644
--- a/src/com/android/settings/wifi/AccessPointDialog.java
+++ b/src/com/android/settings/wifi/AccessPointDialog.java
@@ -17,11 +17,14 @@
package com.android.settings.wifi;
import com.android.settings.R;
+import com.android.settings.SecuritySettings;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.res.Resources;
+import android.security.CertTool;
import android.security.Keystore;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
@@ -129,13 +132,13 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
private TextView mSecurityText;
private Spinner mSecuritySpinner;
private Spinner mWepTypeSpinner;
- private Keystore mKeystore;
+ private CertTool mCertTool;
public AccessPointDialog(Context context, WifiLayer wifiLayer) {
super(context);
mWifiLayer = wifiLayer;
- mKeystore = Keystore.getInstance();
+ mCertTool = CertTool.getInstance();
}
@Override
@@ -240,7 +243,7 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
setEnterpriseFieldsVisible(false);
} else if (mMode == MODE_INFO) {
- if (isEnterprise() && !mState.configured) {
+ if (mState.isEnterprise() && !mState.configured) {
setLayout(R.layout.wifi_ap_configure);
defaultPasswordVisibility = false;
setEnterpriseFieldsVisible(true);
@@ -287,16 +290,6 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
setButtons(positiveButtonResId, negativeButtonResId, neutralButtonResId);
}
- private boolean isEnterprise() {
-
- if(AccessPointState.WPA_EAP.equals(mState.security) ||
- AccessPointState.IEEE8021X.equals(mState.security)) {
- return true;
- } else {
- return false;
- }
- }
-
/** Called when we need to set our member variables to point to the views. */
private void onReferenceViews(View view) {
mPasswordText = (TextView) view.findViewById(R.id.password_text);
@@ -322,7 +315,8 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
mTable = (ViewGroup) view.findViewById(R.id.table);
}
/* for enterprise one */
- if (mMode == MODE_CONFIGURE || (isEnterprise() && !mState.configured)) {
+ if (mMode == MODE_CONFIGURE ||
+ (mState.isEnterprise() && !mState.configured)) {
setEnterpriseFields(view);
mEapSpinner.setSelection(getSelectionIndex(
R.array.wifi_eap_entries, mState.getEap()));
@@ -336,15 +330,14 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
}
private String[] getAllCaCertificateKeys() {
- return appendEmptyInSelection(mKeystore.getAllCaCertificateKeys());
+ return appendEmptyInSelection(mCertTool.getAllCaCertificateKeys());
}
private String[] getAllUserCertificateKeys() {
- return appendEmptyInSelection(mKeystore.getAllUserCertificateKeys());
+ return appendEmptyInSelection(mCertTool.getAllUserCertificateKeys());
}
private String[] appendEmptyInSelection(String[] keys) {
- if (keys.length == 0) return keys;
String[] selections = new String[keys.length + 1];
System.arraycopy(keys, 0, selections, 0, keys.length);
selections[keys.length] = NOT_APPLICABLE;
@@ -436,8 +429,9 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
if (!TextUtils.isEmpty(ssid)) {
mSsidEdit.setText(ssid);
}
-
- mPasswordEdit.setHint(R.string.wifi_password_unchanged);
+ if (mState.configured) {
+ mPasswordEdit.setHint(R.string.wifi_password_unchanged);
+ }
}
updatePasswordCaption(mState.security);
@@ -505,15 +499,15 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
Log.w(TAG, "Assuming connecting to a new network.");
}
- if (isEnterprise()) {
+ if (mState.isEnterprise()) {
if(!mState.configured) {
updateEnterpriseFields(
AccessPointState.WPA_EAP.equals(mState.security) ?
SECURITY_WPA_EAP : SECURITY_IEEE8021X);
}
- } else {
- updatePasswordField();
}
+ updatePasswordField();
+
mWifiLayer.connectToNetwork(mState);
}
@@ -558,58 +552,53 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
mState.setSsid(ssid);
int securityType = getSecurityTypeFromSpinner();
-
- if (!TextUtils.isEmpty(password)) {
- switch (securityType) {
-
- case SECURITY_WPA_PERSONAL: {
- mState.setSecurity(AccessPointState.WPA);
- mState.setPassword(password);
- break;
- }
-
- case SECURITY_WPA2_PERSONAL: {
- mState.setSecurity(AccessPointState.WPA2);
- mState.setPassword(password);
- break;
- }
-
- case SECURITY_AUTO: {
- mState.setPassword(password);
- break;
- }
-
- case SECURITY_WEP: {
- mState.setSecurity(AccessPointState.WEP);
- mState.setPassword(password,
- WEP_TYPE_VALUES[mWepTypeSpinner.getSelectedItemPosition()]);
- break;
- }
-
- }
- } else {
- switch (securityType) {
- case SECURITY_WPA_EAP:
- mState.setSecurity(AccessPointState.WPA_EAP);
- break;
- case SECURITY_IEEE8021X:
- mState.setSecurity(AccessPointState.IEEE8021X);
- break;
- default:
- mState.setSecurity(AccessPointState.OPEN);
- break;
- }
- if (isEnterprise() && !mState.configured) {
- updateEnterpriseFields(
- AccessPointState.WPA_EAP.equals(mState.security) ?
- SECURITY_WPA_EAP : SECURITY_IEEE8021X);
- }
+
+ if (!TextUtils.isEmpty(password) && (securityType != SECURITY_WEP)) {
+ mState.setPassword(password);
}
-
- if (securityType == SECURITY_NONE) {
- mState.setSecurity(AccessPointState.OPEN);
+
+ switch (securityType) {
+ case SECURITY_WPA_PERSONAL: {
+ mState.setSecurity(AccessPointState.WPA);
+ break;
+ }
+
+ case SECURITY_WPA2_PERSONAL: {
+ mState.setSecurity(AccessPointState.WPA2);
+ break;
+ }
+
+ case SECURITY_AUTO: {
+ break;
+ }
+
+ case SECURITY_WEP: {
+ mState.setSecurity(AccessPointState.WEP);
+ mState.setPassword(password, WEP_TYPE_VALUES[
+ mWepTypeSpinner.getSelectedItemPosition()]);
+ break;
+ }
+
+ case SECURITY_WPA_EAP:
+ mState.setSecurity(AccessPointState.WPA_EAP);
+ break;
+
+ case SECURITY_IEEE8021X:
+ mState.setSecurity(AccessPointState.IEEE8021X);
+ break;
+
+ case SECURITY_NONE:
+ default:
+ mState.setSecurity(AccessPointState.OPEN);
+ break;
}
-
+
+ if (mState.isEnterprise() && !mState.configured) {
+ updateEnterpriseFields(
+ AccessPointState.WPA_EAP.equals(mState.security) ?
+ SECURITY_WPA_EAP : SECURITY_IEEE8021X);
+ }
+
if (!mWifiLayer.saveNetwork(mState)) {
return;
}
@@ -649,13 +638,13 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
Spinner spinner = mClientCertSpinner;
int index = spinner.getSelectedItemPosition();
if (index != (spinner.getCount() - 1)) {
- String key = getAllUserCertificateKeys()[index];
- value = mKeystore.getUserCertificate(key);
+ String key = (String)spinner.getSelectedItem();
+ value = mCertTool.getUserCertificate(key);
if (!TextUtils.isEmpty(value)) {
mState.setEnterpriseField(AccessPointState.CLIENT_CERT,
value);
}
- value = mKeystore.getUserPrivateKey(key);
+ value = mCertTool.getUserPrivateKey(key);
if (!TextUtils.isEmpty(value)) {
mState.setEnterpriseField(AccessPointState.PRIVATE_KEY,
value);
@@ -664,8 +653,8 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
spinner = mCaCertSpinner;
index = spinner.getSelectedItemPosition();
if (index != (spinner.getCount() - 1)) {
- String key = getAllCaCertificateKeys()[index];
- value = mKeystore.getCaCertificate(key);
+ String key = (String)spinner.getSelectedItem();
+ value = mCertTool.getCaCertificate(key);
if (!TextUtils.isEmpty(value)) {
mState.setEnterpriseField(AccessPointState.CA_CERT,
value);
@@ -738,7 +727,6 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
mEnterpriseView.setVisibility(visibility);
if (visible) {
setWepVisible(false);
- setGenericPasswordVisible(false);
}
if (mMode != MODE_CONFIGURE) {
mSsidText.setVisibility(View.GONE);
@@ -792,7 +780,17 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
}
case SECURITY_WPA_EAP:
case SECURITY_IEEE8021X: {
+ // Unlock the keystore if it is not unlocked yet.
+ if (Keystore.getInstance().getState() != Keystore.UNLOCKED) {
+ getContext().startActivity(new Intent(
+ SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE));
+ mSecuritySpinner.setSelection(0);
+ return;
+ }
setEnterpriseFieldsVisible(true);
+ setGenericPasswordVisible(true);
+ // Both WPA and WPA2 show the same caption, so either is ok
+ updatePasswordCaption(AccessPointState.WPA);
break;
}
}
diff --git a/src/com/android/settings/wifi/AccessPointState.java b/src/com/android/settings/wifi/AccessPointState.java
index 7ea2dc91bdf..8fb651bc012 100644
--- a/src/com/android/settings/wifi/AccessPointState.java
+++ b/src/com/android/settings/wifi/AccessPointState.java
@@ -276,7 +276,12 @@ public final class AccessPointState implements Comparable, Par
requestRefresh();
}
}
-
+
+ public boolean isEnterprise() {
+ return (WPA_EAP.equals(security) ||
+ AccessPointState.IEEE8021X.equals(security));
+ }
+
public void setSecurity(String security) {
if (TextUtils.isEmpty(this.security) || !this.security.equals(security)) {
this.security = security;
@@ -592,14 +597,17 @@ public final class AccessPointState implements Comparable, Par
} else if (security.equals(OPEN)) {
config.allowedKeyManagement.set(KeyMgmt.NONE);
- } else if (security.equals(WPA_EAP)) {
+ } else if (security.equals(WPA_EAP) || security.equals(IEEE8021X)) {
config.allowedGroupCiphers.set(GroupCipher.TKIP);
config.allowedGroupCiphers.set(GroupCipher.CCMP);
- config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
- } else if (security.equals(IEEE8021X)) {
- config.allowedGroupCiphers.set(GroupCipher.TKIP);
- config.allowedGroupCiphers.set(GroupCipher.CCMP);
- config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+ if (security.equals(WPA_EAP)) {
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ } else {
+ config.allowedKeyManagement.set(KeyMgmt.IEEE8021X);
+ }
+ if (!TextUtils.isEmpty(mPassword)) {
+ config.password = convertToQuotedString(mPassword);
+ }
}
}
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index d2683c0f44f..a0155343a20 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -18,6 +18,7 @@ package com.android.settings.wifi;
import com.android.settings.ProgressCategory;
import com.android.settings.R;
+import com.android.settings.SecuritySettings;
import android.app.Dialog;
import android.content.DialogInterface;
@@ -29,6 +30,7 @@ import android.preference.PreferenceActivity;
import android.preference.PreferenceScreen;
import android.preference.CheckBoxPreference;
import android.provider.Settings;
+import android.security.Keystore;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
@@ -259,7 +261,7 @@ public class WifiSettings extends PreferenceActivity implements WifiLayer.Callba
@Override
public boolean onContextItemSelected(MenuItem item) {
-
+
AccessPointState state = getStateFromMenuInfo(item.getMenuInfo());
if (state == null) {
return false;
@@ -352,6 +354,12 @@ public class WifiSettings extends PreferenceActivity implements WifiLayer.Callba
}
public void showAccessPointDialog(AccessPointState state, int mode) {
+ if (state.isEnterprise() &&
+ Keystore.getInstance().getState() != Keystore.UNLOCKED) {
+ startActivity(new Intent(
+ SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE));
+ return;
+ }
AccessPointDialog dialog = new AccessPointDialog(this, mWifiLayer);
dialog.setMode(mode);
dialog.setState(state);
From 0a59b500147cc038541f6f2897de7e28c15a12c1 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Mon, 6 Jul 2009 17:26:34 +0800
Subject: [PATCH 120/126] Integrate VPN with new keystore and misc fixes.
* Changes
+ Pass intent to keystore when needed and hooks to resume from it.
+ Generate random, unique ID for profile instead of base64 from its
name.
+ Add VPN to "Wirless controls" description.
+ Add credential storage to "Security & location" description.
+ More hints to set password and unlock dialogs in credential storage
settings for actions that come from other processes.
+ Sort VPN profiles according to the names.
+ Replace Keystore with CertTool in L2tpIpsecEditor
---
res/layout/cstor_unlock_dialog_view.xml | 7 +
res/values/strings.xml | 8 +-
.../android/settings/SecuritySettings.java | 33 ++-
src/com/android/settings/vpn/L2tpEditor.java | 6 -
.../android/settings/vpn/L2tpIpsecEditor.java | 6 +-
.../settings/vpn/L2tpIpsecPskEditor.java | 7 -
src/com/android/settings/vpn/Util.java | 6 -
src/com/android/settings/vpn/VpnEditor.java | 7 -
.../settings/vpn/VpnProfileEditor.java | 7 -
src/com/android/settings/vpn/VpnSettings.java | 189 ++++++++++++++++--
10 files changed, 216 insertions(+), 60 deletions(-)
diff --git a/res/layout/cstor_unlock_dialog_view.xml b/res/layout/cstor_unlock_dialog_view.xml
index 66a21754d4a..895306a39e7 100644
--- a/res/layout/cstor_unlock_dialog_view.xml
+++ b/res/layout/cstor_unlock_dialog_view.xml
@@ -24,6 +24,13 @@
android:layout_height="fill_parent"
android:padding="15dip">
+
+
Wireless controls
- Manage Wi-Fi, Bluetooth, airplane mode, & mobile networks
+ Manage Wi-Fi, Bluetooth, airplane mode, mobile networks, & VPNs
@@ -488,7 +488,7 @@
Security & location
- Set My Location, screen unlock, SIM card lock
+ Set My Location, screen unlock, SIM card lock, credential storage lock
Passwords
@@ -1946,6 +1946,8 @@ found in the list of installed applications.
Allow applications to access secure certificates and other credentials
Enter password
+
+ This action requires enabling the credential storage. Please enter the password to enable it.
Set password
@@ -1977,6 +1979,8 @@ found in the list of installed applications.
Confirm new password:
You must set a password for the credential storage.
+
+ This action requires the credential storage but the storage has not been activated before. To activiate it, you must set a password for the credential storage.
Please enter the correct password.
Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.
Please enter the correct password. You have %d more tries to enter the correct password before the credential storage is erased.
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 4e77d6b3c14..73578c738ac 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -577,8 +577,7 @@ public class SecuritySettings extends PreferenceActivity implements
: R.string.cstor_password_error);
if (count <= 3) {
if (count == 1) {
- v.setText(getString(
- R.string.cstor_password_error_reset_warning));
+ v.setText(R.string.cstor_password_error_reset_warning);
} else {
String format = getString(
R.string.cstor_password_error_reset_warning_plural);
@@ -691,11 +690,15 @@ public class SecuritySettings extends PreferenceActivity implements
return v;
}
- private void hideError() {
- View v = mView.findViewById(R.id.cstor_error);
+ private void hide(int viewId) {
+ View v = mView.findViewById(viewId);
if (v != null) v.setVisibility(View.GONE);
}
+ private void hideError() {
+ hide(R.id.cstor_error);
+ }
+
private String getText(int viewId) {
return ((TextView) mView.findViewById(viewId)).getText().toString();
}
@@ -705,6 +708,11 @@ public class SecuritySettings extends PreferenceActivity implements
if (v != null) v.setText(text);
}
+ private void setText(int viewId, int textId) {
+ TextView v = (TextView) mView.findViewById(viewId);
+ if (v != null) v.setText(textId);
+ }
+
private void enablePreferences(boolean enabled) {
mAccessCheckBox.setEnabled(enabled);
mResetButton.setEnabled(enabled);
@@ -773,6 +781,12 @@ public class SecuritySettings extends PreferenceActivity implements
R.layout.cstor_unlock_dialog_view, null);
hideError();
+ // show extra hint only when the action comes from outside
+ if ((mSpecialIntent == null)
+ && (mCstorAddCredentialHelper == null)) {
+ hide(R.id.cstor_access_dialog_hint_from_action);
+ }
+
Dialog d = new AlertDialog.Builder(SecuritySettings.this)
.setView(mView)
.setTitle(R.string.cstor_access_dialog_title)
@@ -790,6 +804,13 @@ public class SecuritySettings extends PreferenceActivity implements
R.layout.cstor_set_password_dialog_view, null);
hideError();
+ // show extra hint only when the action comes from outside
+ if ((mSpecialIntent != null)
+ || (mCstorAddCredentialHelper != null)) {
+ setText(R.id.cstor_first_time_hint,
+ R.string.cstor_first_time_hint_from_action);
+ }
+
switch (id) {
case CSTOR_INIT_DIALOG:
mView.findViewById(R.id.cstor_old_password_block)
@@ -835,9 +856,9 @@ public class SecuritySettings extends PreferenceActivity implements
hideError();
setText(R.id.cstor_credential_name_title,
- getString(R.string.cstor_credential_name));
+ R.string.cstor_credential_name);
setText(R.id.cstor_credential_info_title,
- getString(R.string.cstor_credential_info));
+ R.string.cstor_credential_info);
setText(R.id.cstor_credential_info,
mCstorAddCredentialHelper.getDescription().toString());
diff --git a/src/com/android/settings/vpn/L2tpEditor.java b/src/com/android/settings/vpn/L2tpEditor.java
index 88a1142a156..c518dec46a6 100644
--- a/src/com/android/settings/vpn/L2tpEditor.java
+++ b/src/com/android/settings/vpn/L2tpEditor.java
@@ -60,12 +60,6 @@ class L2tpEditor extends VpnProfileEditor {
: validate(mSecretString, R.string.vpn_l2tp_secret));
}
- @Override
- public void saveSecrets(String originalProfileName) {
- L2tpProfile profile = (L2tpProfile) getProfile();
- // TODO: fill up the implementation after keystore is available
- }
-
private Preference createSecretPreference(Context c) {
final L2tpProfile profile = (L2tpProfile) getProfile();
CheckBoxPreference secret = mSecret = new CheckBoxPreference(c);
diff --git a/src/com/android/settings/vpn/L2tpIpsecEditor.java b/src/com/android/settings/vpn/L2tpIpsecEditor.java
index e79760c8dd8..b6b244f7ee5 100644
--- a/src/com/android/settings/vpn/L2tpIpsecEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecEditor.java
@@ -24,7 +24,7 @@ import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceGroup;
-import android.security.Keystore;
+import android.security.CertTool;
import android.text.TextUtils;
/**
@@ -67,7 +67,7 @@ class L2tpIpsecEditor extends L2tpEditor {
mUserCertificate = createListPreference(c,
R.string.vpn_user_certificate_title,
mProfile.getUserCertificate(),
- Keystore.getInstance().getAllUserCertificateKeys(),
+ CertTool.getInstance().getAllUserCertificateKeys(),
new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(
Preference pref, Object newValue) {
@@ -86,7 +86,7 @@ class L2tpIpsecEditor extends L2tpEditor {
mCaCertificate = createListPreference(c,
R.string.vpn_ca_certificate_title,
mProfile.getCaCertificate(),
- Keystore.getInstance().getAllCaCertificateKeys(),
+ CertTool.getInstance().getAllCaCertificateKeys(),
new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(
Preference pref, Object newValue) {
diff --git a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
index 9c1d02c3903..fb67c987ffc 100644
--- a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
@@ -50,13 +50,6 @@ class L2tpIpsecPskEditor extends L2tpEditor {
: validate(mPresharedKey, R.string.vpn_ipsec_presharedkey));
}
- @Override
- public void saveSecrets(String originalProfileName) {
- L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
- profile.getPresharedKey();
- // TODO: fill up the implementation after keystore is available
- }
-
private Preference createPresharedKeyPreference(Context c) {
final L2tpIpsecPskProfile profile = (L2tpIpsecPskProfile) getProfile();
mPresharedKey = createSecretPreference(c,
diff --git a/src/com/android/settings/vpn/Util.java b/src/com/android/settings/vpn/Util.java
index e4316fd0831..a37049d2ca2 100644
--- a/src/com/android/settings/vpn/Util.java
+++ b/src/com/android/settings/vpn/Util.java
@@ -23,8 +23,6 @@ import android.content.Context;
import android.content.DialogInterface;
import android.widget.Toast;
-import org.apache.commons.codec.binary.Base64;
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -59,10 +57,6 @@ class Util {
createErrorDialog(c, message, listener).show();
}
- static String base64Encode(byte[] bytes) {
- return new String(Base64.encodeBase64(bytes));
- }
-
static void deleteFile(String path) {
deleteFile(new File(path));
}
diff --git a/src/com/android/settings/vpn/VpnEditor.java b/src/com/android/settings/vpn/VpnEditor.java
index e33ce550904..1d419eab215 100644
--- a/src/com/android/settings/vpn/VpnEditor.java
+++ b/src/com/android/settings/vpn/VpnEditor.java
@@ -46,7 +46,6 @@ public class VpnEditor extends PreferenceActivity {
private VpnProfileEditor mProfileEditor;
private boolean mAddingProfile;
- private String mOriginalProfileName;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -54,9 +53,6 @@ public class VpnEditor extends PreferenceActivity {
VpnProfile p = (VpnProfile) ((savedInstanceState == null)
? getIntent().getParcelableExtra(VpnSettings.KEY_VPN_PROFILE)
: savedInstanceState.getParcelable(KEY_PROFILE));
- mOriginalProfileName = (savedInstanceState == null)
- ? p.getName()
- : savedInstanceState.getString(KEY_ORIGINAL_PROFILE_NAME);
mProfileEditor = getEditor(p);
mAddingProfile = TextUtils.isEmpty(p.getName());
@@ -71,7 +67,6 @@ public class VpnEditor extends PreferenceActivity {
if (mProfileEditor == null) return;
outState.putParcelable(KEY_PROFILE, getProfile());
- outState.putString(KEY_ORIGINAL_PROFILE_NAME, mOriginalProfileName);
}
@Override
@@ -126,13 +121,11 @@ public class VpnEditor extends PreferenceActivity {
return false;
}
- mProfileEditor.saveSecrets(mOriginalProfileName);
setResult(getProfile());
return true;
}
private void setResult(VpnProfile p) {
- p.setId(Util.base64Encode(p.getName().getBytes()));
Intent intent = new Intent(this, VpnSettings.class);
intent.putExtra(VpnSettings.KEY_VPN_PROFILE, (Parcelable) p);
setResult(RESULT_OK, intent);
diff --git a/src/com/android/settings/vpn/VpnProfileEditor.java b/src/com/android/settings/vpn/VpnProfileEditor.java
index b679bcb6550..a708a8c89d5 100644
--- a/src/com/android/settings/vpn/VpnProfileEditor.java
+++ b/src/com/android/settings/vpn/VpnProfileEditor.java
@@ -91,13 +91,6 @@ class VpnProfileEditor {
: validate(mServerName, R.string.vpn_vpn_server));
}
- /**
- * Saves the secrets in this profile.
- * @param originalProfileName the original profile name
- */
- public void saveSecrets(String originalProfileName) {
- }
-
/**
* Creates a preference for users to input domain suffices.
*/
diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java
index bbbe9b92a5b..e429f9f37e5 100644
--- a/src/com/android/settings/vpn/VpnSettings.java
+++ b/src/com/android/settings/vpn/VpnSettings.java
@@ -17,6 +17,7 @@
package com.android.settings.vpn;
import com.android.settings.R;
+import com.android.settings.SecuritySettings;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -24,6 +25,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.net.vpn.L2tpIpsecPskProfile;
+import android.net.vpn.L2tpProfile;
import android.net.vpn.VpnManager;
import android.net.vpn.VpnProfile;
import android.net.vpn.VpnState;
@@ -38,6 +41,7 @@ import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.Preference.OnPreferenceClickListener;
+import android.security.Keystore;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
@@ -54,8 +58,8 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
@@ -113,6 +117,9 @@ public class VpnSettings extends PreferenceActivity implements
private VpnProfileActor mConnectingActor;
private boolean mStateSaved = false;
+ // states saved for unlocking keystore
+ private Runnable mUnlockAction;
+
private VpnManager mVpnManager = new VpnManager(this);
private ConnectivityReceiver mConnectivityReceiver =
@@ -169,6 +176,12 @@ public class VpnSettings extends PreferenceActivity implements
public void onResume() {
super.onResume();
mStatusChecker.onResume();
+
+ if ((mUnlockAction != null) && isKeystoreUnlocked()) {
+ Runnable action = mUnlockAction;
+ mUnlockAction = null;
+ runOnUiThread(action);
+ }
}
@Override
@@ -279,9 +292,9 @@ public class VpnSettings extends PreferenceActivity implements
}
@Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- int index = mIndexOfEditedProfile;
+ protected void onActivityResult(final int requestCode, final int resultCode,
+ final Intent data) {
+ final int index = mIndexOfEditedProfile;
mIndexOfEditedProfile = -1;
if ((resultCode == RESULT_CANCELED) || (data == null)) {
@@ -312,6 +325,16 @@ public class VpnSettings extends PreferenceActivity implements
return;
}
+ if (needKeystoreToSave(p)) {
+ Runnable action = new Runnable() {
+ public void run() {
+ mIndexOfEditedProfile = index;
+ onActivityResult(requestCode, resultCode, data);
+ }
+ };
+ if (!unlockKeystore(p, action)) return;
+ }
+
try {
if ((index < 0) || (index >= mVpnProfileList.size())) {
addProfile(p);
@@ -414,7 +437,27 @@ public class VpnSettings extends PreferenceActivity implements
.show();
}
+ // Randomly generates an ID for the profile.
+ // The ID is unique and only set once when the profile is created.
+ private void setProfileId(VpnProfile profile) {
+ String id;
+
+ while (true) {
+ id = String.valueOf(Math.abs(
+ Double.doubleToLongBits(Math.random())));
+ if (id.length() >= 8) break;
+ }
+ for (VpnProfile p : mVpnProfileList) {
+ if (p.getId().equals(id)) {
+ setProfileId(profile);
+ return;
+ }
+ }
+ profile.setId(id);
+ }
+
private void addProfile(VpnProfile p) throws IOException {
+ setProfileId(p);
saveProfileToStorage(p);
mVpnProfileList.add(p);
addPreferenceFor(p);
@@ -445,8 +488,11 @@ public class VpnSettings extends PreferenceActivity implements
throw new RuntimeException("inconsistent state!");
}
- // TODO: call saveSecret(String) after keystore is available
+ p.setId(oldProfile.getId());
+ processSecrets(p);
+
+ // TODO: remove copyFiles once the setId() code propagates.
// Copy config files and remove the old ones if they are in different
// directories.
if (Util.copyFiles(getProfileDir(oldProfile), getProfileDir(p))) {
@@ -463,25 +509,93 @@ public class VpnSettings extends PreferenceActivity implements
startActivityForResult(intent, REQUEST_SELECT_VPN_TYPE);
}
- private void startVpnEditor(VpnProfile profile) {
+ private boolean isKeystoreUnlocked() {
+ return (Keystore.getInstance().getState() == Keystore.UNLOCKED);
+ }
+
+
+ // Returns true if the profile needs to access keystore
+ private boolean needKeystoreToSave(VpnProfile p) {
+ return needKeystoreToConnect(p);
+ }
+
+ // Returns true if the profile needs to access keystore
+ private boolean needKeystoreToEdit(VpnProfile p) {
+ switch (p.getType()) {
+ case L2TP_IPSEC:
+ case L2TP_IPSEC_PSK:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ // Returns true if the profile needs to access keystore
+ private boolean needKeystoreToConnect(VpnProfile p) {
+ switch (p.getType()) {
+ case L2TP_IPSEC:
+ case L2TP_IPSEC_PSK:
+ return true;
+
+ case L2TP:
+ return ((L2tpProfile) p).isSecretEnabled();
+
+ default:
+ return false;
+ }
+ }
+
+ // Returns true if keystore is unlocked or keystore is not a concern
+ private boolean unlockKeystore(VpnProfile p, Runnable action) {
+ if (isKeystoreUnlocked()) return true;
+ mUnlockAction = action;
+ startActivity(
+ new Intent(SecuritySettings.ACTION_UNLOCK_CREDENTIAL_STORAGE));
+ return false;
+ }
+
+ private void startVpnEditor(final VpnProfile profile) {
+ if (needKeystoreToEdit(profile)) {
+ Runnable action = new Runnable() {
+ public void run() {
+ startVpnEditor(profile);
+ }
+ };
+ if (!unlockKeystore(profile, action)) return;
+ }
+
Intent intent = new Intent(this, VpnEditor.class);
intent.putExtra(KEY_VPN_PROFILE, (Parcelable) profile);
startActivityForResult(intent, REQUEST_ADD_OR_EDIT_PROFILE);
}
+ private synchronized void connect(final VpnProfile p) {
+ if (needKeystoreToConnect(p)) {
+ Runnable action = new Runnable() {
+ public void run() {
+ connect(p);
+ }
+ };
+ if (!unlockKeystore(p, action)) return;
+ }
+
+ mConnectingActor = getActor(p);
+ if (mConnectingActor.isConnectDialogNeeded()) {
+ removeDialog(DIALOG_CONNECT);
+ showDialog(DIALOG_CONNECT);
+ } else {
+ changeState(p, VpnState.CONNECTING);
+ mConnectingActor.connect(null);
+ }
+ }
+
// Do connect or disconnect based on the current state.
private synchronized void connectOrDisconnect(VpnProfile p) {
VpnPreference pref = mVpnPreferenceMap.get(p.getName());
switch (p.getState()) {
case IDLE:
- mConnectingActor = getActor(p);
- if (mConnectingActor.isConnectDialogNeeded()) {
- removeDialog(DIALOG_CONNECT);
- showDialog(DIALOG_CONNECT);
- } else {
- changeState(p, VpnState.CONNECTING);
- mConnectingActor.connect(null);
- }
+ connect(p);
break;
case CONNECTING:
@@ -601,7 +715,6 @@ public class VpnSettings extends PreferenceActivity implements
File root = new File(PROFILES_ROOT);
String[] dirs = root.list();
if (dirs == null) return;
- Arrays.sort(dirs);
for (String dir : dirs) {
File f = new File(new File(root, dir), PROFILE_OBJ_FILE);
if (!f.exists()) continue;
@@ -611,11 +724,21 @@ public class VpnSettings extends PreferenceActivity implements
if (!checkIdConsistency(dir, p)) continue;
mVpnProfileList.add(p);
- addPreferenceFor(p);
} catch (IOException e) {
Log.e(TAG, "retrieveVpnListFromStorage()", e);
}
}
+ Collections.sort(mVpnProfileList, new Comparator() {
+ public int compare(VpnProfile p1, VpnProfile p2) {
+ return p1.getName().compareTo(p2.getName());
+ }
+
+ public boolean equals(VpnProfile p) {
+ // not used
+ return false;
+ }
+ });
+ for (VpnProfile p : mVpnProfileList) addPreferenceFor(p);
disableProfilePreferencesIfOneActive();
}
@@ -668,6 +791,40 @@ public class VpnSettings extends PreferenceActivity implements
return mVpnManager.createVpnProfile(Enum.valueOf(VpnType.class, type));
}
+ private static final String NAMESPACE_VPN = "vpn";
+ private static final String KEY_PREFIX_IPSEC_PSK = "ipsk000";
+ private static final String KEY_PREFIX_L2TP_SECRET = "lscrt000";
+
+ private void processSecrets(VpnProfile p) {
+ Keystore ks = Keystore.getInstance();
+ switch (p.getType()) {
+ case L2TP_IPSEC_PSK:
+ L2tpIpsecPskProfile pskProfile = (L2tpIpsecPskProfile) p;
+ String keyName = KEY_PREFIX_IPSEC_PSK + p.getId();
+ String presharedKey = pskProfile.getPresharedKey();
+ if (!presharedKey.equals(keyName)) {
+ ks.put(NAMESPACE_VPN, keyName, presharedKey);
+ pskProfile.setPresharedKey(NAMESPACE_VPN + "_" + keyName);
+ }
+ // pass through
+
+ case L2TP:
+ L2tpProfile l2tpProfile = (L2tpProfile) p;
+ keyName = KEY_PREFIX_L2TP_SECRET + p.getId();
+ String secret = l2tpProfile.getSecretString();
+ if (l2tpProfile.isSecretEnabled()) {
+ if (!secret.equals(keyName)) {
+ ks.put(NAMESPACE_VPN, keyName, secret);
+ l2tpProfile.setSecretString(
+ NAMESPACE_VPN + "_" + keyName);
+ }
+ } else {
+ ks.remove(NAMESPACE_VPN, keyName);
+ }
+ break;
+ }
+ }
+
private class VpnPreference extends Preference {
VpnProfile mProfile;
VpnPreference(Context c, VpnProfile p) {
From 44fbbea071611f33fb8004b5684f5e342763d278 Mon Sep 17 00:00:00 2001
From: Jean-Michel Trivi
Date: Mon, 6 Jul 2009 14:04:54 -0700
Subject: [PATCH 121/126] Fix bug 1946195 by making use of the current Locale
to set a default value in the language pref list (bug was no selection in the
default language list). Fix half of bug 1956707 where speech rate value as
read from the settings was translated to a ratio, which applied an improper
speech rate on the TTS engine (bug was setting a default rate makes the TTS
demo unintelligible). Moved logic to set the default value in the language
pref list in a separate private method to improve readability. Changed
default rate values so that normal is 1x and the fastest is 2x.
---
res/values/arrays.xml | 6 +-
.../settings/TextToSpeechSettings.java | 75 +++++++++++--------
2 files changed, 45 insertions(+), 36 deletions(-)
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 750b0835719..a470acc4f3a 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -88,10 +88,10 @@
- 60
+ - 80
- 100
- - 140
- - 180
- - 220
+ - 150
+ - 200
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index ec0fc8cde66..11998a3537d 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -39,6 +39,7 @@ import android.speech.tts.TextToSpeech;
import android.util.Log;
import java.util.List;
+import java.util.Locale;
import java.util.StringTokenizer;
public class TextToSpeechSettings extends PreferenceActivity implements
@@ -95,14 +96,14 @@ public class TextToSpeechSettings extends PreferenceActivity implements
initClickers();
initDefaultSettings();
}
-
-
+
+
@Override
protected void onStart() {
super.onStart();
// whenever we return to this screen, we don't know the state of the
// system, so we have to recheck that we can play the demo, or it must be disabled.
- // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
+ // TODO make the TTS service listen to "changes in the system", i.e. sd card un/mount
initClickers();
updateWidgetState();
checkVoiceData();
@@ -174,23 +175,21 @@ public class TextToSpeechSettings extends PreferenceActivity implements
String variant = null;
mDefaultLocPref = (ListPreference) findPreference(KEY_TTS_DEFAULT_LANG);
language = Settings.Secure.getString(resolver, TTS_DEFAULT_LANG);
- if (language != null) {
- mDefaultLanguage = language;
- } else {
- // default language setting not found, initialize it, as well as the country and variant
- language = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_LANG;
- country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
- variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+ if (language == null) {
+ // the default language property isn't set, use that of the current locale
+ Locale currentLocale = Locale.getDefault();
+ language = currentLocale.getISO3Language();
+ country = currentLocale.getISO3Country();
+ variant = currentLocale.getVariant();
Settings.Secure.putString(resolver, TTS_DEFAULT_LANG, language);
Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, country);
Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
}
+ mDefaultLanguage = language;
if (country == null) {
// country wasn't initialized yet because a default language was found
country = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
- if (country != null) {
- mDefaultCountry = country;
- } else {
+ if (country == null) {
// default country setting not found, initialize it, as well as the variant;
country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
@@ -198,30 +197,19 @@ public class TextToSpeechSettings extends PreferenceActivity implements
Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
}
}
+ mDefaultCountry = country;
if (variant == null) {
// variant wasn't initialized yet because a default country was found
variant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
- if (variant != null) {
- mDefaultLocVariant = variant;
- } else {
+ if (variant == null) {
// default variant setting not found, initialize it
variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
}
}
- // we now have the default lang/country/variant trio, build a string value from it
- String localeString = new String(language);
- if (country.compareTo("") != 0) {
- localeString += LOCALE_DELIMITER + country;
- } else {
- localeString += LOCALE_DELIMITER + " ";
- }
- if (variant.compareTo("") != 0) {
- localeString += LOCALE_DELIMITER + variant;
- }
- Log.v(TAG, "In initDefaultSettings: localeString=" + localeString);
- // TODO handle the case where localeString isn't in the existing entries
- mDefaultLocPref.setValue(localeString);
+ mDefaultLocVariant = variant;
+
+ setDefaultLocalePref(language, country, variant);
mDefaultLocPref.setOnPreferenceChangeListener(this);
}
@@ -311,10 +299,10 @@ public class TextToSpeechSettings extends PreferenceActivity implements
// Default rate
int value = Integer.parseInt((String) objValue);
try {
- Settings.Secure.putInt(getContentResolver(),
+ Settings.Secure.putInt(getContentResolver(),
TTS_DEFAULT_RATE, value);
if (mTts != null) {
- mTts.setSpeechRate(value);
+ mTts.setSpeechRate((float)(value/100.0f));
}
Log.i(TAG, "TTS default rate is "+value);
} catch (NumberFormatException e) {
@@ -330,10 +318,10 @@ public class TextToSpeechSettings extends PreferenceActivity implements
Log.v(TAG, "TTS default lang/country/variant set to "
+ mDefaultLanguage + "/" + mDefaultCountry + "/" + mDefaultLocVariant);
}
-
+
return true;
}
-
+
/**
* Called when mPlayExample or mInstallData is clicked
@@ -384,4 +372,25 @@ public class TextToSpeechSettings extends PreferenceActivity implements
}
+ private void setDefaultLocalePref(String language, String country, String variant) {
+ // build a string from the default lang/country/variant trio,
+ String localeString = new String(language);
+ if (country.compareTo("") != 0) {
+ localeString += LOCALE_DELIMITER + country;
+ } else {
+ localeString += LOCALE_DELIMITER + " ";
+ }
+ if (variant.compareTo("") != 0) {
+ localeString += LOCALE_DELIMITER + variant;
+ }
+
+ if (mDefaultLocPref.findIndexOfValue(localeString) > -1) {
+ mDefaultLocPref.setValue(localeString);
+ } else {
+ mDefaultLocPref.setValueIndex(0);
+ }
+
+ Log.v(TAG, "In initDefaultSettings: localeString=" + localeString);
+ }
+
}
From 33ababd1bdb651d32952536e6d5e72750d1f4cc9 Mon Sep 17 00:00:00 2001
From: Hung-ying Tyan
Date: Tue, 7 Jul 2009 10:35:45 +0800
Subject: [PATCH 122/126] String fixes for the credential storage and vpn
settings.
* Changes
+ Shorten the messages for both set-password and enter-password dialogs
when other activities access the credential storage.
Patch Set 2:
+ Fix the capital issue in the vpn error messages.
+ Add separate strings for terms used in the error messages.
+ Modify related src files that use those terms.
---
res/values/strings.xml | 25 ++++++++++---------
.../settings/vpn/AuthenticationActor.java | 4 +--
src/com/android/settings/vpn/L2tpEditor.java | 2 +-
.../android/settings/vpn/L2tpIpsecEditor.java | 4 +--
.../settings/vpn/L2tpIpsecPskEditor.java | 2 +-
.../settings/vpn/VpnProfileEditor.java | 4 +--
6 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1022a2e0472..8af3c584e12 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1822,8 +1822,8 @@ found in the list of installed applications.
Username:
Password:
- username
- password
+ a username
+ a password
Remember username
@@ -1843,8 +1843,8 @@ found in the list of installed applications.
Delete network
- You must enter a %s.
- You must select a %s.
+ You must enter %s.
+ You must select %s.
The VPN name \'%s\' already exists. Find another name.
Are you sure you want to delete this VPN?
Are you sure you don\'t want to create this profile?
@@ -1874,6 +1874,7 @@ found in the list of installed applications.
VPN name
+ a VPN name
'%s' is added
@@ -1884,30 +1885,30 @@ found in the list of installed applications.
Set user certificate
User certificate
+ a user certificate
Set CA certificate
Certificate authority (CA) certificate
+ a CA certificate
Set L2TP secret
L2TP secret
+ an L2TP secret
Set IPSec pre-shared key
IPSec pre-shared key
-
-
- Set IPSec pre-shared key
-
- IPSec pre-shared key
+ an IPSec pre-shared key
Set VPN server
VPN server
+ a VPN server
VPN server name
@@ -1947,7 +1948,7 @@ found in the list of installed applications.
Enter password
- This action requires enabling the credential storage. Please enter the password to enable it.
+ Enter the credential storage password.
Set password
@@ -1978,9 +1979,9 @@ found in the list of installed applications.
Confirm new password:
- You must set a password for the credential storage.
+ Set a password for the credential storage.
- This action requires the credential storage but the storage has not been activated before. To activiate it, you must set a password for the credential storage.
+ Set a password for the credential storage.
Please enter the correct password.
Please enter the correct password. You have one more try to enter the correct password before the credential storage is erased.
Please enter the correct password. You have %d more tries to enter the correct password before the credential storage is erased.
diff --git a/src/com/android/settings/vpn/AuthenticationActor.java b/src/com/android/settings/vpn/AuthenticationActor.java
index af9875c1149..286064f3cae 100644
--- a/src/com/android/settings/vpn/AuthenticationActor.java
+++ b/src/com/android/settings/vpn/AuthenticationActor.java
@@ -70,9 +70,9 @@ public class AuthenticationActor implements VpnProfileActor {
TextView passwordView = (TextView) d.findViewById(R.id.password_value);
Context c = mContext;
if (TextUtils.isEmpty(usernameView.getText().toString())) {
- return c.getString(R.string.vpn_username);
+ return c.getString(R.string.vpn_a_username);
} else if (TextUtils.isEmpty(passwordView.getText().toString())) {
- return c.getString(R.string.vpn_password);
+ return c.getString(R.string.vpn_a_password);
} else {
return null;
}
diff --git a/src/com/android/settings/vpn/L2tpEditor.java b/src/com/android/settings/vpn/L2tpEditor.java
index c518dec46a6..643ba3b61f2 100644
--- a/src/com/android/settings/vpn/L2tpEditor.java
+++ b/src/com/android/settings/vpn/L2tpEditor.java
@@ -57,7 +57,7 @@ class L2tpEditor extends VpnProfileEditor {
return ((result != null)
? result
- : validate(mSecretString, R.string.vpn_l2tp_secret));
+ : validate(mSecretString, R.string.vpn_a_l2tp_secret));
}
private Preference createSecretPreference(Context c) {
diff --git a/src/com/android/settings/vpn/L2tpIpsecEditor.java b/src/com/android/settings/vpn/L2tpIpsecEditor.java
index b6b244f7ee5..b14feb32d2c 100644
--- a/src/com/android/settings/vpn/L2tpIpsecEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecEditor.java
@@ -55,10 +55,10 @@ class L2tpIpsecEditor extends L2tpEditor {
public String validate() {
String result = super.validate();
if (result == null) {
- result = validate(mUserCertificate, R.string.vpn_user_certificate);
+ result = validate(mUserCertificate, R.string.vpn_a_user_certificate);
}
if (result == null) {
- result = validate(mCaCertificate, R.string.vpn_ca_certificate);
+ result = validate(mCaCertificate, R.string.vpn_a_ca_certificate);
}
return result;
}
diff --git a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
index fb67c987ffc..11590daaa5b 100644
--- a/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
+++ b/src/com/android/settings/vpn/L2tpIpsecPskEditor.java
@@ -47,7 +47,7 @@ class L2tpIpsecPskEditor extends L2tpEditor {
return ((result != null)
? result
- : validate(mPresharedKey, R.string.vpn_ipsec_presharedkey));
+ : validate(mPresharedKey, R.string.vpn_a_ipsec_presharedkey));
}
private Preference createPresharedKeyPreference(Context c) {
diff --git a/src/com/android/settings/vpn/VpnProfileEditor.java b/src/com/android/settings/vpn/VpnProfileEditor.java
index a708a8c89d5..a1cdc7633d4 100644
--- a/src/com/android/settings/vpn/VpnProfileEditor.java
+++ b/src/com/android/settings/vpn/VpnProfileEditor.java
@@ -85,10 +85,10 @@ class VpnProfileEditor {
* null if all the inputs are valid
*/
public String validate() {
- String result = validate(mName, R.string.vpn_name);
+ String result = validate(mName, R.string.vpn_a_name);
return ((result != null)
? result
- : validate(mServerName, R.string.vpn_vpn_server));
+ : validate(mServerName, R.string.vpn_a_vpn_server));
}
/**
From 242096832b552081dc602fe81d9c0fd0a5103ad2 Mon Sep 17 00:00:00 2001
From: Chung-yih Wang
Date: Tue, 7 Jul 2009 21:58:13 +0800
Subject: [PATCH 123/126] Add header 'blob://' in front of the cert/key names
in wpa_supplicant.conf.
1. This addition is from CL 6082 change in wpa_supplicant.
2. Fix the empty password pop-up for EAP.
---
src/com/android/settings/wifi/AccessPointDialog.java | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/com/android/settings/wifi/AccessPointDialog.java b/src/com/android/settings/wifi/AccessPointDialog.java
index bf2007a9a5a..c9f511bc4ca 100644
--- a/src/com/android/settings/wifi/AccessPointDialog.java
+++ b/src/com/android/settings/wifi/AccessPointDialog.java
@@ -84,6 +84,7 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
AccessPointState.WEP_PASSWORD_HEX
};
private static final String NOT_APPLICABLE = "N/A";
+ private static final String BLOB_HEADER = "blob://";
// Button positions, default to impossible values
private int mConnectButtonPos = Integer.MAX_VALUE;
@@ -528,7 +529,8 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
if (passwordIsEmpty && (!mState.hasPassword() ||
mMode == MODE_RETRY_PASSWORD) &&
(mState.security != null) &&
- !mState.security.equals(AccessPointState.OPEN)) {
+ !mState.security.equals(AccessPointState.OPEN) &&
+ !mState.isEnterprise()) {
new AlertDialog.Builder(getContext())
.setTitle(R.string.error_title)
.setIcon(android.R.drawable.ic_dialog_alert)
@@ -642,12 +644,12 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
value = mCertTool.getUserCertificate(key);
if (!TextUtils.isEmpty(value)) {
mState.setEnterpriseField(AccessPointState.CLIENT_CERT,
- value);
+ BLOB_HEADER + value);
}
value = mCertTool.getUserPrivateKey(key);
if (!TextUtils.isEmpty(value)) {
mState.setEnterpriseField(AccessPointState.PRIVATE_KEY,
- value);
+ BLOB_HEADER + value);
}
}
spinner = mCaCertSpinner;
@@ -657,7 +659,7 @@ public class AccessPointDialog extends AlertDialog implements DialogInterface.On
value = mCertTool.getCaCertificate(key);
if (!TextUtils.isEmpty(value)) {
mState.setEnterpriseField(AccessPointState.CA_CERT,
- value);
+ BLOB_HEADER + value);
}
}
switch (securityType) {
From c155acc11c540b3f552a9051003f1db35d6d6197 Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Tue, 7 Jul 2009 14:38:41 -0700
Subject: [PATCH 124/126] Trigger backup of locale change.
---
src/com/android/settings/LocalePicker.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/com/android/settings/LocalePicker.java b/src/com/android/settings/LocalePicker.java
index ecd9689a08f..39fb6fabae0 100644
--- a/src/com/android/settings/LocalePicker.java
+++ b/src/com/android/settings/LocalePicker.java
@@ -19,6 +19,7 @@ package com.android.settings;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.ListActivity;
+import android.backup.BackupManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.RemoteException;
@@ -158,6 +159,8 @@ public class LocalePicker extends ListActivity {
config.userSetLocale = true;
am.updateConfiguration(config);
+ // Trigger the dirty bit for the Settings Provider.
+ BackupManager.dataChanged("com.android.providers.settings");
} catch (RemoteException e) {
// Intentionally left blank
}
From eb72bcd6d07708bfc65eec474092f136e822c9fb Mon Sep 17 00:00:00 2001
From: Amith Yamasani
Date: Tue, 7 Jul 2009 11:37:08 -0700
Subject: [PATCH 125/126] Fix vibrate and silent mode toggle dependency.
---
.../settings/SoundAndDisplaySettings.java | 34 ++++++++-----------
1 file changed, 15 insertions(+), 19 deletions(-)
diff --git a/src/com/android/settings/SoundAndDisplaySettings.java b/src/com/android/settings/SoundAndDisplaySettings.java
index 3d3a5d0606e..8e7411c40a8 100644
--- a/src/com/android/settings/SoundAndDisplaySettings.java
+++ b/src/com/android/settings/SoundAndDisplaySettings.java
@@ -216,33 +216,29 @@ public class SoundAndDisplaySettings extends PreferenceActivity implements
Settings.System.ACCELEROMETER_ROTATION, 0) != 0);
}
+ private void setRingerMode(boolean silent, boolean vibrate) {
+ if (silent) {
+ mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE :
+ AudioManager.RINGER_MODE_SILENT);
+ } else {
+ mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
+ mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
+ vibrate ? AudioManager.VIBRATE_SETTING_ON
+ : AudioManager.VIBRATE_SETTING_OFF);
+ }
+ }
+
@Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (preference == mSilent) {
- final boolean silent = mSilent.isChecked();
- mAudioManager.setRingerMode(silent ? AudioManager.RINGER_MODE_SILENT
- : AudioManager.RINGER_MODE_NORMAL);
- updateState(false);
-
+ if (preference == mSilent || preference == mVibrate) {
+ setRingerMode(mSilent.isChecked(), mVibrate.isChecked());
+ if (preference == mSilent) updateState(false);
} else if (preference == mPlayMediaNotificationSounds) {
try {
mMountService.setPlayNotificationSounds(mPlayMediaNotificationSounds.isChecked());
} catch (RemoteException e) {
}
- } else if (preference == mVibrate) {
- final boolean vibrate = mVibrate.isChecked();
- final boolean silent = mSilent.isChecked();
-
- if (silent) {
- mAudioManager.setRingerMode(vibrate ? AudioManager.RINGER_MODE_VIBRATE :
- AudioManager.RINGER_MODE_SILENT);
- } else {
- mAudioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,
- vibrate ? AudioManager.VIBRATE_SETTING_ON
- : AudioManager.VIBRATE_SETTING_OFF);
- }
-
} else if (preference == mDtmfTone) {
Settings.System.putInt(getContentResolver(), Settings.System.DTMF_TONE_WHEN_DIALING,
mDtmfTone.isChecked() ? 1 : 0);
From 00d4fbfc42f2f4abf1a82f0854eb3d7c1ef1a04d Mon Sep 17 00:00:00 2001
From: Jean-Michel Trivi
Date: Tue, 7 Jul 2009 17:08:32 -0700
Subject: [PATCH 126/126] In the TTS settings: rely on the default locale
rather than default values stored in TextToSpeech.Engine to initialize the
default TTS country and variant.
---
src/com/android/settings/TextToSpeechSettings.java | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/com/android/settings/TextToSpeechSettings.java b/src/com/android/settings/TextToSpeechSettings.java
index 11998a3537d..88bfc6703ec 100644
--- a/src/com/android/settings/TextToSpeechSettings.java
+++ b/src/com/android/settings/TextToSpeechSettings.java
@@ -191,8 +191,9 @@ public class TextToSpeechSettings extends PreferenceActivity implements
country = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_COUNTRY);
if (country == null) {
// default country setting not found, initialize it, as well as the variant;
- country = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
- variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+ Locale currentLocale = Locale.getDefault();
+ country = currentLocale.getISO3Country();
+ variant = currentLocale.getVariant();
Settings.Secure.putString(resolver, TTS_DEFAULT_COUNTRY, country);
Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
}
@@ -203,7 +204,8 @@ public class TextToSpeechSettings extends PreferenceActivity implements
variant = Settings.Secure.getString(resolver, KEY_TTS_DEFAULT_VARIANT);
if (variant == null) {
// default variant setting not found, initialize it
- variant = TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_VARIANT;
+ Locale currentLocale = Locale.getDefault();
+ variant = currentLocale.getVariant();
Settings.Secure.putString(resolver, TTS_DEFAULT_VARIANT, variant);
}
}