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
This commit is contained in:
Hung-ying Tyan
2009-06-26 14:24:50 +08:00
parent 386278a338
commit e7565f3c48
15 changed files with 660 additions and 369 deletions

View File

@@ -1,13 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 The Android Open Source Project
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
android:layout_height="fill_parent"
android:padding="10dip">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_marginLeft="@dimen/vpn_connect_margin_left"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="@+id/username_str"
@@ -15,32 +33,28 @@
android:layout_height="wrap_content"
android:textSize="@dimen/vpn_connect_normal_text_size"
android:gravity="right"
android:layout_marginRight="@dimen/vpn_connect_input_box_padding"
android:layout_marginRight="@dimen/vpn_connect_margin_right"
android:text="@string/vpn_username_colon" />
<EditText android:id="@+id/username_value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/vpn_connect_margin_right"
android:singleLine="True"/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_marginLeft="@dimen/vpn_connect_margin_left"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10sp">
android:layout_height="wrap_content">
<TextView android:id="@+id/password_str"
android:layout_width="@dimen/vpn_connect_input_box_label_width"
android:layout_height="wrap_content"
android:textSize="@dimen/vpn_connect_normal_text_size"
android:gravity="right"
android:layout_marginRight="@dimen/vpn_connect_input_box_padding"
android:layout_marginRight="@dimen/vpn_connect_margin_right"
android:text="@string/vpn_password_colon" />
<EditText android:id="@+id/password_value"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/vpn_connect_margin_right"
android:password="True"
android:singleLine="True"/>
</LinearLayout>
@@ -48,7 +62,8 @@
<CheckBox android:id="@+id/save_username"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/vpn_connect_margin_left"
android:layout_marginLeft="66dip"
android:text="@string/vpn_save_username" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="vpn_connect_margin_left">5sp</dimen>
<dimen name="vpn_connect_margin_right">5sp</dimen>
<dimen name="vpn_connect_margin_right">10sp</dimen>
<dimen name="vpn_connect_normal_text_size">16sp</dimen>
<dimen name="vpn_connect_input_box_label_width">90sp</dimen>
<dimen name="vpn_connect_input_box_width">200sp</dimen>
<dimen name="vpn_connect_input_box_padding">5sp</dimen>
</resources>

View File

