diff options
author | Hung-ying Tyan <tyanh@google.com> | 2009-06-26 14:24:50 +0800 |
---|---|---|
committer | Hung-ying Tyan <tyanh@google.com> | 2009-06-26 14:24:50 +0800 |
commit | e7565f3c48e6c90e65d9c15e33d20673a187c156 (patch) | |
tree | b3f6dd9c2d8508faa0dc81d94b107cb2b32e9ce8 /src/com | |
parent | 386278a338d740dce95b7fa1514662b0eb5683e4 (diff) | |
download | packages_apps_settings-e7565f3c48e6c90e65d9c15e33d20673a187c156.zip packages_apps_settings-e7565f3c48e6c90e65d9c15e33d20673a187c156.tar.gz packages_apps_settings-e7565f3c48e6c90e65d9c15e33d20673a187c156.tar.bz2 |
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
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/android/settings/SecuritySettings.java | 12 | ||||
-rw-r--r-- | src/com/android/settings/vpn/AuthenticationActor.java | 33 | ||||
-rw-r--r-- | src/com/android/settings/vpn/L2tpEditor.java | 119 | ||||
-rw-r--r-- | src/com/android/settings/vpn/L2tpIpsecEditor.java | 42 | ||||
-rw-r--r-- | src/com/android/settings/vpn/Util.java | 9 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnEditor.java | 111 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnProfileEditor.java | 150 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnSettings.java | 253 | ||||
-rw-r--r-- | src/com/android/settings/vpn/VpnTypeSelection.java | 9 |
9 files changed, 471 insertions, 267 deletions
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java index ffeac34..e0d0cc1 100644 --- a/src/com/android/settings/SecuritySettings.java +++ b/src/com/android/settings/SecuritySettings.java @@ -28,7 +28,6 @@ import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.location.LocationManager; -import android.net.vpn.VpnManager; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; @@ -198,17 +197,6 @@ public class SecuritySettings extends PreferenceActivity implements showPassword.setPersistent(false); passwordsCat.addPreference(showPassword); - PreferenceScreen vpnPreferences = getPreferenceManager() - .createPreferenceScreen(this); - vpnPreferences.setTitle(R.string.vpn_settings_title); - vpnPreferences.setSummary(R.string.vpn_settings_summary); - vpnPreferences.setIntent(new VpnManager(this).createSettingsActivityIntent()); - - PreferenceCategory vpnCat = new PreferenceCategory(this); - vpnCat.setTitle(R.string.vpn_settings_category); - root.addPreference(vpnCat); - vpnCat.addPreference(vpnPreferences); - return root; } diff --git a/src/com/android/settings/vpn/AuthenticationActor.java b/src/com/android/settings/vpn/AuthenticationActor.java index c56317c..af9875c 100644 --- a/src/com/android/settings/vpn/AuthenticationActor.java +++ b/src/com/android/settings/vpn/AuthenticationActor.java @@ -28,11 +28,14 @@ import android.net.vpn.VpnProfile; import android.net.vpn.VpnState; import android.os.IBinder; import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; +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. @@ -66,9 +69,9 @@ public class AuthenticationActor implements VpnProfileActor { TextView usernameView = (TextView) d.findViewById(R.id.username_value); TextView passwordView = (TextView) d.findViewById(R.id.password_value); Context c = mContext; - if (Util.isNullOrEmpty(usernameView.getText().toString())) { + if (TextUtils.isEmpty(usernameView.getText().toString())) { return c.getString(R.string.vpn_username); - } else if (Util.isNullOrEmpty(passwordView.getText().toString())) { + } else if (TextUtils.isEmpty(passwordView.getText().toString())) { return c.getString(R.string.vpn_password); } else { return null; @@ -81,12 +84,14 @@ public class AuthenticationActor implements VpnProfileActor { 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(""); + try { + setSavedUsername(saveUsername.isChecked() + ? usernameView.getText().toString() + : ""); + } catch (IOException e) { + Log.e(TAG, "setSavedUsername()", e); } + connect(usernameView.getText().toString(), passwordView.getText().toString()); passwordView.setText(""); @@ -101,7 +106,11 @@ public class AuthenticationActor implements VpnProfileActor { public void updateConnectView(Dialog d) { String username = mProfile.getSavedUsername(); if (username == null) username = ""; - updateConnectView(d, username, "", !Util.isNullOrEmpty(username)); + updateConnectView(d, username, "", !TextUtils.isEmpty(username)); + } + + protected Context getContext() { + return mContext; } private void connect(final String username, final String password) { @@ -121,7 +130,6 @@ public class AuthenticationActor implements VpnProfileActor { if (!success) { Log.d(TAG, "~~~~~~ connect() failed!"); - // TODO: pop up a dialog broadcastConnectivity(VpnState.IDLE); } else { Log.d(TAG, "~~~~~~ connect() succeeded!"); @@ -209,4 +217,11 @@ public class AuthenticationActor implements VpnProfileActor { } catch (Exception e) {} } } + + private void setSavedUsername(String name) throws IOException { + if (!name.equals(mProfile.getSavedUsername())) { + mProfile.setSavedUsername(name); + VpnSettings.saveProfileToStorage(mProfile); + } + } } diff --git a/src/com/android/settings/vpn/L2tpEditor.java b/src/com/android/settings/vpn/L2tpEditor.java new file mode 100644 index 0000000..88a1142 --- /dev/null +++ b/src/com/android/settings/vpn/L2tpEditor.java @@ -0,0 +1,119 @@ +/* + * 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.L2tpProfile; +import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.Preference; +import android.preference.PreferenceGroup; + +/** + * The class for editing {@link L2tpProfile}. + */ +class L2tpEditor extends VpnProfileEditor { + private CheckBoxPreference mSecret; + private EditTextPreference mSecretString; + private String mOriginalSecret; + private boolean mOriginalSecretEnabled; + + public L2tpEditor(L2tpProfile p) { + super(p); + } + + @Override + protected void loadExtraPreferencesTo(PreferenceGroup subpanel) { + Context c = subpanel.getContext(); + subpanel.addPreference(createSecretPreference(c)); + subpanel.addPreference(createSecretStringPreference(c)); + mSecretString.setEnabled(mSecret.isChecked()); + + L2tpProfile profile = (L2tpProfile) getProfile(); + mOriginalSecret = profile.getSecretString(); + mOriginalSecretEnabled = profile.isSecretEnabled(); + } + + @Override + public String validate() { + String result = super.validate(); + if (!mSecret.isChecked()) return result; + + return ((result != null) + ? result + : 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); + boolean enabled = profile.isSecretEnabled(); + setSecretTitle(secret, R.string.vpn_l2tp_secret, enabled); + secret.setChecked(enabled); + setSecretSummary(secret, enabled); + secret.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange( + Preference pref, Object newValue) { + boolean enabled = (Boolean) newValue; + profile.setSecretEnabled(enabled); + mSecretString.setEnabled(enabled); + setSecretTitle(mSecret, R.string.vpn_l2tp_secret, + enabled); + setSecretSummary(mSecret, enabled); + return true; + } + }); + return secret; + } + + private Preference createSecretStringPreference(Context c) { + final L2tpProfile profile = (L2tpProfile) getProfile(); + mSecretString = createSecretPreference(c, + R.string.vpn_l2tp_secret_string_title, + R.string.vpn_l2tp_secret, + profile.getSecretString(), + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange( + Preference pref, Object newValue) { + profile.setSecretString((String) newValue); + setSecretSummary(mSecretString, + R.string.vpn_l2tp_secret, + (String) newValue); + return true; + } + }); + return mSecretString; + } + + private void setSecretSummary(CheckBoxPreference secret, boolean enabled) { + Context c = secret.getContext(); + String formatString = c.getString(enabled + ? R.string.vpn_is_enabled + : R.string.vpn_is_disabled); + secret.setSummary(String.format( + formatString, c.getString(R.string.vpn_l2tp_secret))); + } +} diff --git a/src/com/android/settings/vpn/L2tpIpsecEditor.java b/src/com/android/settings/vpn/L2tpIpsecEditor.java index bb63772..e79760c 100644 --- a/src/com/android/settings/vpn/L2tpIpsecEditor.java +++ b/src/com/android/settings/vpn/L2tpIpsecEditor.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. @@ -25,11 +25,12 @@ import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceGroup; import android.security.Keystore; +import android.text.TextUtils; /** * The class for editing {@link L2tpIpsecProfile}. */ -class L2tpIpsecEditor extends VpnProfileEditor { +class L2tpIpsecEditor extends L2tpEditor { private static final String TAG = L2tpIpsecEditor.class.getSimpleName(); private ListPreference mUserCertificate; @@ -44,23 +45,22 @@ class L2tpIpsecEditor extends VpnProfileEditor { @Override protected void loadExtraPreferencesTo(PreferenceGroup subpanel) { + super.loadExtraPreferencesTo(subpanel); Context c = subpanel.getContext(); subpanel.addPreference(createUserCertificatePreference(c)); subpanel.addPreference(createCaCertificatePreference(c)); } @Override - public String validate(Context c) { - String result = super.validate(c); - if (result != null) { - return result; - } else if (Util.isNullOrEmpty(mUserCertificate.getValue())) { - return c.getString(R.string.vpn_error_user_certificate_not_selected); - } else if (Util.isNullOrEmpty(mCaCertificate.getValue())) { - return c.getString(R.string.vpn_error_ca_certificate_not_selected); - } else { - return null; + public String validate() { + String result = super.validate(); + if (result == null) { + result = validate(mUserCertificate, R.string.vpn_user_certificate); } + if (result == null) { + result = validate(mCaCertificate, R.string.vpn_ca_certificate); + } + return result; } private Preference createUserCertificatePreference(Context c) { @@ -72,9 +72,13 @@ class L2tpIpsecEditor extends VpnProfileEditor { public boolean onPreferenceChange( Preference pref, Object newValue) { mProfile.setUserCertificate((String) newValue); - return onPreferenceChangeCommon(pref, newValue); + setSummary(pref, R.string.vpn_user_certificate, + (String) newValue); + return true; } }); + setSummary(mUserCertificate, R.string.vpn_user_certificate, + mProfile.getUserCertificate()); return mUserCertificate; } @@ -87,9 +91,13 @@ class L2tpIpsecEditor extends VpnProfileEditor { public boolean onPreferenceChange( Preference pref, Object newValue) { mProfile.setCaCertificate((String) newValue); - return onPreferenceChangeCommon(pref, newValue); + setSummary(pref, R.string.vpn_ca_certificate, + (String) newValue); + return true; } }); + setSummary(mCaCertificate, R.string.vpn_ca_certificate, + mProfile.getCaCertificate()); return mCaCertificate; } @@ -103,13 +111,7 @@ class L2tpIpsecEditor extends VpnProfileEditor { pref.setEntries(keys); pref.setEntryValues(keys); pref.setValue(text); - pref.setSummary(checkNull(text, c)); pref.setOnPreferenceChangeListener(listener); return pref; } - - private boolean onPreferenceChangeCommon(Preference pref, Object newValue) { - pref.setSummary(checkNull(newValue.toString(), pref.getContext())); - return true; - } } diff --git a/src/com/android/settings/vpn/Util.java b/src/com/android/settings/vpn/Util.java index d7ba1f7..e4316fd 100644 --- a/src/com/android/settings/vpn/Util.java +++ b/src/com/android/settings/vpn/Util.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. @@ -59,10 +59,6 @@ class Util { createErrorDialog(c, message, listener).show(); } - static boolean isNullOrEmpty(String message) { - return ((message == null) || (message.length() == 0)); - } - static String base64Encode(byte[] bytes) { return new String(Base64.encodeBase64(bytes)); } @@ -132,7 +128,8 @@ class Util { private static AlertDialog createErrorDialog(Context c, String message, DialogInterface.OnClickListener okListener) { AlertDialog.Builder b = new AlertDialog.Builder(c) - .setTitle(R.string.vpn_error_title) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(message); if (okListener != null) { b.setPositiveButton(R.string.vpn_back_button, okListener); diff --git a/src/com/android/settings/vpn/VpnEditor.java b/src/com/android/settings/vpn/VpnEditor.java index 35c8bfb..9df98a6 100644 --- a/src/com/android/settings/vpn/VpnEditor.java +++ b/src/com/android/settings/vpn/VpnEditor.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. @@ -22,60 +22,59 @@ import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.vpn.L2tpIpsecProfile; +import android.net.vpn.L2tpProfile; import android.net.vpn.VpnProfile; import android.net.vpn.VpnType; import android.os.Bundle; import android.os.Parcelable; -import android.preference.EditTextPreference; -import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceGroup; +import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; +import android.view.View; /** * The activity class for editing a new or existing VPN profile. */ public class VpnEditor extends PreferenceActivity { - private static final String TAG = VpnEditor.class.getSimpleName(); - private static final int MENU_SAVE = Menu.FIRST; private static final int MENU_CANCEL = Menu.FIRST + 1; - - private EditTextPreference mName; + private static final String KEY_PROFILE = "profile"; private VpnProfileEditor mProfileEditor; + private boolean mAddingProfile; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + VpnProfile p = (VpnProfile) ((savedInstanceState == null) + ? getIntent().getParcelableExtra(VpnSettings.KEY_VPN_PROFILE) + : savedInstanceState.getParcelable(KEY_PROFILE)); + mProfileEditor = getEditor(p); + mAddingProfile = TextUtils.isEmpty(p.getName()); // Loads the XML preferences file addPreferencesFromResource(R.xml.vpn_edit); - mName = (EditTextPreference) findPreference("vpn_name"); - mName.setOnPreferenceChangeListener( - new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange( - Preference pref, Object newValue) { - setName((String) newValue); - return true; - } - }); - - if (savedInstanceState == null) { - VpnProfile p = getIntent().getParcelableExtra( - VpnSettings.KEY_VPN_PROFILE); - initViewFor(p); - } + initViewFor(p); + } + + @Override + protected synchronized void onSaveInstanceState(Bundle outState) { + if (mProfileEditor == null) return; + + outState.putParcelable(KEY_PROFILE, getProfile()); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - menu.add(0, MENU_SAVE, 0, R.string.vpn_menu_save) + menu.add(0, MENU_SAVE, 0, R.string.vpn_menu_done) .setIcon(android.R.drawable.ic_menu_save); - menu.add(0, MENU_CANCEL, 0, R.string.vpn_menu_cancel) + menu.add(0, MENU_CANCEL, 0, + mAddingProfile ? R.string.vpn_menu_cancel + : R.string.vpn_menu_revert) .setIcon(android.R.drawable.ic_menu_close_clear_cancel); return true; } @@ -96,33 +95,16 @@ public class VpnEditor extends PreferenceActivity { } private void initViewFor(VpnProfile profile) { - VpnProfileEditor editor = getEditor(profile); - VpnType type = profile.getType(); - PreferenceGroup subsettings = getPreferenceScreen(); - setTitle(profile); - setName(profile.getName()); - - editor.loadPreferencesTo(subsettings); - mProfileEditor = editor; + mProfileEditor.loadPreferencesTo(getPreferenceScreen()); } private void setTitle(VpnProfile profile) { - if (Util.isNullOrEmpty(profile.getName())) { - setTitle(String.format(getString(R.string.vpn_edit_title_add), - profile.getType().getDisplayName())); - } else { - setTitle(String.format(getString(R.string.vpn_edit_title_edit), - profile.getType().getDisplayName())); - } - } - - private void setName(String newName) { - newName = (newName == null) ? "" : newName.trim(); - mName.setText(newName); - mName.setSummary(Util.isNullOrEmpty(newName) - ? getString(R.string.vpn_name_summary) - : newName); + String formatString = mAddingProfile + ? getString(R.string.vpn_edit_title_add) + : getString(R.string.vpn_edit_title_edit); + setTitle(String.format(formatString, + profile.getType().getDisplayName())); } /** @@ -130,24 +112,18 @@ public class VpnEditor extends PreferenceActivity { * @return true if the result is successfully set */ private boolean validateAndSetResult() { - String errorMsg = null; - if (Util.isNullOrEmpty(mName.getText())) { - errorMsg = getString(R.string.vpn_error_name_empty); - } else { - errorMsg = mProfileEditor.validate(this); - } + String errorMsg = mProfileEditor.validate(); if (errorMsg != null) { Util.showErrorMessage(this, errorMsg); return false; } - setResult(mProfileEditor.getProfile()); + setResult(getProfile()); return true; } private void setResult(VpnProfile p) { - p.setName(mName.getText()); p.setId(Util.base64Encode(p.getName().getBytes())); Intent intent = new Intent(this, VpnSettings.class); intent.putExtra(VpnSettings.KEY_VPN_PROFILE, (Parcelable) p); @@ -155,17 +131,26 @@ public class VpnEditor extends PreferenceActivity { } private VpnProfileEditor getEditor(VpnProfile p) { - if (p instanceof L2tpIpsecProfile) { - return new L2tpIpsecEditor((L2tpIpsecProfile) p); - } else { - return new VpnProfileEditor(p); + switch (p.getType()) { + case L2TP_IPSEC: + return new L2tpIpsecEditor((L2tpIpsecProfile) p); + + case L2TP_IPSEC_PSK: + case L2TP: + return new L2tpEditor((L2tpProfile) p); + + default: + return new VpnProfileEditor(p); } } private void showCancellationConfirmDialog() { new AlertDialog.Builder(this) - .setTitle(R.string.vpn_error_title) - .setMessage(R.string.vpn_confirm_profile_cancellation) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(mAddingProfile + ? R.string.vpn_confirm_add_profile_cancellation + : R.string.vpn_confirm_edit_profile_cancellation) .setPositiveButton(R.string.vpn_yes_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int w) { @@ -175,4 +160,8 @@ public class VpnEditor extends PreferenceActivity { .setNegativeButton(R.string.vpn_mistake_button, null) .show(); } + + private VpnProfile getProfile() { + return mProfileEditor.getProfile(); + } } diff --git a/src/com/android/settings/vpn/VpnProfileEditor.java b/src/com/android/settings/vpn/VpnProfileEditor.java index a245263..b679bcb 100644 --- a/src/com/android/settings/vpn/VpnProfileEditor.java +++ b/src/com/android/settings/vpn/VpnProfileEditor.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. @@ -20,14 +20,21 @@ import com.android.settings.R; import android.content.Context; import android.net.vpn.VpnProfile; +import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; +import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceGroup; +import android.text.TextUtils; +import android.text.method.PasswordTransformationMethod; /** * The common class for editing {@link VpnProfile}. */ class VpnProfileEditor { + private static final String KEY_VPN_NAME = "vpn_name"; + + private EditTextPreference mName; private EditTextPreference mServerName; private EditTextPreference mDomainSuffices; private VpnProfile mProfile; @@ -47,6 +54,18 @@ class VpnProfileEditor { */ public void loadPreferencesTo(PreferenceGroup subpanel) { Context c = subpanel.getContext(); + + mName = (EditTextPreference) subpanel.findPreference(KEY_VPN_NAME); + mName.setOnPreferenceChangeListener( + new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange( + Preference pref, Object newValue) { + setName((String) newValue); + return true; + } + }); + setName(getProfile().getName()); + subpanel.addPreference(createServerNamePreference(c)); loadExtraPreferencesTo(subpanel); subpanel.addPreference(createDomainSufficesPreference(c)); @@ -65,60 +84,135 @@ class VpnProfileEditor { * @return an error message that is ready to be displayed in a dialog; or * null if all the inputs are valid */ - public String validate(Context c) { - return (Util.isNullOrEmpty(mServerName.getText()) - ? c.getString(R.string.vpn_error_server_name_empty) - : null); + public String validate() { + String result = validate(mName, R.string.vpn_name); + return ((result != null) + ? result + : 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. */ protected EditTextPreference createDomainSufficesPreference(Context c) { - EditTextPreference pref = mDomainSuffices = new EditTextPreference(c); - pref.setTitle(R.string.vpn_dns_search_list_title); - pref.setDialogTitle(R.string.vpn_dns_search_list_title); - pref.setPersistent(true); - pref.setText(mProfile.getDomainSuffices()); - pref.setSummary(mProfile.getDomainSuffices()); - pref.setOnPreferenceChangeListener( + mDomainSuffices = createEditTextPreference(c, + R.string.vpn_dns_search_list_title, + R.string.vpn_dns_search_list, + mProfile.getDomainSuffices(), new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange( Preference pref, Object newValue) { String v = ((String) newValue).trim(); mProfile.setDomainSuffices(v); - pref.setSummary(checkNull(v, pref.getContext())); + setSummary(pref, R.string.vpn_dns_search_list, v, false); return true; } }); - return pref; + return mDomainSuffices; } private Preference createServerNamePreference(Context c) { - EditTextPreference serverName = mServerName = new EditTextPreference(c); - String title = c.getString(R.string.vpn_server_name_title); - serverName.setTitle(title); - serverName.setDialogTitle(title); - serverName.setSummary(checkNull(mProfile.getServerName(), c)); - serverName.setText(mProfile.getServerName()); - serverName.setPersistent(true); - serverName.setOnPreferenceChangeListener( + mServerName = createEditTextPreference(c, + R.string.vpn_vpn_server_title, + R.string.vpn_vpn_server, + mProfile.getServerName(), new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange( Preference pref, Object newValue) { String v = ((String) newValue).trim(); mProfile.setServerName(v); - pref.setSummary(checkNull(v, pref.getContext())); + setSummary(pref, R.string.vpn_vpn_server, v); return true; } }); return mServerName; } + protected EditTextPreference createEditTextPreference(Context c, int titleId, + int prefNameId, String value, + Preference.OnPreferenceChangeListener listener) { + EditTextPreference pref = new EditTextPreference(c); + pref.setTitle(titleId); + pref.setDialogTitle(titleId); + setSummary(pref, prefNameId, value); + pref.setText(value); + pref.setPersistent(true); + pref.setOnPreferenceChangeListener(listener); + return pref; + } + + protected EditTextPreference createSecretPreference(Context c, int titleId, + int fieldNameId, String value, + Preference.OnPreferenceChangeListener listener) { + EditTextPreference pref = new EditTextPreference(c); + pref.setTitle(titleId); + pref.setDialogTitle(titleId); + pref.getEditText().setTransformationMethod( + new PasswordTransformationMethod()); + pref.setText(value); + setSecretSummary(pref, fieldNameId, value); + pref.setPersistent(true); + pref.setOnPreferenceChangeListener(listener); + return pref; + } + + protected String validate(Preference pref, int fieldNameId) { + Context c = pref.getContext(); + String value = (pref instanceof EditTextPreference) + ? ((EditTextPreference) pref).getText() + : ((ListPreference) pref).getValue(); + String formatString = (pref instanceof EditTextPreference) + ? c.getString(R.string.vpn_error_miss_entering) + : c.getString(R.string.vpn_error_miss_selecting); + return (TextUtils.isEmpty(value) + ? String.format(formatString, c.getString(fieldNameId)) + : null); + } + + protected void setSummary(Preference pref, int fieldNameId, String v) { + setSummary(pref, fieldNameId, v, true); + } + + protected void setSummary(Preference pref, int fieldNameId, String v, + boolean required) { + Context c = pref.getContext(); + String formatString = required + ? c.getString(R.string.vpn_field_not_set) + : c.getString(R.string.vpn_field_not_set_optional); + pref.setSummary(TextUtils.isEmpty(v) + ? String.format(formatString, c.getString(fieldNameId)) + : v); + } + + protected void setSecretSummary(Preference pref, int fieldNameId, + String value) { + Context c = pref.getContext(); + String formatString = TextUtils.isEmpty(value) + ? c.getString(R.string.vpn_field_not_set) + : c.getString(R.string.vpn_field_is_set); + pref.setSummary(String.format(formatString, c.getString(fieldNameId))); + } + + protected void setSecretTitle( + CheckBoxPreference pref, int fieldNameId, boolean enabled) { + Context c = pref.getContext(); + String formatString = enabled + ? c.getString(R.string.vpn_disable_field) + : c.getString(R.string.vpn_enable_field); + pref.setTitle(String.format(formatString, c.getString(fieldNameId))); + } - String checkNull(String value, Context c) { - return ((value != null && value.length() > 0) - ? value - : c.getString(R.string.vpn_not_set)); - } + private void setName(String newName) { + newName = (newName == null) ? "" : newName.trim(); + mName.setText(newName); + getProfile().setName(newName); + setSummary(mName, R.string.vpn_name, newName); + } } diff --git a/src/com/android/settings/vpn/VpnSettings.java b/src/com/android/settings/vpn/VpnSettings.java index 06f0e25..1603998 100644 --- a/src/com/android/settings/vpn/VpnSettings.java +++ b/src/com/android/settings/vpn/VpnSettings.java @@ -29,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.ConditionVariable; import android.os.Parcel; import android.os.Parcelable; import android.preference.Preference; @@ -37,6 +38,7 @@ import android.preference.PreferenceCategory; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; import android.preference.Preference.OnPreferenceClickListener; +import android.text.TextUtils; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; @@ -53,9 +55,13 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** * The preference activity for configuring VPN settings. @@ -87,6 +93,9 @@ public class VpnSettings extends PreferenceActivity implements private static final int CONTEXT_MENU_DELETE_ID = ContextMenu.FIRST + 3; private static final int CONNECT_BUTTON = DialogInterface.BUTTON1; + private static final int OK_BUTTON = DialogInterface.BUTTON1; + + private static final int DIALOG_CONNECT = 0; private PreferenceScreen mAddVpn; private PreferenceCategory mVpnListContainer; @@ -102,6 +111,7 @@ public class VpnSettings extends PreferenceActivity implements // actor engaged in connecting private VpnProfileActor mConnectingActor; + private boolean mStateSaved = false; private VpnManager mVpnManager = new VpnManager(this); @@ -110,6 +120,8 @@ public class VpnSettings extends PreferenceActivity implements private boolean mConnectingError; + private StatusChecker mStatusChecker = new StatusChecker(); + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -133,16 +145,30 @@ public class VpnSettings extends PreferenceActivity implements // listen to vpn connectivity event mVpnManager.registerConnectivityReceiver(mConnectivityReceiver); + + String profileName = (savedInstanceState == null) + ? null + : savedInstanceState.getString(STATE_ACTIVE_ACTOR); + mStateSaved = !TextUtils.isEmpty(profileName); + retrieveVpnListFromStorage(); + if (mStateSaved) { + mConnectingActor = + getActor(mVpnPreferenceMap.get(profileName).mProfile); + } else { + checkVpnConnectionStatusInBackground(); + } + } + + @Override + public void onPause() { + super.onPause(); + mStatusChecker.onPause(); } @Override public void onResume() { super.onResume(); - - if ((mVpnProfileList == null) || mVpnProfileList.isEmpty()) { - retrieveVpnListFromStorage(); - checkVpnConnectionStatusInBackground(); - } + mStatusChecker.onResume(); } @Override @@ -154,17 +180,6 @@ public class VpnSettings extends PreferenceActivity implements } @Override - protected void onRestoreInstanceState(final Bundle savedState) { - String profileName = savedState.getString(STATE_ACTIVE_ACTOR); - if (Util.isNullOrEmpty(profileName)) return; - - retrieveVpnListFromStorage(); - - VpnProfile p = mVpnPreferenceMap.get(profileName).mProfile; - mConnectingActor = getActor(p); - } - - @Override protected void onDestroy() { super.onDestroy(); unregisterForContextMenu(getListView()); @@ -173,8 +188,19 @@ public class VpnSettings extends PreferenceActivity implements @Override protected Dialog onCreateDialog (int id) { + switch (id) { + case DIALOG_CONNECT: + return createConnectDialog(); + + default: + return null; + } + } + + private Dialog createConnectDialog() { if (mConnectingActor == null) { Log.e(TAG, "no connecting actor to create the dialog"); + return null; } String name = (mConnectingActor == null) ? getString(R.string.vpn_default_profile_name) @@ -185,7 +211,7 @@ public class VpnSettings extends PreferenceActivity implements name)) .setPositiveButton(getString(R.string.vpn_connect_button), this) - .setNegativeButton(getString(R.string.vpn_cancel_button), + .setNegativeButton(getString(android.R.string.cancel), this) .create(); return d; @@ -193,7 +219,10 @@ public class VpnSettings extends PreferenceActivity implements @Override protected void onPrepareDialog (int id, Dialog dialog) { - if (mConnectingActor != null) { + if (mStateSaved) { + mStateSaved = false; + super.onPrepareDialog(id, dialog); + } else if (mConnectingActor != null) { mConnectingActor.updateConnectView(dialog); } } @@ -214,7 +243,8 @@ public class VpnSettings extends PreferenceActivity implements (isIdle || (state == VpnState.DISCONNECTING)); 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) + menu.add(0, CONTEXT_MENU_DISCONNECT_ID, 0, + R.string.vpn_menu_disconnect) .setEnabled(state == VpnState.CONNECTED); menu.add(0, CONTEXT_MENU_EDIT_ID, 0, R.string.vpn_menu_edit) .setEnabled(isNotConnect); @@ -272,7 +302,8 @@ public class VpnSettings extends PreferenceActivity implements if (checkDuplicateName(p, index)) { final VpnProfile profile = p; Util.showErrorMessage(this, String.format( - getString(R.string.vpn_error_duplicate_name), p.getName()), + getString(R.string.vpn_error_duplicate_name), + p.getName()), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int w) { startVpnEditor(profile); @@ -289,7 +320,8 @@ public class VpnSettings extends PreferenceActivity implements } else { replaceProfile(index, p); Util.showShortToastMessage(this, String.format( - getString(R.string.vpn_profile_replaced), p.getName())); + getString(R.string.vpn_profile_replaced), + p.getName())); } } catch (IOException e) { final VpnProfile profile = p; @@ -308,7 +340,7 @@ public class VpnSettings extends PreferenceActivity implements // Called when the buttons on the connect dialog are clicked. //@Override public synchronized void onClick(DialogInterface dialog, int which) { - dismissDialog(0); + dismissDialog(DIALOG_CONNECT); if (which == CONNECT_BUTTON) { Dialog d = (Dialog) dialog; String error = mConnectingActor.validateInputs(d); @@ -319,14 +351,15 @@ public class VpnSettings extends PreferenceActivity implements } 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)) + .setTitle(android.R.string.dialog_alert_title) + .setIcon(android.R.drawable.ic_dialog_alert) + .setMessage(String.format(getString( + R.string.vpn_error_miss_entering), error)) .setPositiveButton(R.string.vpn_back_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - showDialog(0); + showDialog(DIALOG_CONNECT); } }) .show(); @@ -357,12 +390,27 @@ public class VpnSettings extends PreferenceActivity implements } // position: position in mVpnProfileList - private void deleteProfile(int position) { + private void deleteProfile(final int position) { if ((position < 0) || (position >= mVpnProfileList.size())) return; - VpnProfile p = mVpnProfileList.remove(position); - VpnPreference pref = mVpnPreferenceMap.remove(p.getName()); - mVpnListContainer.removePreference(pref); - removeProfileFromStorage(p); + DialogInterface.OnClickListener onClickListener = + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + if (which == OK_BUTTON) { + VpnProfile p = mVpnProfileList.remove(position); + VpnPreference pref = + mVpnPreferenceMap.remove(p.getName()); + mVpnListContainer.removePreference(pref); + removeProfileFromStorage(p); + } + } + }; + new AlertDialog.Builder(this) + .setTitle(android.R.string.dialog_alert_title) + .setMessage(R.string.vpn_confirm_profile_deletion) + .setPositiveButton(android.R.string.ok, onClickListener) + .setNegativeButton(R.string.vpn_no_button, onClickListener) + .show(); } private void addProfile(VpnProfile p) throws IOException { @@ -396,6 +444,8 @@ public class VpnSettings extends PreferenceActivity implements throw new RuntimeException("inconsistent state!"); } + // TODO: call saveSecret(String) after keystore is available + // Copy config files and remove the old ones if they are in different // directories. if (Util.copyFiles(getProfileDir(oldProfile), getProfileDir(p))) { @@ -423,9 +473,10 @@ public class VpnSettings extends PreferenceActivity implements VpnPreference pref = mVpnPreferenceMap.get(p.getName()); switch (p.getState()) { case IDLE: - mConnectingActor = getActor(new VpnProfileWrapper(p)); + mConnectingActor = getActor(p); if (mConnectingActor.isConnectDialogNeeded()) { - showDialog(0); + removeDialog(DIALOG_CONNECT); + showDialog(DIALOG_CONNECT); } else { changeState(p, VpnState.CONNECTING); mConnectingActor.connect(null); @@ -487,7 +538,7 @@ public class VpnSettings extends PreferenceActivity implements private void showReconnectDialog(final VpnProfile p) { new AlertDialog.Builder(this) - .setTitle(R.string.vpn_error_title) + .setTitle(android.R.string.dialog_alert_title) .setMessage(R.string.vpn_confirm_reconnect) .setPositiveButton(R.string.vpn_yes_button, new DialogInterface.OnClickListener() { @@ -522,11 +573,11 @@ public class VpnSettings extends PreferenceActivity implements } } - private String getProfileDir(VpnProfile p) { + static String getProfileDir(VpnProfile p) { return PROFILES_ROOT + p.getId(); } - private void saveProfileToStorage(VpnProfile p) throws IOException { + static void saveProfileToStorage(VpnProfile p) throws IOException { File f = new File(getProfileDir(p)); if (!f.exists()) f.mkdirs(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream( @@ -541,7 +592,8 @@ public class VpnSettings extends PreferenceActivity implements private void retrieveVpnListFromStorage() { mVpnPreferenceMap = new LinkedHashMap<String, VpnPreference>(); - mVpnProfileList = new ArrayList<VpnProfile>(); + mVpnProfileList = Collections.synchronizedList( + new ArrayList<VpnProfile>()); mVpnListContainer.removeAll(); File root = new File(PROFILES_ROOT); @@ -566,13 +618,7 @@ public class VpnSettings extends PreferenceActivity implements } private void checkVpnConnectionStatusInBackground() { - new Thread(new Runnable() { - public void run() { - for (VpnProfile p : mVpnProfileList) { - getActor(p).checkStatus(); - } - } - }).start(); + mStatusChecker.check(mVpnProfileList); } // A sanity check. Returns true if the profile directory name and profile ID @@ -661,99 +707,50 @@ public class VpnSettings extends PreferenceActivity implements } } - // 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) { - } + // managing status check in a background thread + private class StatusChecker { + private Set<VpnProfile> mQueue = new HashSet<VpnProfile>(); + private boolean mPaused; + private ConditionVariable mThreadCv = new ConditionVariable(); - @Override - public String getRouteList() { - return mProfile.getRouteList(); + void onPause() { + mPaused = true; + mThreadCv.block(); // until the checking thread is over } - @Override - public void setState(VpnState state) { + synchronized void onResume() { + mPaused = false; + start(); } - @Override - public VpnState getState() { - return mProfile.getState(); + synchronized void check(List<VpnProfile> list) { + boolean started = !mQueue.isEmpty(); + for (VpnProfile p : list) { + if (!mQueue.contains(p)) mQueue.add(p); + } + if (!started) start(); } - @Override - public boolean isIdle() { - return mProfile.isIdle(); + private synchronized VpnProfile next() { + if (mPaused || mQueue.isEmpty()) return null; + Iterator<VpnProfile> i = mQueue.iterator(); + VpnProfile p = i.next(); + i.remove(); + return p; } - @Override - public VpnType getType() { - return mProfile.getType(); + private void start() { + mThreadCv.close(); + new Thread(new Runnable() { + public void run() { + while (true) { + VpnProfile p = next(); + if (p == null) break; + getActor(p).checkStatus(); + } + mThreadCv.open(); + } + }).start(); } } } diff --git a/src/com/android/settings/vpn/VpnTypeSelection.java b/src/com/android/settings/vpn/VpnTypeSelection.java index 0448106..e74fb43 100644 --- a/src/com/android/settings/vpn/VpnTypeSelection.java +++ b/src/com/android/settings/vpn/VpnTypeSelection.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. @@ -54,10 +54,13 @@ public class VpnTypeSelection extends PreferenceActivity { PreferenceScreen root = getPreferenceScreen(); for (VpnType t : VpnManager.getSupportedVpnTypes()) { String displayName = t.getDisplayName(); - mTypeMap.put(displayName, t); + String message = String.format( + getString(R.string.vpn_edit_title_add), displayName); + mTypeMap.put(message, t); Preference pref = new Preference(this); - pref.setTitle(displayName); + pref.setTitle(message); + pref.setSummary(t.getDescription()); root.addPreference(pref); } } |