diff options
-rw-r--r-- | res/layout/vpn_dialog.xml | 22 | ||||
-rw-r--r-- | res/values/strings.xml | 9 | ||||
-rw-r--r-- | res/values/styles.xml | 5 | ||||
-rw-r--r-- | src/com/android/settings/vpn2/VpnDialog.java | 63 | ||||
-rw-r--r-- | src/com/android/settings/vpn2/VpnSettings.java | 7 |
5 files changed, 90 insertions, 16 deletions
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml index ffbfd4d..b4779e6 100644 --- a/res/layout/vpn_dialog.xml +++ b/res/layout/vpn_dialog.xml @@ -15,7 +15,7 @@ --> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -96,15 +96,27 @@ android:prompt="@string/vpn_ipsec_ca_cert" /> </LinearLayout> + <CheckBox style="@style/vpn_value" android:id="@+id/show_options" + android:singleLine="false" + android:text="@string/vpn_show_options"/> + </LinearLayout> + + <LinearLayout android:id="@+id/options" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:visibility="gone"> <TextView style="@style/vpn_label" android:text="@string/vpn_search_domains"/> <EditText style="@style/vpn_value" android:id="@+id/search_domains" android:hint="@string/vpn_not_used"/> - <!-- Not sure if we have time to make it. --> - <TextView style="@style/vpn_label" android:text="@string/vpn_routes" - android:visibility="gone"/> + <TextView style="@style/vpn_label" android:text="@string/vpn_dns_servers"/> + <EditText style="@style/vpn_value" android:id="@+id/dns_servers" + android:hint="@string/vpn_not_used"/> + + <TextView style="@style/vpn_label" android:text="@string/vpn_routes"/> <EditText style="@style/vpn_value" android:id="@+id/routes" - android:visibility="gone"/> + android:hint="@string/vpn_not_used"/> </LinearLayout> <LinearLayout android:id="@+id/login" diff --git a/res/values/strings.xml b/res/values/strings.xml index d2d919e..47fed2f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3492,18 +3492,21 @@ found in the list of installed applications.</string> <string name="vpn_ipsec_user_cert">IPSec user certificate</string> <!-- Selection label for the IPSec CA certificate of a VPN network. [CHAR LIMIT=40] --> <string name="vpn_ipsec_ca_cert">IPSec CA certificate</string> + <!-- Checkbox label to show advanced options of a VPN network. [CHAR LIMIT=40] --> + <string name="vpn_show_options">Show advanced options</string> <!-- Input label for the DNS search domains of a VPN network. [CHAR LIMIT=40] --> <string name="vpn_search_domains">DNS search domains</string> + <!-- Input label for the DNS servers of a VPN network. [CHAR LIMIT=40] --> + <string name="vpn_dns_servers">DNS servers (e.g. 8.8.8.8)</string> <!-- Input label for the forwarding routes of a VPN network. [CHAR LIMIT=40] --> - <string name="vpn_routes">Forwarding routes</string> + <string name="vpn_routes">Forwarding routes (e.g. 10.0.0.0/8)</string> <!-- Input label for the username of a VPN network. [CHAR LIMIT=40] --> <string name="vpn_username">Username</string> <!-- Input label for the password of a VPN network. [CHAR LIMIT=40] --> <string name="vpn_password">Password</string> <!-- Checkbox label to save the username and the password for a VPN network. [CHAR LIMIT=40] --> <string name="vpn_save_login">Save account information</string> - - <!-- Hint for not filling an optional field in a VPN configuration. [CHAR LIMIT=40] --> + <!-- Hint for not using an optional feature of a VPN network. [CHAR LIMIT=40] --> <string name="vpn_not_used">(not used)</string> <!-- Option to not use a CA certificate to verify the VPN server. [CHAR LIMIT=40] --> <string name="vpn_no_ca_cert">(do not verify server)</string> diff --git a/res/values/styles.xml b/res/values/styles.xml index ffa7912..32e0a48 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -143,15 +143,14 @@ <style name="vpn_label"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> - <item name="android:textSize">16sp</item> + <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> </style> <style name="vpn_value"> <item name="android:layout_width">match_parent</item> <item name="android:layout_height">wrap_content</item> - <item name="android:textSize">18sp</item> + <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> <item name="android:singleLine">true</item> - <item name="android:paddingBottom">1mm</item> </style> <style name="InputMethodPreferenceStyle"> diff --git a/src/com/android/settings/vpn2/VpnDialog.java b/src/com/android/settings/vpn2/VpnDialog.java index d644700..c1a4531 100644 --- a/src/com/android/settings/vpn2/VpnDialog.java +++ b/src/com/android/settings/vpn2/VpnDialog.java @@ -27,15 +27,18 @@ import android.security.KeyStore; import android.text.Editable; import android.text.TextWatcher; import android.view.View; +import android.view.WindowManager; import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; import android.widget.Spinner; import android.widget.TextView; -class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListener { +import java.net.InetAddress; + +class VpnDialog extends AlertDialog implements TextWatcher, + View.OnClickListener, AdapterView.OnItemSelectedListener { private final KeyStore mKeyStore = KeyStore.getInstance(); private final DialogInterface.OnClickListener mListener; private final VpnProfile mProfile; @@ -50,6 +53,7 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen private TextView mUsername; private TextView mPassword; private TextView mSearchDomains; + private TextView mDnsServers; private TextView mRoutes; private CheckBox mMppe; private TextView mL2tpSecret; @@ -82,6 +86,7 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen mUsername = (TextView) mView.findViewById(R.id.username); mPassword = (TextView) mView.findViewById(R.id.password); mSearchDomains = (TextView) mView.findViewById(R.id.search_domains); + mDnsServers = (TextView) mView.findViewById(R.id.dns_servers); mRoutes = (TextView) mView.findViewById(R.id.routes); mMppe = (CheckBox) mView.findViewById(R.id.mppe); mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret); @@ -98,6 +103,7 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen mUsername.setText(mProfile.username); mPassword.setText(mProfile.password); mSearchDomains.setText(mProfile.searchDomains); + mDnsServers.setText(mProfile.dnsServers); mRoutes.setText(mProfile.routes); mMppe.setChecked(mProfile.mppe); mL2tpSecret.setText(mProfile.l2tpSecret); @@ -115,6 +121,8 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen mServer.addTextChangedListener(this); mUsername.addTextChangedListener(this); mPassword.addTextChangedListener(this); + mDnsServers.addTextChangedListener(this); + mRoutes.addTextChangedListener(this); mIpsecSecret.addTextChangedListener(this); mIpsecUserCert.setOnItemSelectedListener(this); @@ -131,6 +139,15 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen // Show type-specific fields. changeType(mProfile.type); + // Show advanced options directly if any of them is set. + View showOptions = mView.findViewById(R.id.show_options); + if (mProfile.searchDomains.isEmpty() && mProfile.dnsServers.isEmpty() && + mProfile.routes.isEmpty()) { + showOptions.setOnClickListener(this); + } else { + onClick(showOptions); + } + // Create a button to save the profile. setButton(DialogInterface.BUTTON_POSITIVE, context.getString(R.string.vpn_save), mListener); @@ -155,6 +172,10 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen // Disable the action button if necessary. getButton(DialogInterface.BUTTON_POSITIVE) .setEnabled(mEditing ? valid : validate(false)); + + // Workaround to resize the dialog for the input method. + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | + WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); } @Override @@ -171,6 +192,12 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen } @Override + public void onClick(View showOptions) { + showOptions.setVisibility(View.GONE); + mView.findViewById(R.id.options).setVisibility(View.VISIBLE); + } + + @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (parent == mType) { changeType(position); @@ -221,7 +248,9 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen if (!editing) { return mUsername.getText().length() != 0 && mPassword.getText().length() != 0; } - if (mName.getText().length() == 0 || mServer.getText().length() == 0) { + if (mName.getText().length() == 0 || mServer.getText().length() == 0 || + !validateAddresses(mDnsServers.getText().toString(), false) || + !validateAddresses(mRoutes.getText().toString(), true)) { return false; } switch (mType.getSelectedItemPosition()) { @@ -239,6 +268,33 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen return false; } + private boolean validateAddresses(String addresses, boolean cidr) { + try { + for (String address : addresses.split(" ")) { + if (address.isEmpty()) { + continue; + } + // Legacy VPN currently only supports IPv4. + int prefixLength = 32; + if (cidr) { + String[] parts = address.split("/", 2); + address = parts[0]; + prefixLength = Integer.parseInt(parts[1]); + } + byte[] bytes = InetAddress.parseNumericAddress(address).getAddress(); + int integer = (bytes[3] & 0xFF) | (bytes[2] & 0xFF) << 8 | + (bytes[1] & 0xFF) << 16 | (bytes[0] & 0xFF) << 24; + if (bytes.length != 4 || prefixLength < 0 || prefixLength > 32 || + (prefixLength < 32 && (integer << prefixLength) != 0)) { + return false; + } + } + } catch (Exception e) { + return false; + } + return true; + } + private void loadCertificates(Spinner spinner, String prefix, int firstId, String selected) { Context context = getContext(); String first = (firstId == 0) ? "" : context.getString(firstId); @@ -279,6 +335,7 @@ class VpnDialog extends AlertDialog implements TextWatcher, OnItemSelectedListen profile.username = mUsername.getText().toString(); profile.password = mPassword.getText().toString(); profile.searchDomains = mSearchDomains.getText().toString().trim(); + profile.dnsServers = mDnsServers.getText().toString().trim(); profile.routes = mRoutes.getText().toString().trim(); // Then, save type-specific fields. diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index 4dbb6bd..2ab99e8 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -108,7 +108,7 @@ public class VpnSettings extends SettingsPreferenceFragment implements Credentials.getInstance().unlock(getActivity()); } else { // We already tried, but it is still not working! - getActivity().getFragmentManager().popBackStack(); + finishFragment(); } mUnlocking = !mUnlocking; return; @@ -429,8 +429,11 @@ public class VpnSettings extends SettingsPreferenceFragment implements config.interfaze = interfaze; config.session = profile.name; config.routes = profile.routes; + if (!profile.dnsServers.isEmpty()) { + config.dnsServers = Arrays.asList(profile.dnsServers.split(" +")); + } if (!profile.searchDomains.isEmpty()) { - config.searchDomains = Arrays.asList(profile.searchDomains.split(" ")); + config.searchDomains = Arrays.asList(profile.searchDomains.split(" +")); } mService.startLegacyVpn(config, racoon, mtpd); |