@@ -1817,74 +1817,150 @@ found in the list of installed applications.</string>
<string name="vpn_settings_activity_title">VPN settings</string>
<string name="vpn_username_colon">User name:</string>
<!-- Title of VPN connect dialog -->
<string name="vpn_connect_to">Connect to %s</string>
<!-- In VPN connect dialog, for inputing username and password -->
<string name="vpn_username_colon">Username:</string>
<string name="vpn_password_colon">Password:</string>
<string name="vpn_username">User name</string>
<string name="vpn_password">Password</string>
<string name="vpn_username">username</string>
<string name="vpn_password">password</string>
<!-- In VPN connect dialog where user may check to remember the username entered -->
<string name="vpn_save_username">Remember me</string>
<string name="vpn_you_miss_a_field">You missed a field!</string>
<string name="vpn_please_fill_up">Please fill up \"%s\".</string>
<string name="vpn_connect_button">Connect</string>
<string name="vpn_cancel_button">Cancel</string>
<string name="vpn_yes_button">Yes</string>
<string name="vpn_no_button">No</string>
<string name="vpn_back_button">Back</string>
<string name="vpn_mistake_button">No, it's a mistake</string>
<string name="vpn_menu_save">Save</string>
<!-- Edit VPN screen menu option to discard the user's changes for this VPN -->
<string name="vpn_menu_cancel">Discard</string>
<string name="vpn_menu_connect">Connect</string>
<string name="vpn_menu_disconnect">Disconnect</string>
<string name="vpn_menu_edit">Edit</string>
<string name="vpn_menu_delete">Delete</string>
<string name="vpn_menu_done">Save</string>
<string name="vpn_menu_cancel">Cancel</string>
<string name="vpn_menu_revert">Revert</string>
<string name="vpn_menu_connect">Connect to network</string>
<string name="vpn_menu_disconnect">Disconnect network</string>
<string name="vpn_menu_edit">Edit network</string>
<string name="vpn_menu_delete">Delete network</string>
<!-- VPN error dialog title -->
<string name="vpn_error_title">Attention</string>
<string name="vpn_error_name_empty">VPN Name cannot be empty.</string>
<string name="vpn_error_server_name_empty">The Server Name field cannot be empty.</string>
<string name="vpn_error_duplicate_name">The VPN Name \'%s\' already exists. Find another name.</string>
<string name="vpn_error_user_certificate_not_selected">Need to select a user certificate.</string>
<string name="vpn_error_ca_certificate_not_selected">Need to select a CA certificate.</string>
<string name="vpn_error_userkey_not_selected">Need to select a userkey.</string>
<string name="vpn_confirm_profile_cancellation">Are you sure you don\'t want to create this profile?</string>
<!-- VPN error dialog messages -->
<string name="vpn_error_miss_entering">You must enter a %s.</string>
<string name="vpn_error_miss_selecting">You must select a %s.</string>
<string name="vpn_error_duplicate_name">The VPN name \'%s\' already exists. Find another name.</string>
<string name="vpn_confirm_profile_deletion">Are you sure you want to delete this VPN?</string>
<string name="vpn_confirm_add_profile_cancellation">Are you sure you don\'t want to create this profile?</string>
<string name="vpn_confirm_edit_profile_cancellation">Are you sure you want to discard the changes made to this profile?</string>
<string name="vpn_confirm_reconnect">The previous connection attempt failed. Do you want to try again?</string>
<string name="vpn_add_new_vpn">Add new VPN</string>
<string name="vpn_edit_title_add">Add new %s VPN</string>
<string name="vpn_edit_title_edit">Edit %s VPN</string>
<string name="vpn_type_title">Select VPN type</string>
<string name="vpns">VPN networks</string>
<!-- EditTextPreference summary text when no value has been set -->
<string name="vpn_not_set">Click to set the value</string>
<!-- EditTextPreference summary text when VPN is connecting -->
<!-- VPN type selection activity title -->
<string name="vpn_type_title">Add VPN</string>
<!-- "Add VPN" preference title -->
<string name="vpn_add_new_vpn">Add VPN</string>
<!-- VPN profile editor title when adding a new profile -->
<string name="vpn_edit_title_add">Add %s VPN</string>
<!-- VPN profile editor title when editing an existing profile -->
<string name="vpn_edit_title_edit">%s details</string>
<!-- Preference group title for a list of VPN profiles -->
<string name="vpns">VPNs</string>
<!-- Preference summary text when VPN is connecting -->
<string name="vpn_connecting">Connecting...</string>
<!-- EditTextPreference summary text when VPN is disconnecting -->
<!-- Preference summary text when VPN is disconnecting -->
<string name="vpn_disconnecting">Disconnecting...</string>
<!-- EditTextPreference summary text when VPN is connected -->
<!-- Preference summary text when VPN is connected -->
<string name="vpn_connected">Connected</string>
<!-- EditTextPreference summary text when VPN is not connected -->
<string name="vpn_connect_hint">Select to connect</string>
<!-- dialog title when asking for username and password -->
<string name="vpn_connect_to">Connect to %s</string>
<!-- Preference summary text when VPN is not connected -->
<string name="vpn_connect_hint">Connect to network</string>
<string name="vpn_default_profile_name">nowhere</string>
<string name="vpn_name">VPN Name</string>
<string name="vpn_name_summary">Give a name to this VPN</string>
<!-- Name of a VPN profile -->
<string name="vpn_name">VPN name</string>
<string name="vpn_profile_added">'%s' is added</string>
<string name="vpn_profile_replaced">Changes are made to '%s'</string>
<!-- Toast message shown when a profile is added -->
<string name="vpn_profile_added">&#39;%s&#39; is added</string>
<!-- Toast message shown when changes of a profile is saved -->
<string name="vpn_profile_replaced">Changes are made to &#39;%s&#39;</string>
<string name="vpn_user_certificate_title">User Certificate</string>
<string name="vpn_ca_certificate_title">CA Certificate</string>
<string name="vpn_userkey_title">User Key</string>
<string name="vpn_server_name_title">Server Name</string>
<string name="vpn_dns_search_list_title">DNS Search List</string>
<!-- Preference title -->
<string name="vpn_user_certificate_title">Set user certificate</string>
<!-- Complete term -->
<string name="vpn_user_certificate">User certificate</string>
<string name="vpn_settings_category">VPN</string>
<string name="vpn_settings_title">VPN</string>
<string name="vpn_settings_summary">Set up &amp; manage VPN configurations, connections</string>
<!-- Preference title -->
<string name="vpn_ca_certificate_title">Set CA certificate</string>
<!-- Complete term -->
<string name="vpn_ca_certificate">Certificate authority (CA) certificate</string>
<!-- Preference title -->
<string name="vpn_l2tp_secret_string_title">Set L2TP secret</string>
<!-- Complete term -->
<string name="vpn_l2tp_secret">L2TP secret</string>
<!-- Preference title -->
<string name="vpn_psk_title">Set IPSec pre-shared key</string>
<!-- Complete term -->
<string name="vpn_psk">IPSec pre-shared key</string>
<!-- Preference title -->
<string name="vpn_vpn_server_title">Set VPN server</string>
<!-- Complete term -->
<string name="vpn_vpn_server">VPN server</string>
<!-- Dialog title for setting VPN server name -->
<string name="vpn_vpn_server_dialog_title">VPN server name</string>
<!-- Preference title -->
<string name="vpn_dns_search_list_title">DNS search domains</string>
<!-- Complete term -->
<string name="vpn_dns_search_list">DNS search domains</string>
<!-- Summary text to hint that the value is set -->
<string name="vpn_field_is_set">%s is set</string>
<!-- Summary text to hint that the value is not set -->
<string name="vpn_field_not_set">%s not set</string>
<!-- Summary text to hint that the value is not set but it's not required-->
<string name="vpn_field_not_set_optional">%s not set (optional)</string>
<!-- CheckBoxPreference title to enable something -->
<string name="vpn_enable_field">Enable %s</string>
<!-- CheckBoxPreference title to disable something -->
<string name="vpn_disable_field">Disable %s</string>
<!-- CheckBoxPreference summary to hint that something is enabled -->
<string name="vpn_is_enabled">%s is enabled</string>
<!-- CheckBoxPreference summary to hint that something is disabled -->
<string name="vpn_is_disabled">%s is disabled</string>
<!-- Title of preference to enter the VPN settings activity -->
<string name="vpn_settings_title">VPN settings</string>
<!-- Summary of preference to enter the VPN settings activity -->
<string name="vpn_settings_summary">Set up &amp; manage Virtual Private Networks (VPNs)</string>
<!-- Title of preference group for credential storage settings -->
<string name="cstor_settings_category">Credential storage</string>
<!-- Title of preference to enable/dislable access to credential storage -->
<string name="cstor_access_title">Use secure credentials</string>
<!-- Summary of preference to enable/dislable access to credential storage -->
<string name="cstor_access_summary">Allow applications to access secure certificates and other credentials</string>
<!-- Title of preference to set storage password -->
<string name="cstor_set_passwd_title">Set storage password</string>
<!-- Summary of preference to set storage password -->
<string name="cstor_set_passwd_summary">Set or change the secure credential storage password</string>
<!-- Title of dialog to set storage password -->
<string name="cstor_set_passwd_dialog_title">Set password</string>
<!-- Title of preference to reset storage -->
<string name="cstor_reset_title">Clear storage</string>
<!-- Summary of preference to reset storage -->
<string name="cstor_reset_summary">Clear credential storage of all contents and reset its password</string>
<string name="cstor_reset_hint">Are you sure you want to delete all certificates and other stored credentials and reset the password?</string>
<!-- Description for the old-password input box -->
<string name="cstor_old_password">Current password:</string>
<!-- Description for the new-password input box -->
<string name="cstor_new_password">New password:</string>
<!-- Description for the confirm-new-password input box -->
<string name="cstor_confirm_password">Confirm new password:</string>
<!-- Description when user set up the storage for the very first time -->
<string name="cstor_first_time_hint">You must set a password for credential storage before you can store secure certificates and other credentials in it.</string>
<!-- Sound settings screen, setting check box label -->
<string name="emergency_tone_title">Emergency tone</string>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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,10 +18,9 @@
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
<EditTextPreference
android:key="vpn_name"
android:title="@string/vpn_name"
android:dialogTitle="@string/vpn_name"
android:key="vpn_name"
android:summary="@string/vpn_name_summary"
android:singleLine="true"/>
</PreferenceScreen>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 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.

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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)));
}
}

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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);
}
@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),
String formatString = mAddingProfile
? getString(R.string.vpn_edit_title_add)
: getString(R.string.vpn_edit_title_edit);
setTitle(String.format(formatString,
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);
}
/**
@@ -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) {
switch (p.getType()) {
case L2TP_IPSEC:
return new L2tpIpsecEditor((L2tpIpsecProfile) p);
} else {
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();
}
}

View File

@@ -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;
}
String checkNull(String value, Context c) {
return ((value != null && value.length() > 0)
? value
: c.getString(R.string.vpn_not_set));
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)));
}
private void setName(String newName) {
newName = (newName == null) ? "" : newName.trim();
mName.setText(newName);
getProfile().setName(newName);
setSummary(mName, R.string.vpn_name, newName);
}
}

View File

@@ -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
@@ -153,17 +179,6 @@ public class VpnSettings extends PreferenceActivity implements
mConnectingActor.getProfile().getName());
}
@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();
@@ -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,13 +390,28 @@ 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;
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());
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 {
saveProfileToStorage(p);
@@ -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;
// 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();
VpnProfileWrapper(VpnProfile p) {
mProfile = p;
void onPause() {
mPaused = true;
mThreadCv.block(); // until the checking thread is over
}
@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
}
}
synchronized void onResume() {
mPaused = false;
start();
}
@Override
public String getSavedUsername() {
return mProfile.getSavedUsername();
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 void writeToParcel(Parcel parcel, int flags) {
mProfile.writeToParcel(parcel, flags);
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 void setName(String name) {
private void start() {
mThreadCv.close();
new Thread(new Runnable() {
public void run() {
while (true) {
VpnProfile p = next();
if (p == null) break;
getActor(p).checkStatus();
}
@Override
public String getName() {
return mProfile.getName();
mThreadCv.open();
}
@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();
}).start();
}
}
}

View File

@@ -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);
}
}