Add VPN settings classes to Settings app.
PATCH SET 2: + Add import com.android.settings.R PATCH SET 3: + Remove @Override interface methods to be compilable by Java 1.5. PATCH SET 4: + Add import android.net.vpn.VpnManager PATCH SET 5: + Add license headers. PATCH SET 6: + Remove Constant.java and move the constants to VpnSettings. + Make AuthenticationActor implement DialogInterface's handlers. + Remove trailing spaces. PATCH SET 7: + Remove default username.
This commit is contained in:
@@ -110,6 +110,20 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".vpn.VpnSettings"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.net.vpn.SETTINGS" />
|
||||
<action android:name="android.net.vpn.INSTALL_PROFILE" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".vpn.VpnTypeSelection"></activity>
|
||||
<activity android:name=".vpn.VpnEditor"></activity>
|
||||
|
||||
<activity android:name="DateTimeSettings" android:label="@string/date_and_time"
|
||||
>
|
||||
<intent-filter>
|
||||
|
48
res/layout/vpn_connect_dialog_view.xml
Normal file
48
res/layout/vpn_connect_dialog_view.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<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"
|
||||
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_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">
|
||||
<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"
|
||||
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>
|
||||
|
||||
</LinearLayout>
|
9
res/values/dimens.xml
Executable file
9
res/values/dimens.xml
Executable file
@@ -0,0 +1,9 @@
|
||||
<?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_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>
|
@@ -1726,4 +1726,73 @@ found in the list of installed applications.</string>
|
||||
|
||||
<!-- Power Control Widget -->
|
||||
<string name="gadget_title">Power Control</string>
|
||||
|
||||
<string name="vpn_settings_activity_title">VPN settings</string>
|
||||
|
||||
<string name="vpn_username_colon">User name:</string>
|
||||
<string name="vpn_password_colon">Password:</string>
|
||||
<string name="vpn_username">User name</string>
|
||||
<string name="vpn_password">Password</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_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 -->
|
||||
<string name="vpn_connecting">Connecting...</string>
|
||||
<!-- EditTextPreference summary text when VPN is disconnecting -->
|
||||
<string name="vpn_disconnecting">Disconnecting...</string>
|
||||
<!-- EditTextPreference 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</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_settings_category">VPN</string>
|
||||
<string name="vpn_settings_title">VPN</string>
|
||||
<string name="vpn_settings_summary">Set up and manage VPN configurations, connections</string>
|
||||
</resources>
|
||||
|
27
res/xml/vpn_edit.xml
Normal file
27
res/xml/vpn_edit.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings">
|
||||
|
||||
<EditTextPreference
|
||||
android:title="@string/vpn_name"
|
||||
android:dialogTitle="@string/vpn_name"
|
||||
android:key="vpn_name"
|
||||
android:summary="@string/vpn_name_summary"
|
||||
android:singleLine="true"/>
|
||||
|
||||
</PreferenceScreen>
|
36
res/xml/vpn_settings.xml
Normal file
36
res/xml/vpn_settings.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="@string/vpn_settings_activity_title">
|
||||
|
||||
<PreferenceScreen android:key="add_new_vpn"
|
||||
android:title="@string/vpn_add_new_vpn">
|
||||
<!--intent
|
||||
android:action="android.intent.action.MAIN"
|
||||
android:targetPackage="com.android.settings.vpn"
|
||||
android:targetClass="com.android.settings.vpn.VpnEditor" /-->
|
||||
</PreferenceScreen>
|
||||
|
||||
<!--CheckBoxPreference android:key="installer_enabled"
|
||||
android:defaultValue="false"
|
||||
android:title="@string/installer_enabled"
|
||||
android:summaryOn="@string/installer_enabled_summary_on"
|
||||
android:summaryOff="@string/installer_enabled_summary_off" /-->
|
||||
|
||||
<PreferenceCategory android:key="vpn_list" android:title="@string/vpns">
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
21
res/xml/vpn_type.xml
Normal file
21
res/xml/vpn_type.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2008 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
|
||||
android:title="@string/vpn_type_title">
|
||||
|
||||
</PreferenceScreen>
|
@@ -52,6 +52,16 @@
|
||||
android:targetClass="com.android.settings.bluetooth.BluetoothSettings" />
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:title="@string/vpn_settings_title"
|
||||
android:summary="@string/vpn_settings_summary"
|
||||
android:dependency="toggle_airplane">
|
||||
<intent
|
||||
android:action="android.intent.action.MAIN"
|
||||
android:targetPackage="com.android.settings"
|
||||
android:targetClass="com.android.settings.vpn.VpnSettings" />
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
android:title="@string/network_settings_title"
|
||||
android:summary="@string/network_settings_summary"
|
||||
|
@@ -24,6 +24,7 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
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;
|
||||
@@ -160,6 +161,17 @@ public class SecuritySettings extends PreferenceActivity {
|
||||
showPassword.setPersistent(false);
|
||||
passwordsCat.addPreference(showPassword);
|
||||
|
||||
PreferenceScreen vpnPreferences = getPreferenceManager()
|
||||
.createPreferenceScreen(this);
|
||||
vpnPreferences.setTitle(R.string.vpn_settings_category);
|
||||
vpnPreferences.setIntent(new VpnManager(this).createSettingsActivityIntent());
|
||||
|
||||
PreferenceCategory vpnCat = new PreferenceCategory(this);
|
||||
vpnCat.setTitle(R.string.vpn_settings_title);
|
||||
vpnCat.setSummary(R.string.vpn_settings_summary);
|
||||
root.addPreference(vpnCat);
|
||||
vpnCat.addPreference(vpnPreferences);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
295
src/com/android/settings/vpn/AuthenticationActor.java
Normal file
295
src/com/android/settings/vpn/AuthenticationActor.java
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.app.AlertDialog;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.net.vpn.IVpnService;
|
||||
import android.net.vpn.VpnManager;
|
||||
import android.net.vpn.VpnProfile;
|
||||
import android.net.vpn.VpnState;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class AuthenticationActor implements VpnProfileActor,
|
||||
DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
|
||||
private static final String TAG = AuthenticationActor.class.getName();
|
||||
private static final int ONE_SECOND = 1000; // ms
|
||||
|
||||
private static final String STATE_IS_DIALOG_OPEN = "is_dialog_open";
|
||||
private static final String STATE_USERNAME = "username";
|
||||
private static final String STATE_PASSWORD = "password";
|
||||
|
||||
private Context mContext;
|
||||
private TextView mUsernameView;
|
||||
private TextView mPasswordView;
|
||||
|
||||
private VpnProfile mProfile;
|
||||
private View mView;
|
||||
private VpnManager mVpnManager;
|
||||
private AlertDialog mConnectDialog;
|
||||
private AlertDialog mDisconnectDialog;
|
||||
|
||||
public AuthenticationActor(Context context, VpnProfile p) {
|
||||
mContext = context;
|
||||
mProfile = p;
|
||||
mVpnManager = new VpnManager(context);
|
||||
}
|
||||
|
||||
//@Override
|
||||
public VpnProfile getProfile() {
|
||||
return mProfile;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public synchronized void connect() {
|
||||
connect("", "");
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dismissConnectDialog();
|
||||
switch (which) {
|
||||
case DialogInterface.BUTTON1: // connect
|
||||
if (validateInputs()) {
|
||||
broadcastConnectivity(VpnState.CONNECTING);
|
||||
connectInternal();
|
||||
}
|
||||
break;
|
||||
|
||||
case DialogInterface.BUTTON2: // cancel
|
||||
broadcastConnectivity(VpnState.CANCELLED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
dismissConnectDialog();
|
||||
broadcastConnectivity(VpnState.CANCELLED);
|
||||
}
|
||||
|
||||
private void connect(String username, String password) {
|
||||
Context c = mContext;
|
||||
mConnectDialog = new AlertDialog.Builder(c)
|
||||
.setView(createConnectView(username, password))
|
||||
.setTitle(c.getString(R.string.vpn_connect_to) + " "
|
||||
+ mProfile.getName())
|
||||
.setPositiveButton(c.getString(R.string.vpn_connect_button),
|
||||
this)
|
||||
.setNegativeButton(c.getString(R.string.vpn_cancel_button),
|
||||
this)
|
||||
.setOnCancelListener(this)
|
||||
.create();
|
||||
mConnectDialog.show();
|
||||
}
|
||||
|
||||
//@Override
|
||||
public synchronized void onSaveState(Bundle outState) {
|
||||
outState.putBoolean(STATE_IS_DIALOG_OPEN, (mConnectDialog != null));
|
||||
if (mConnectDialog != null) {
|
||||
assert(mConnectDialog.isShowing());
|
||||
outState.putBoolean(STATE_IS_DIALOG_OPEN, (mConnectDialog != null));
|
||||
outState.putString(STATE_USERNAME,
|
||||
mUsernameView.getText().toString());
|
||||
outState.putString(STATE_PASSWORD,
|
||||
mPasswordView.getText().toString());
|
||||
dismissConnectDialog();
|
||||
}
|
||||
}
|
||||
|
||||
//@Override
|
||||
public synchronized void onRestoreState(final Bundle savedState) {
|
||||
boolean isDialogOpen = savedState.getBoolean(STATE_IS_DIALOG_OPEN);
|
||||
if (isDialogOpen) {
|
||||
connect(savedState.getString(STATE_USERNAME),
|
||||
savedState.getString(STATE_PASSWORD));
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void dismissConnectDialog() {
|
||||
mConnectDialog.dismiss();
|
||||
mConnectDialog = null;
|
||||
}
|
||||
|
||||
private void connectInternal() {
|
||||
mVpnManager.startVpnService();
|
||||
ServiceConnection c = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className,
|
||||
IBinder service) {
|
||||
boolean success = false;
|
||||
try {
|
||||
success = IVpnService.Stub.asInterface(service)
|
||||
.connect(mProfile,
|
||||
mUsernameView.getText().toString(),
|
||||
mPasswordView.getText().toString());
|
||||
mPasswordView.setText("");
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "connect()", e);
|
||||
checkStatus();
|
||||
} finally {
|
||||
mContext.unbindService(this);
|
||||
|
||||
if (!success) {
|
||||
Log.d(TAG, "~~~~~~ connect() failed!");
|
||||
// TODO: pop up a dialog
|
||||
broadcastConnectivity(VpnState.IDLE);
|
||||
} else {
|
||||
Log.d(TAG, "~~~~~~ connect() succeeded!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
checkStatus();
|
||||
}
|
||||
};
|
||||
if (!bindService(c)) broadcastConnectivity(VpnState.IDLE);
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void disconnect() {
|
||||
ServiceConnection c = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className,
|
||||
IBinder service) {
|
||||
try {
|
||||
IVpnService.Stub.asInterface(service).disconnect();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "disconnect()", e);
|
||||
checkStatus();
|
||||
} finally {
|
||||
mContext.unbindService(this);
|
||||
broadcastConnectivity(VpnState.IDLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
checkStatus();
|
||||
}
|
||||
};
|
||||
bindService(c);
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void checkStatus() {
|
||||
ServiceConnection c = new ServiceConnection() {
|
||||
public synchronized void onServiceConnected(ComponentName className,
|
||||
IBinder service) {
|
||||
try {
|
||||
IVpnService.Stub.asInterface(service).checkStatus(mProfile);
|
||||
} catch (Throwable e) {
|
||||
Log.e(TAG, "checkStatus()", e);
|
||||
} finally {
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
if (bindService(c)) {
|
||||
// wait for a second, let status propagate
|
||||
wait(c, ONE_SECOND);
|
||||
}
|
||||
mContext.unbindService(c);
|
||||
}
|
||||
|
||||
private boolean bindService(ServiceConnection c) {
|
||||
return mVpnManager.bindVpnService(c);
|
||||
}
|
||||
|
||||
private void broadcastConnectivity(VpnState s) {
|
||||
mVpnManager.broadcastConnectivity(mProfile.getName(), s);
|
||||
}
|
||||
|
||||
// returns true if inputs pass validation
|
||||
private boolean validateInputs() {
|
||||
Context c = mContext;
|
||||
String error = null;
|
||||
if (Util.isNullOrEmpty(mUsernameView.getText().toString())) {
|
||||
error = c.getString(R.string.vpn_username);
|
||||
} else if (Util.isNullOrEmpty(mPasswordView.getText().toString())) {
|
||||
error = c.getString(R.string.vpn_password);
|
||||
}
|
||||
if (error == null) {
|
||||
return true;
|
||||
} else {
|
||||
new AlertDialog.Builder(c)
|
||||
.setTitle(c.getString(R.string.vpn_you_miss_a_field))
|
||||
.setMessage(String.format(
|
||||
c.getString(R.string.vpn_please_fill_up), error))
|
||||
.setPositiveButton(c.getString(R.string.vpn_back_button),
|
||||
createBackButtonListener())
|
||||
.show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private View createConnectView(String username, String password) {
|
||||
View v = View.inflate(mContext, R.layout.vpn_connect_dialog_view, null);
|
||||
mUsernameView = (TextView) v.findViewById(R.id.username_value);
|
||||
mPasswordView = (TextView) v.findViewById(R.id.password_value);
|
||||
mUsernameView.setText(username);
|
||||
mPasswordView.setText(password);
|
||||
copyFieldsFromOldView(v);
|
||||
mView = v;
|
||||
return v;
|
||||
}
|
||||
|
||||
private void copyFieldsFromOldView(View newView) {
|
||||
if (mView == null) return;
|
||||
mUsernameView.setText(
|
||||
((TextView) mView.findViewById(R.id.username_value)).getText());
|
||||
mPasswordView.setText(
|
||||
((TextView) mView.findViewById(R.id.password_value)).getText());
|
||||
}
|
||||
|
||||
private DialogInterface.OnClickListener createBackButtonListener() {
|
||||
return new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
connect();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void wait(Object o, int ms) {
|
||||
synchronized (o) {
|
||||
try {
|
||||
o.wait(ms);
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
}
|
138
src/com/android/settings/vpn/L2tpIpsecEditor.java
Normal file
138
src/com/android/settings/vpn/L2tpIpsecEditor.java
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.L2tpIpsecProfile;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceGroup;
|
||||
import android.security.Keystore;
|
||||
|
||||
/**
|
||||
* The class for editing {@link L2tpIpsecProfile}.
|
||||
*/
|
||||
class L2tpIpsecEditor extends SingleServerEditor {
|
||||
private static final String TAG = L2tpIpsecEditor.class.getSimpleName();
|
||||
|
||||
private ListPreference mUserCertificate;
|
||||
private ListPreference mCaCertificate;
|
||||
private ListPreference mUserkey;
|
||||
|
||||
private L2tpIpsecProfile mProfile;
|
||||
|
||||
public L2tpIpsecEditor(L2tpIpsecProfile p) {
|
||||
super(p);
|
||||
mProfile = p;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void loadPreferencesTo(PreferenceGroup subsettings) {
|
||||
super.loadPreferencesTo(subsettings);
|
||||
Context c = subsettings.getContext();
|
||||
subsettings.addPreference(createUserkeyPreference(c));
|
||||
subsettings.addPreference(createUserCertificatePreference(c));
|
||||
subsettings.addPreference(createCaCertificatePreference(c));
|
||||
subsettings.addPreference(createDomainSufficesPreference(c));
|
||||
}
|
||||
|
||||
//@Override
|
||||
public String validate(Context c) {
|
||||
String result = super.validate(c);
|
||||
if (result != null) {
|
||||
return result;
|
||||
} else if (mProfile.isCustomized()) {
|
||||
return null;
|
||||
} else if (Util.isNullOrEmpty(mUserkey.getValue())) {
|
||||
return c.getString(R.string.vpn_error_userkey_not_selected);
|
||||
} else if (Util.isNullOrEmpty(mUserCertificate.getValue())) {
|
||||
return c.getString(R.string.vpn_error_user_certificate_not_selected);
|
||||
} else if (Util.isNullOrEmpty(mCaCertificate.getValue())) {
|
||||
return c.getString(R.string.vpn_error_ca_certificate_not_selected);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Preference createUserCertificatePreference(Context c) {
|
||||
mUserCertificate = createListPreference(c,
|
||||
R.string.vpn_user_certificate_title,
|
||||
mProfile.getUserCertificate(),
|
||||
Keystore.getInstance().getAllCertificateKeys(),
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
mProfile.setUserCertificate((String) newValue);
|
||||
return onPreferenceChangeCommon(pref, newValue);
|
||||
}
|
||||
});
|
||||
return mUserCertificate;
|
||||
}
|
||||
|
||||
private Preference createCaCertificatePreference(Context c) {
|
||||
mCaCertificate = createListPreference(c,
|
||||
R.string.vpn_ca_certificate_title,
|
||||
mProfile.getCaCertificate(),
|
||||
Keystore.getInstance().getAllCertificateKeys(),
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
mProfile.setCaCertificate((String) newValue);
|
||||
return onPreferenceChangeCommon(pref, newValue);
|
||||
}
|
||||
});
|
||||
return mCaCertificate;
|
||||
}
|
||||
|
||||
private Preference createUserkeyPreference(Context c) {
|
||||
mUserkey = createListPreference(c,
|
||||
R.string.vpn_userkey_title,
|
||||
mProfile.getUserkey(),
|
||||
Keystore.getInstance().getAllUserkeyKeys(),
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
mProfile.setUserkey((String) newValue);
|
||||
return onPreferenceChangeCommon(pref, newValue);
|
||||
}
|
||||
});
|
||||
return mUserkey;
|
||||
}
|
||||
|
||||
private ListPreference createListPreference(Context c, int titleResId,
|
||||
String text, String[] keys,
|
||||
Preference.OnPreferenceChangeListener listener) {
|
||||
ListPreference pref = new ListPreference(c);
|
||||
pref.setTitle(titleResId);
|
||||
pref.setDialogTitle(titleResId);
|
||||
pref.setPersistent(true);
|
||||
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;
|
||||
}
|
||||
}
|
110
src/com/android/settings/vpn/SingleServerEditor.java
Normal file
110
src/com/android/settings/vpn/SingleServerEditor.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.SingleServerProfile;
|
||||
import android.net.vpn.VpnProfile;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceGroup;
|
||||
|
||||
/**
|
||||
* The class for editing {@link SingleServerProfile}.
|
||||
*/
|
||||
class SingleServerEditor implements VpnProfileEditor {
|
||||
private EditTextPreference mServerName;
|
||||
private EditTextPreference mDomainSuffices;
|
||||
private SingleServerProfile mProfile;
|
||||
|
||||
public SingleServerEditor(SingleServerProfile p) {
|
||||
mProfile = p;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public VpnProfile getProfile() {
|
||||
return mProfile;
|
||||
}
|
||||
|
||||
//@Override
|
||||
public void loadPreferencesTo(PreferenceGroup subpanel) {
|
||||
Context c = subpanel.getContext();
|
||||
subpanel.addPreference(createServerNamePreference(c));
|
||||
}
|
||||
|
||||
//@Override
|
||||
public String validate(Context c) {
|
||||
return (mProfile.isCustomized()
|
||||
? null
|
||||
: (Util.isNullOrEmpty(mServerName.getText())
|
||||
? c.getString(R.string.vpn_error_server_name_empty)
|
||||
: null));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
String v = ((String) newValue).trim();
|
||||
mProfile.setDomainSuffices(v);
|
||||
pref.setSummary(checkNull(v, pref.getContext()));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return pref;
|
||||
}
|
||||
|
||||
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(
|
||||
new Preference.OnPreferenceChangeListener() {
|
||||
public boolean onPreferenceChange(
|
||||
Preference pref, Object newValue) {
|
||||
String v = ((String) newValue).trim();
|
||||
mProfile.setServerName(v);
|
||||
pref.setSummary(checkNull(v, pref.getContext()));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return mServerName;
|
||||
}
|
||||
|
||||
|
||||
String checkNull(String value, Context c) {
|
||||
return ((value != null && value.length() > 0)
|
||||
? value
|
||||
: c.getString(R.string.vpn_not_set));
|
||||
}
|
||||
}
|
147
src/com/android/settings/vpn/Util.java
Normal file
147
src/com/android/settings/vpn/Util.java
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class Util {
|
||||
|
||||
static void showShortToastMessage(Context context, String message) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
static void showShortToastMessage(Context context, int messageId) {
|
||||
Toast.makeText(context, messageId, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
static void showLongToastMessage(Context context, String message) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
static void showLongToastMessage(Context context, int messageId) {
|
||||
Toast.makeText(context, messageId, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
static void showErrorMessage(Context c, String message) {
|
||||
createErrorDialog(c, message, null).show();
|
||||
}
|
||||
|
||||
static void showErrorMessage(Context c, String message,
|
||||
DialogInterface.OnClickListener listener) {
|
||||
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));
|
||||
}
|
||||
|
||||
static void deleteFile(String path) {
|
||||
deleteFile(new File(path));
|
||||
}
|
||||
|
||||
static void deleteFile(String path, boolean toDeleteSelf) {
|
||||
deleteFile(new File(path), toDeleteSelf);
|
||||
}
|
||||
|
||||
static void deleteFile(File f) {
|
||||
deleteFile(f, true);
|
||||
}
|
||||
|
||||
static void deleteFile(File f, boolean toDeleteSelf) {
|
||||
if (f.isDirectory()) {
|
||||
for (File child : f.listFiles()) deleteFile(child, true);
|
||||
}
|
||||
if (toDeleteSelf) f.delete();
|
||||
}
|
||||
|
||||
static boolean isFileOrEmptyDirectory(String path) {
|
||||
File f = new File(path);
|
||||
if (!f.isDirectory()) return true;
|
||||
|
||||
String[] list = f.list();
|
||||
return ((list == null) || (list.length == 0));
|
||||
}
|
||||
|
||||
static boolean copyFiles(String sourcePath , String targetPath)
|
||||
throws IOException {
|
||||
return copyFiles(new File(sourcePath), new File(targetPath));
|
||||
}
|
||||
|
||||
// returns false if sourceLocation is the same as the targetLocation
|
||||
static boolean copyFiles(File sourceLocation , File targetLocation)
|
||||
throws IOException {
|
||||
if (sourceLocation.equals(targetLocation)) return false;
|
||||
|
||||
if (sourceLocation.isDirectory()) {
|
||||
if (!targetLocation.exists()) {
|
||||
targetLocation.mkdir();
|
||||
}
|
||||
String[] children = sourceLocation.list();
|
||||
for (int i=0; i<children.length; i++) {
|
||||
copyFiles(new File(sourceLocation, children[i]),
|
||||
new File(targetLocation, children[i]));
|
||||
}
|
||||
} else if (sourceLocation.exists()) {
|
||||
InputStream in = new FileInputStream(sourceLocation);
|
||||
OutputStream out = new FileOutputStream(targetLocation);
|
||||
|
||||
// Copy the bits from instream to outstream
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static AlertDialog createErrorDialog(Context c, String message,
|
||||
DialogInterface.OnClickListener okListener) {
|
||||
AlertDialog.Builder b = new AlertDialog.Builder(c)
|
||||
.setTitle(R.string.vpn_error_title)
|
||||
.setMessage(message);
|
||||
if (okListener != null) {
|
||||
b.setPositiveButton(R.string.vpn_back_button, okListener);
|
||||
} else {
|
||||
b.setPositiveButton(android.R.string.ok, null);
|
||||
}
|
||||
return b.create();
|
||||
}
|
||||
|
||||
private Util() {
|
||||
}
|
||||
}
|
181
src/com/android/settings/vpn/VpnEditor.java
Normal file
181
src/com/android/settings/vpn/VpnEditor.java
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.vpn.L2tpIpsecProfile;
|
||||
import android.net.vpn.SingleServerProfile;
|
||||
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.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
/**
|
||||
* 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 VpnProfileEditor mProfileEditor;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// 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
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
menu.add(0, MENU_SAVE, 0, R.string.vpn_menu_save)
|
||||
.setIcon(android.R.drawable.ic_menu_save);
|
||||
menu.add(0, MENU_CANCEL, 0, R.string.vpn_menu_cancel)
|
||||
.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case MENU_SAVE:
|
||||
if (validateAndSetResult()) {
|
||||
finish();
|
||||
}
|
||||
return true;
|
||||
case MENU_CANCEL:
|
||||
showCancellationConfirmDialog();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the validity of the inputs and set the profile as result if valid.
|
||||
* @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);
|
||||
}
|
||||
|
||||
if (errorMsg != null) {
|
||||
Util.showErrorMessage(this, errorMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
setResult(mProfileEditor.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);
|
||||
setResult(RESULT_OK, intent);
|
||||
}
|
||||
|
||||
private VpnProfileEditor getEditor(VpnProfile p) {
|
||||
if (p instanceof L2tpIpsecProfile) {
|
||||
return new L2tpIpsecEditor((L2tpIpsecProfile) p);
|
||||
} else if (p instanceof SingleServerProfile) {
|
||||
return new SingleServerEditor((SingleServerProfile) p);
|
||||
} else {
|
||||
throw new RuntimeException("Unknown profile type: " + p.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private void showCancellationConfirmDialog() {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.vpn_error_title)
|
||||
.setMessage(R.string.vpn_confirm_profile_cancellation)
|
||||
.setPositiveButton(R.string.vpn_yes_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
finish();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.vpn_mistake_button, null)
|
||||
.show();
|
||||
}
|
||||
}
|
54
src/com/android/settings/vpn/VpnProfileActor.java
Normal file
54
src/com/android/settings/vpn/VpnProfileActor.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 android.net.vpn.VpnProfile;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* The interface to act on a {@link VpnProfile}.
|
||||
*/
|
||||
public interface VpnProfileActor {
|
||||
VpnProfile getProfile();
|
||||
|
||||
/**
|
||||
* Establishes a VPN connection.
|
||||
*/
|
||||
void connect();
|
||||
|
||||
/**
|
||||
* Tears down the connection.
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
/**
|
||||
* Checks the current status. The result is expected to be broadcast.
|
||||
* Use {@link VpnManager#registerConnectivityReceiver()} to register a
|
||||
* broadcast receiver and to receives the broadcast events.
|
||||
*/
|
||||
void checkStatus();
|
||||
|
||||
/**
|
||||
* Called to save the states when the device is rotated.
|
||||
*/
|
||||
void onSaveState(Bundle outState);
|
||||
|
||||
/**
|
||||
* Called to restore the states on the rotated screen.
|
||||
*/
|
||||
void onRestoreState(Bundle savedState);
|
||||
}
|
41
src/com/android/settings/vpn/VpnProfileEditor.java
Normal file
41
src/com/android/settings/vpn/VpnProfileEditor.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 android.content.Context;
|
||||
import android.net.vpn.VpnProfile;
|
||||
import android.preference.PreferenceGroup;
|
||||
|
||||
/**
|
||||
* The interface to set up preferences for editing a {@link VpnProfile}.
|
||||
*/
|
||||
public interface VpnProfileEditor {
|
||||
VpnProfile getProfile();
|
||||
|
||||
/**
|
||||
* Adds the preferences to the panel.
|
||||
*/
|
||||
void loadPreferencesTo(PreferenceGroup subpanel);
|
||||
|
||||
/**
|
||||
* Validates the inputs in the preferences.
|
||||
*
|
||||
* @return an error message that is ready to be displayed in a dialog; or
|
||||
* null if all the inputs are valid
|
||||
*/
|
||||
String validate(Context c);
|
||||
}
|
585
src/com/android/settings/vpn/VpnSettings.java
Normal file
585
src/com/android/settings/vpn/VpnSettings.java
Normal file
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.vpn.VpnManager;
|
||||
import android.net.vpn.VpnProfile;
|
||||
import android.net.vpn.VpnState;
|
||||
import android.net.vpn.VpnType;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.preference.Preference.OnPreferenceClickListener;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView.AdapterContextMenuInfo;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The preference activity for configuring VPN settings.
|
||||
*/
|
||||
public class VpnSettings extends PreferenceActivity {
|
||||
// Key to the field exchanged for profile editing.
|
||||
static final String KEY_VPN_PROFILE = "vpn_profile";
|
||||
|
||||
// Key to the field exchanged for VPN type selection.
|
||||
static final String KEY_VPN_TYPE = "vpn_type";
|
||||
|
||||
private static final String TAG = VpnSettings.class.getSimpleName();
|
||||
|
||||
private static final String PREF_ADD_VPN = "add_new_vpn";
|
||||
private static final String PREF_VPN_LIST = "vpn_list";
|
||||
|
||||
private static final String PROFILES_ROOT = VpnManager.PROFILES_PATH + "/";
|
||||
private static final String PROFILE_OBJ_FILE = ".pobj";
|
||||
|
||||
private static final String STATE_ACTIVE_ACTOR = "active_actor";
|
||||
|
||||
private static final int REQUEST_ADD_OR_EDIT_PROFILE = 1;
|
||||
private static final int REQUEST_SELECT_VPN_TYPE = 2;
|
||||
|
||||
private static final int CONTEXT_MENU_CONNECT_ID = ContextMenu.FIRST + 0;
|
||||
private static final int CONTEXT_MENU_DISCONNECT_ID = ContextMenu.FIRST + 1;
|
||||
private static final int CONTEXT_MENU_EDIT_ID = ContextMenu.FIRST + 2;
|
||||
private static final int CONTEXT_MENU_DELETE_ID = ContextMenu.FIRST + 3;
|
||||
|
||||
private PreferenceScreen mAddVpn;
|
||||
private PreferenceCategory mVpnListContainer;
|
||||
|
||||
// profile name --> VpnPreference
|
||||
private Map<String, VpnPreference> mVpnPreferenceMap;
|
||||
private List<VpnProfile> mVpnProfileList;
|
||||
|
||||
private int mIndexOfEditedProfile = -1;
|
||||
|
||||
// profile engaged in a connection
|
||||
private VpnProfile mActiveProfile;
|
||||
|
||||
// actor engaged in an action
|
||||
private VpnProfileActor mActiveActor;
|
||||
|
||||
private VpnManager mVpnManager = new VpnManager(this);
|
||||
|
||||
private ConnectivityReceiver mConnectivityReceiver =
|
||||
new ConnectivityReceiver();
|
||||
|
||||
private boolean mConnectingError;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.vpn_settings);
|
||||
|
||||
// restore VpnProfile list and construct VpnPreference map
|
||||
mVpnListContainer = (PreferenceCategory) findPreference(PREF_VPN_LIST);
|
||||
retrieveVpnListFromStorage();
|
||||
|
||||
// set up the "add vpn" preference
|
||||
mAddVpn = (PreferenceScreen) findPreference(PREF_ADD_VPN);
|
||||
mAddVpn.setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startVpnTypeSelection();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// for long-press gesture on a profile preference
|
||||
registerForContextMenu(getListView());
|
||||
|
||||
// listen to vpn connectivity event
|
||||
mVpnManager.registerConnectivityReceiver(mConnectivityReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onSaveInstanceState(Bundle outState) {
|
||||
if (mActiveActor == null) return;
|
||||
|
||||
mActiveActor.onSaveState(outState);
|
||||
outState.putString(STATE_ACTIVE_ACTOR,
|
||||
mActiveActor.getProfile().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(final Bundle savedState) {
|
||||
String profileName = savedState.getString(STATE_ACTIVE_ACTOR);
|
||||
if (Util.isNullOrEmpty(profileName)) return;
|
||||
|
||||
final VpnProfile p = mVpnPreferenceMap.get(profileName).mProfile;
|
||||
mActiveActor = getActor(p);
|
||||
mActiveActor.onRestoreState(savedState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unregisterForContextMenu(getListView());
|
||||
mVpnManager.unregisterConnectivityReceiver(mConnectivityReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
|
||||
VpnProfile p = getProfile(getProfilePositionFrom(
|
||||
(AdapterContextMenuInfo) menuInfo));
|
||||
if (p != null) {
|
||||
VpnState state = p.getState();
|
||||
menu.setHeaderTitle(p.getName());
|
||||
|
||||
boolean isIdle = (state == VpnState.IDLE);
|
||||
boolean isNotConnect =
|
||||
(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)
|
||||
.setEnabled(!isIdle);
|
||||
menu.add(0, CONTEXT_MENU_EDIT_ID, 0, R.string.vpn_menu_edit)
|
||||
.setEnabled(isNotConnect);
|
||||
menu.add(0, CONTEXT_MENU_DELETE_ID, 0, R.string.vpn_menu_delete)
|
||||
.setEnabled(isNotConnect);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
int position = getProfilePositionFrom(
|
||||
(AdapterContextMenuInfo) item.getMenuInfo());
|
||||
VpnProfile p = getProfile(position);
|
||||
|
||||
switch(item.getItemId()) {
|
||||
case CONTEXT_MENU_CONNECT_ID:
|
||||
case CONTEXT_MENU_DISCONNECT_ID:
|
||||
connectOrDisconnect(p);
|
||||
return true;
|
||||
|
||||
case CONTEXT_MENU_EDIT_ID:
|
||||
mIndexOfEditedProfile = position;
|
||||
startVpnEditor(p);
|
||||
return true;
|
||||
|
||||
case CONTEXT_MENU_DELETE_ID:
|
||||
deleteProfile(position);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
int index = mIndexOfEditedProfile;
|
||||
mIndexOfEditedProfile = -1;
|
||||
|
||||
if ((resultCode == RESULT_CANCELED) || (data == null)) {
|
||||
Log.v(TAG, "no result returned by editor");
|
||||
return;
|
||||
}
|
||||
|
||||
if (requestCode == REQUEST_SELECT_VPN_TYPE) {
|
||||
String typeName = data.getStringExtra(KEY_VPN_TYPE);
|
||||
startVpnEditor(createVpnProfile(typeName));
|
||||
} else if (requestCode == REQUEST_ADD_OR_EDIT_PROFILE) {
|
||||
VpnProfile p = data.getParcelableExtra(KEY_VPN_PROFILE);
|
||||
if (p == null) {
|
||||
Log.e(TAG, "null object returned by editor");
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkDuplicateName(p, index)) {
|
||||
final VpnProfile profile = p;
|
||||
Util.showErrorMessage(this, String.format(
|
||||
getString(R.string.vpn_error_duplicate_name), p.getName()),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
startVpnEditor(profile);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if ((index < 0) || (index >= mVpnProfileList.size())) {
|
||||
addProfile(p);
|
||||
Util.showShortToastMessage(this, String.format(
|
||||
getString(R.string.vpn_profile_added), p.getName()));
|
||||
} else {
|
||||
replaceProfile(index, p);
|
||||
Util.showShortToastMessage(this, String.format(
|
||||
getString(R.string.vpn_profile_replaced), p.getName()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
final VpnProfile profile = p;
|
||||
Util.showErrorMessage(this, e + ": " + e.getMessage(),
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
startVpnEditor(profile);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("unknown request code: " + requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces the profile at index in mVpnProfileList with p.
|
||||
// Returns true if p's name is a duplicate.
|
||||
private boolean checkDuplicateName(VpnProfile p, int index) {
|
||||
List<VpnProfile> list = mVpnProfileList;
|
||||
VpnPreference pref = mVpnPreferenceMap.get(p.getName());
|
||||
if ((pref != null) && (index >= 0) && (index < list.size())) {
|
||||
// not a duplicate if p is to replace the profile at index
|
||||
if (pref.mProfile == list.get(index)) pref = null;
|
||||
}
|
||||
return (pref != null);
|
||||
}
|
||||
|
||||
private int getProfilePositionFrom(AdapterContextMenuInfo menuInfo) {
|
||||
// excludes mVpnListContainer and the preferences above it
|
||||
return menuInfo.position - mVpnListContainer.getOrder() - 1;
|
||||
}
|
||||
|
||||
// position: position in mVpnProfileList
|
||||
private VpnProfile getProfile(int position) {
|
||||
return ((position >= 0) ? mVpnProfileList.get(position) : null);
|
||||
}
|
||||
|
||||
// position: position in mVpnProfileList
|
||||
private void deleteProfile(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);
|
||||
}
|
||||
|
||||
private void addProfile(VpnProfile p) throws IOException {
|
||||
saveProfileToStorage(p);
|
||||
mVpnProfileList.add(p);
|
||||
addPreferenceFor(p);
|
||||
disableProfilePreferencesIfOneActive();
|
||||
}
|
||||
|
||||
// Adds a preference in mVpnListContainer
|
||||
private void addPreferenceFor(VpnProfile p) {
|
||||
VpnPreference pref = new VpnPreference(this, p);
|
||||
mVpnPreferenceMap.put(p.getName(), pref);
|
||||
mVpnListContainer.addPreference(pref);
|
||||
|
||||
pref.setOnPreferenceClickListener(
|
||||
new Preference.OnPreferenceClickListener() {
|
||||
public boolean onPreferenceClick(Preference pref) {
|
||||
connectOrDisconnect(((VpnPreference) pref).mProfile);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// index: index to mVpnProfileList
|
||||
private void replaceProfile(int index, VpnProfile p) throws IOException {
|
||||
Map<String, VpnPreference> map = mVpnPreferenceMap;
|
||||
VpnProfile oldProfile = mVpnProfileList.set(index, p);
|
||||
VpnPreference pref = map.remove(oldProfile.getName());
|
||||
if (pref.mProfile != oldProfile) {
|
||||
throw new RuntimeException("inconsistent state!");
|
||||
}
|
||||
|
||||
// Copy config files and remove the old ones if they are in different
|
||||
// directories.
|
||||
if (Util.copyFiles(getProfileDir(oldProfile), getProfileDir(p))) {
|
||||
removeProfileFromStorage(oldProfile);
|
||||
}
|
||||
saveProfileToStorage(p);
|
||||
|
||||
pref.setProfile(p);
|
||||
map.put(p.getName(), pref);
|
||||
}
|
||||
|
||||
private void startVpnTypeSelection() {
|
||||
Intent intent = new Intent(this, VpnTypeSelection.class);
|
||||
startActivityForResult(intent, REQUEST_SELECT_VPN_TYPE);
|
||||
}
|
||||
|
||||
private void startVpnEditor(VpnProfile profile) {
|
||||
Intent intent = new Intent(this, VpnEditor.class);
|
||||
intent.putExtra(KEY_VPN_PROFILE, (Parcelable) profile);
|
||||
startActivityForResult(intent, REQUEST_ADD_OR_EDIT_PROFILE);
|
||||
}
|
||||
|
||||
// Do connect or disconnect based on the current state.
|
||||
private synchronized void connectOrDisconnect(VpnProfile p) {
|
||||
VpnPreference pref = mVpnPreferenceMap.get(p.getName());
|
||||
switch (p.getState()) {
|
||||
case IDLE:
|
||||
changeState(p, VpnState.CONNECTING);
|
||||
mActiveActor = getActor(p);
|
||||
mActiveActor.connect();
|
||||
break;
|
||||
|
||||
case CONNECTING:
|
||||
// TODO: bring up a dialog to confirm disconnect
|
||||
break;
|
||||
|
||||
case CONNECTED:
|
||||
mConnectingError = false;
|
||||
// pass through
|
||||
case DISCONNECTING:
|
||||
changeState(p, VpnState.DISCONNECTING);
|
||||
getActor(p).disconnect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void changeState(VpnProfile p, VpnState state) {
|
||||
VpnState oldState = p.getState();
|
||||
if (oldState == state) return;
|
||||
|
||||
Log.d(TAG, "changeState: " + p.getName() + ": " + state);
|
||||
p.setState(state);
|
||||
mVpnPreferenceMap.get(p.getName()).setSummary(
|
||||
getProfileSummaryString(p));
|
||||
|
||||
switch (state) {
|
||||
case CONNECTED:
|
||||
mActiveActor = null;
|
||||
// pass through
|
||||
case CONNECTING:
|
||||
mActiveProfile = p;
|
||||
disableProfilePreferencesIfOneActive();
|
||||
break;
|
||||
|
||||
case DISCONNECTING:
|
||||
if (oldState == VpnState.CONNECTING) {
|
||||
mConnectingError = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case CANCELLED:
|
||||
changeState(p, VpnState.IDLE);
|
||||
break;
|
||||
|
||||
case IDLE:
|
||||
assert(mActiveProfile != p);
|
||||
mActiveProfile = null;
|
||||
mActiveActor = null;
|
||||
enableProfilePreferences();
|
||||
|
||||
if (oldState == VpnState.CONNECTING) mConnectingError = true;
|
||||
if (mConnectingError) showReconnectDialog(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void showReconnectDialog(final VpnProfile p) {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.vpn_error_title)
|
||||
.setMessage(R.string.vpn_confirm_reconnect)
|
||||
.setPositiveButton(R.string.vpn_yes_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int w) {
|
||||
dialog.dismiss();
|
||||
connectOrDisconnect(p);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.vpn_no_button, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void disableProfilePreferencesIfOneActive() {
|
||||
if (mActiveProfile == null) return;
|
||||
|
||||
for (VpnProfile p : mVpnProfileList) {
|
||||
switch (p.getState()) {
|
||||
case DISCONNECTING:
|
||||
case IDLE:
|
||||
mVpnPreferenceMap.get(p.getName()).setEnabled(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enableProfilePreferences() {
|
||||
for (VpnProfile p : mVpnProfileList) {
|
||||
mVpnPreferenceMap.get(p.getName()).setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProfileDir(VpnProfile p) {
|
||||
return PROFILES_ROOT + p.getId();
|
||||
}
|
||||
|
||||
private void saveProfileToStorage(VpnProfile p) throws IOException {
|
||||
File f = new File(getProfileDir(p));
|
||||
if (!f.exists()) f.mkdirs();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
|
||||
new File(f, PROFILE_OBJ_FILE)));
|
||||
oos.writeObject(p);
|
||||
oos.close();
|
||||
}
|
||||
|
||||
private void removeProfileFromStorage(VpnProfile p) {
|
||||
Util.deleteFile(getProfileDir(p));
|
||||
}
|
||||
|
||||
private void retrieveVpnListFromStorage() {
|
||||
mVpnPreferenceMap = new LinkedHashMap<String, VpnPreference>();
|
||||
mVpnProfileList = new ArrayList<VpnProfile>();
|
||||
|
||||
File root = new File(PROFILES_ROOT);
|
||||
String[] dirs = root.list();
|
||||
if (dirs == null) return;
|
||||
Arrays.sort(dirs);
|
||||
for (String dir : dirs) {
|
||||
File f = new File(new File(root, dir), PROFILE_OBJ_FILE);
|
||||
if (!f.exists()) continue;
|
||||
try {
|
||||
VpnProfile p = deserialize(f);
|
||||
if (!checkIdConsistency(dir, p)) continue;
|
||||
|
||||
mVpnProfileList.add(p);
|
||||
addPreferenceFor(p);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "retrieveVpnListFromStorage()", e);
|
||||
}
|
||||
}
|
||||
disableProfilePreferencesIfOneActive();
|
||||
checkVpnConnectionStatusInBackground();
|
||||
}
|
||||
|
||||
private void checkVpnConnectionStatusInBackground() {
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
for (VpnProfile p : mVpnProfileList) {
|
||||
getActor(p).checkStatus();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
// A sanity check. Returns true if the profile directory name and profile ID
|
||||
// are consistent.
|
||||
private boolean checkIdConsistency(String dirName, VpnProfile p) {
|
||||
if (!dirName.equals(p.getId())) {
|
||||
Log.v(TAG, "ID inconsistent: " + dirName + " vs " + p.getId());
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private VpnProfile deserialize(File profileObjectFile) throws IOException {
|
||||
try {
|
||||
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
|
||||
profileObjectFile));
|
||||
VpnProfile p = (VpnProfile) ois.readObject();
|
||||
ois.close();
|
||||
return p;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProfileSummaryString(VpnProfile p) {
|
||||
switch (p.getState()) {
|
||||
case CONNECTING:
|
||||
return getString(R.string.vpn_connecting);
|
||||
case DISCONNECTING:
|
||||
return getString(R.string.vpn_disconnecting);
|
||||
case CONNECTED:
|
||||
return getString(R.string.vpn_connected);
|
||||
default:
|
||||
return getString(R.string.vpn_connect_hint);
|
||||
}
|
||||
}
|
||||
|
||||
private VpnProfileActor getActor(VpnProfile p) {
|
||||
return new AuthenticationActor(this, p);
|
||||
}
|
||||
|
||||
private VpnProfile createVpnProfile(String type) {
|
||||
return mVpnManager.createVpnProfile(Enum.valueOf(VpnType.class, type));
|
||||
}
|
||||
|
||||
private class VpnPreference extends Preference {
|
||||
VpnProfile mProfile;
|
||||
VpnPreference(Context c, VpnProfile p) {
|
||||
super(c);
|
||||
setProfile(p);
|
||||
}
|
||||
|
||||
void setProfile(VpnProfile p) {
|
||||
mProfile = p;
|
||||
setTitle(p.getName());
|
||||
setSummary(getProfileSummaryString(p));
|
||||
}
|
||||
}
|
||||
|
||||
// to receive vpn connectivity events broadcast by VpnService
|
||||
private class ConnectivityReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String profileName = intent.getStringExtra(
|
||||
VpnManager.BROADCAST_PROFILE_NAME);
|
||||
if (profileName == null) return;
|
||||
|
||||
VpnState s = (VpnState) intent.getSerializableExtra(
|
||||
VpnManager.BROADCAST_CONNECTION_STATE);
|
||||
if (s == null) {
|
||||
Log.e(TAG, "received null connectivity state");
|
||||
return;
|
||||
}
|
||||
VpnPreference pref = mVpnPreferenceMap.get(profileName);
|
||||
if (pref != null) {
|
||||
Log.d(TAG, "received connectivity: " + profileName
|
||||
+ ": connected? " + s);
|
||||
changeState(pref.mProfile, s);
|
||||
} else {
|
||||
Log.e(TAG, "received connectivity: " + profileName
|
||||
+ ": connected? " + s + ", but profile does not exist;"
|
||||
+ " just ignore it");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
70
src/com/android/settings/vpn/VpnTypeSelection.java
Normal file
70
src/com/android/settings/vpn/VpnTypeSelection.java
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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.Intent;
|
||||
import android.net.vpn.VpnManager;
|
||||
import android.net.vpn.VpnType;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceScreen;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The activity to select a VPN type.
|
||||
*/
|
||||
public class VpnTypeSelection extends PreferenceActivity {
|
||||
private Map<String, VpnType> mTypeMap = new HashMap<String, VpnType>();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.vpn_type);
|
||||
initTypeList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen ps, Preference pref) {
|
||||
setResult(mTypeMap.get(pref.getTitle().toString()));
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initTypeList() {
|
||||
PreferenceScreen root = getPreferenceScreen();
|
||||
for (VpnType t : VpnManager.getSupportedVpnTypes()) {
|
||||
String displayName = t.getDisplayName();
|
||||
mTypeMap.put(displayName, t);
|
||||
|
||||
Preference pref = new Preference(this);
|
||||
pref.setTitle(displayName);
|
||||
root.addPreference(pref);
|
||||
}
|
||||
}
|
||||
|
||||
private void setResult(VpnType type) {
|
||||
Intent intent = new Intent(this, VpnSettings.class);
|
||||
intent.putExtra(VpnSettings.KEY_VPN_TYPE, type.toString());
|
||||
setResult(RESULT_OK, intent);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user