OSDN Git Service

Add L2TP secret, L2TP/IPSec PSK support. Fix screen orientation.
authorHung-ying Tyan <tyanh@google.com>
Fri, 26 Jun 2009 06:24:50 +0000 (14:24 +0800)
committerHung-ying Tyan <tyanh@google.com>
Fri, 26 Jun 2009 06:24:50 +0000 (14:24 +0800)
* 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

15 files changed:
res/layout/vpn_connect_dialog_view.xml
res/values/dimens.xml
res/values/strings.xml
res/xml/vpn_edit.xml
res/xml/vpn_settings.xml
res/xml/vpn_type.xml
src/com/android/settings/SecuritySettings.java
src/com/android/settings/vpn/AuthenticationActor.java
src/com/android/settings/vpn/L2tpEditor.java [new file with mode: 0644]
src/com/android/settings/vpn/L2tpIpsecEditor.java
src/com/android/settings/vpn/Util.java
src/com/android/settings/vpn/VpnEditor.java
src/com/android/settings/vpn/VpnProfileEditor.java
src/com/android/settings/vpn/VpnSettings.java
src/com/android/settings/vpn/VpnTypeSelection.java

index be66c2f..062f881 100644 (file)
@@ -1,54 +1,69 @@
 <?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"
-        android:orientation="vertical"
+     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="fill_parent">
+        android:layout_height="wrap_content">
 
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-            android:orientation="horizontal"
-            android:layout_marginLeft="@dimen/vpn_connect_margin_left"
+            android:orientation="vertical"
             android:layout_width="fill_parent"
-            android:layout_height="wrap_content">
-        <TextView android:id="@+id/username_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:text="@string/vpn_username_colon" />
-        <EditText android:id="@+id/username_value" 
+            android:layout_height="fill_parent"
+            android:padding="10dip">
+
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="horizontal"
                 android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginRight="@dimen/vpn_connect_margin_right"
-                android:singleLine="True"/>
-    </LinearLayout>
+                android:layout_height="wrap_content">
+            <TextView android:id="@+id/username_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_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: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">
-        <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:text="@string/vpn_password_colon" />
-        <EditText android:id="@+id/password_value" 
+        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:orientation="horizontal"
                 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>
+                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_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:password="True"
+                    android:singleLine="True"/>
+        </LinearLayout>
 
-    <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:text="@string/vpn_save_username" />
+        <CheckBox android:id="@+id/save_username"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="66dip"
+                android:text="@string/vpn_save_username" />
 
-</LinearLayout>
+    </LinearLayout>
+</ScrollView>
index 56bd60c..790f86b 100755 (executable)
@@ -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>
index b049a2a..7c6529d 100644 (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>
-
-    <!-- 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>
+    <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 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>
-    <string name="vpn_default_profile_name">nowhere</string>
+    <!-- Preference summary text when VPN is not connected -->
+    <string name="vpn_connect_hint">Connect to network</string>
 
-    <string name="vpn_name">VPN Name</string>
-    <string name="vpn_name_summary">Give a name to this VPN</string>
-
-    <string name="vpn_profile_added">'%s' is added</string>
-    <string name="vpn_profile_replaced">Changes are made to '%s'</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>
+    <string name="vpn_default_profile_name">nowhere</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>
+    <!-- Name of a VPN profile -->
+    <string name="vpn_name">VPN name</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>
+
+    <!-- Preference title -->
+    <string name="vpn_user_certificate_title">Set user certificate</string>
+    <!-- Complete term -->
+    <string name="vpn_user_certificate">User certificate</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>
index 7976242..a3cab9c 100644 (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.
         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>   
index a1a4bf9..773ae1c 100644 (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.
index c59b54a..fbc7822 100644 (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.
index ffeac34..e0d0cc1 100644 (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;
     }
 
index c56317c..af9875c 100644 (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);
+        }
+    }
 }
diff --git a/src/com/android/settings/vpn/L2tpEditor.java b/src/com/android/settings/vpn/L2tpEditor.java
new file mode 100644 (file)
index 0000000..88a1142
--- /dev/null
@@ -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)));
+    }
+}
index bb63772..e79760c 100644 (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;
-    }
 }
index d7ba1f7..e4316fd 100644 (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);
index 35c8bfb..9df98a6 100644 (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);
-        }
+        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();
+    }
 }
index a245263..b679bcb 100644 (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;
+    }
+
+    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);
+    }
 }
index 06f0e25..1603998 100644 (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
@@ -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();
         }
     }
 }
index 0448106..e74fb43 100644 (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);
         }
     }