Loading res/layout/vpn_dialog.xml +0 −44 Original line number Diff line number Diff line Loading @@ -66,25 +66,6 @@ <EditText style="@style/vpn_value" android:id="@+id/server"/> <CheckBox style="@style/vpn_value" android:id="@+id/mppe" android:text="@string/vpn_mppe" android:visibility="gone"/> <LinearLayout android:id="@+id/l2tp" 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_l2tp_secret" android:labelFor="@+id/l2tp_secret"/> <EditText style="@style/vpn_value" android:id="@+id/l2tp_secret" android:password="true" android:hint="@string/vpn_not_used"/> </LinearLayout> <LinearLayout android:id="@+id/options_ipsec_identity" android:layout_width="match_parent" android:layout_height="wrap_content" Loading Loading @@ -154,31 +135,6 @@ android:layout_height="wrap_content" android:orientation="vertical" android:visibility="gone"> <LinearLayout android:id="@+id/network_options" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView style="@style/vpn_label" android:text="@string/vpn_search_domains" android:labelFor="@+id/search_domains"/> <EditText style="@style/vpn_value" android:id="@+id/search_domains" android:hint="@string/vpn_not_used"/> <TextView style="@style/vpn_label" android:text="@string/vpn_dns_servers" android:labelFor="@+id/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" android:labelFor="@+id/routes"/> <EditText style="@style/vpn_value" android:id="@+id/routes" android:hint="@string/vpn_not_used"/> </LinearLayout> <TextView android:id="@+id/vpn_proxy_settings_title" style="@style/vpn_label" Loading res/values/arrays.xml +1 −7 Original line number Diff line number Diff line Loading @@ -872,15 +872,9 @@ <item>1</item> </string-array> <!-- Match this with the constants in VpnProfile. --> <skip /> <!-- Match this with the array VPN_TYPES in ConfigDialog. --> <skip /> <!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] --> <string-array name="vpn_types" translatable="false"> <item>PPTP</item> <item>L2TP/IPSec PSK</item> <item>L2TP/IPSec RSA</item> <item>IPSec Xauth PSK</item> <item>IPSec Xauth RSA</item> <item>IPSec Hybrid RSA</item> <item>IKEv2/IPSec MSCHAPv2</item> <item>IKEv2/IPSec PSK</item> <item>IKEv2/IPSec RSA</item> Loading res/values/strings.xml +0 −26 Original line number Diff line number Diff line Loading @@ -6087,10 +6087,6 @@ <string name="vpn_type">Type</string> <!-- Input label for the server address of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_server">Server address</string> <!-- Checkbox label to enable PPP encryption for a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_mppe">PPP encryption (MPPE)</string> <!-- Input label for the L2TP secret of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_l2tp_secret">L2TP secret</string> <!-- Input label for the IPSec identifier of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_ipsec_identifier">IPSec identifier</string> <!-- Input label for the IPSec pre-shared key of a VPN profile. [CHAR LIMIT=40] --> Loading @@ -6103,12 +6099,6 @@ <string name="vpn_ipsec_server_cert">IPSec server certificate</string> <!-- Checkbox label to show advanced options of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_show_options">Show advanced options</string> <!-- Input label for the DNS search domains of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_search_domains">DNS search domains</string> <!-- Input label for the DNS servers of a VPN profile. [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 profile. [CHAR LIMIT=40] --> <string name="vpn_routes">Forwarding routes (e.g. 10.0.0.0/8)</string> <!-- Input label for the username of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_username">Username</string> <!-- Input label for the password of a VPN profile. [CHAR LIMIT=40] --> Loading @@ -6121,22 +6111,6 @@ <string name="vpn_no_ca_cert">(don\u2019t verify server)</string> <!-- Option to use the server certificate received from the VPN server. [CHAR LIMIT=40] --> <string name="vpn_no_server_cert">(received from server)</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: the selected VPN type doesn't support always-on. [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_type">This VPN type can\'t stay connected at all times</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: the server address is not in numeric form (e.g. 8.8.8.8). [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_server">Always-on VPN only supports numeric server addresses</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: no DNS is found. [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_no_dns">A DNS server must be specified for always-on VPN</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: DNS server addresses are not in numeric form (e.g. 8.8.8.8). [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_dns">DNS server addresses must be numeric for always-on VPN</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: generic error. [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_other">The information entered doesn\'t support src/com/android/settings/vpn2/ConfigDialog.java +36 −183 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.settings.vpn2; import static com.android.internal.net.VpnProfile.isLegacyType; import android.content.Context; import android.content.DialogInterface; import android.content.pm.PackageManager; Loading @@ -43,9 +41,6 @@ import com.android.net.module.util.ProxyUtils; import com.android.settings.R; import com.android.settings.utils.AndroidKeystoreAliasLoader; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; Loading @@ -60,13 +55,18 @@ class ConfigDialog extends AlertDialog implements TextWatcher, View.OnClickListener, AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener { private static final String TAG = "ConfigDialog"; // Vpn profile constants to match with R.array.vpn_types. private static final List<Integer> VPN_TYPES = List.of( VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS, VpnProfile.TYPE_IKEV2_IPSEC_PSK, VpnProfile.TYPE_IKEV2_IPSEC_RSA ); private final DialogInterface.OnClickListener mListener; private final VpnProfile mProfile; private boolean mEditing; private boolean mExists; private List<String> mTotalTypes; private List<String> mAllowedTypes; private View mView; Loading @@ -75,14 +75,9 @@ class ConfigDialog extends AlertDialog implements TextWatcher, private TextView mServer; private TextView mUsername; private TextView mPassword; private TextView mSearchDomains; private TextView mDnsServers; private TextView mRoutes; private Spinner mProxySettings; private TextView mProxyHost; private TextView mProxyPort; private CheckBox mMppe; private TextView mL2tpSecret; private TextView mIpsecIdentifier; private TextView mIpsecSecret; private Spinner mIpsecUserCert; Loading Loading @@ -116,14 +111,9 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mServer = (TextView) mView.findViewById(R.id.server); 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); mProxySettings = (Spinner) mView.findViewById(R.id.vpn_proxy_settings); mProxyHost = (TextView) mView.findViewById(R.id.vpn_proxy_host); mProxyPort = (TextView) mView.findViewById(R.id.vpn_proxy_port); mMppe = (CheckBox) mView.findViewById(R.id.mppe); mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret); mIpsecIdentifier = (TextView) mView.findViewById(R.id.ipsec_identifier); mIpsecSecret = (TextView) mView.findViewById(R.id.ipsec_secret); mIpsecUserCert = (Spinner) mView.findViewById(R.id.ipsec_user_cert); Loading @@ -137,29 +127,17 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // Second, copy values from the profile. mName.setText(mProfile.name); setTypesByFeature(mType); // Not all types will be available to the user. Find the index corresponding to the // string of the profile's type. if (mAllowedTypes != null && mTotalTypes != null) { mType.setSelection(mAllowedTypes.indexOf(mTotalTypes.get(mProfile.type))); } else { Log.w(TAG, "Allowed or Total vpn types not initialized when setting initial selection"); } mType.setSelection(convertVpnProfileConstantToTypeIndex(mProfile.type)); mServer.setText(mProfile.server); if (mProfile.saveLogin) { mUsername.setText(mProfile.username); mPassword.setText(mProfile.password); } mSearchDomains.setText(mProfile.searchDomains); mDnsServers.setText(mProfile.dnsServers); mRoutes.setText(mProfile.routes); if (mProfile.proxy != null) { mProxyHost.setText(mProfile.proxy.getHost()); int port = mProfile.proxy.getPort(); mProxyPort.setText(port == 0 ? "" : Integer.toString(port)); } mMppe.setChecked(mProfile.mppe); mL2tpSecret.setText(mProfile.l2tpSecret); mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium); mIpsecIdentifier.setText(mProfile.ipsecIdentifier); mIpsecSecret.setText(mProfile.ipsecSecret); final AndroidKeystoreAliasLoader androidKeystoreAliasLoader = Loading @@ -185,8 +163,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mServer.addTextChangedListener(this); mUsername.addTextChangedListener(this); mPassword.addTextChangedListener(this); mDnsServers.addTextChangedListener(this); mRoutes.addTextChangedListener(this); mProxySettings.setOnItemSelectedListener(this); mProxyHost.addTextChangedListener(this); mProxyPort.addTextChangedListener(this); Loading Loading @@ -217,12 +193,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // Create a button to forget the profile if it has already been saved.. setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(R.string.vpn_forget), mListener); // Display warning subtitle if the existing VPN is an insecure type... if (VpnProfile.isLegacyType(mProfile.type)) { TextView subtitle = mView.findViewById(R.id.dialog_alert_subtitle); subtitle.setVisibility(View.VISIBLE); } } // Create a button to save the profile. Loading Loading @@ -285,10 +255,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher, @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (parent == mType) { // Because the spinner may not display all available types, // convert the selected position into the actual vpn profile type integer. final int profileType = convertAllowedIndexToProfileType(position); changeType(profileType); changeType(VPN_TYPES.get(position)); } else if (parent == mProxySettings) { updateProxyFieldsVisibility(position); } Loading Loading @@ -330,17 +297,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } else { mAlwaysOnVpn.setChecked(false); mAlwaysOnVpn.setEnabled(false); if (!profile.isTypeValidForLockdown()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_type); } else if (isLegacyType(profile.type) && !profile.isServerAddressNumeric()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_server); } else if (isLegacyType(profile.type) && !profile.hasDns()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_no_dns); } else if (isLegacyType(profile.type) && !profile.areDnsAddressesNumeric()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_dns); } else { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_other); } mAlwaysOnInvalidReason.setVisibility(View.VISIBLE); } Loading Loading @@ -370,21 +327,14 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } private boolean isAdvancedOptionsEnabled() { return mSearchDomains.getText().length() > 0 || mDnsServers.getText().length() > 0 || mRoutes.getText().length() > 0 || mProxyHost.getText().length() > 0 || mProxyPort.getText().length() > 0; return mProxyHost.getText().length() > 0 || mProxyPort.getText().length() > 0; } private void configureAdvancedOptionsVisibility() { if (mShowOptions.isChecked() || isAdvancedOptionsEnabled()) { mView.findViewById(R.id.options).setVisibility(View.VISIBLE); mShowOptions.setVisibility(View.GONE); // Configure networking option visibility // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes final int visibility = isLegacyType(getSelectedVpnType()) ? View.VISIBLE : View.GONE; mView.findViewById(R.id.network_options).setVisibility(visibility); } else { mView.findViewById(R.id.options).setVisibility(View.GONE); mShowOptions.setVisibility(View.VISIBLE); Loading @@ -393,8 +343,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, private void changeType(int type) { // First, hide everything. mMppe.setVisibility(View.GONE); mView.findViewById(R.id.l2tp).setVisibility(View.GONE); mView.findViewById(R.id.ipsec_psk).setVisibility(View.GONE); mView.findViewById(R.id.ipsec_user).setVisibility(View.GONE); mView.findViewById(R.id.ipsec_peer).setVisibility(View.GONE); Loading @@ -403,34 +351,18 @@ class ConfigDialog extends AlertDialog implements TextWatcher, setUsernamePasswordVisibility(type); // Always enable identity for IKEv2/IPsec profiles. if (!isLegacyType(type)) { mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE); } // Then, unhide type-specific fields. switch (type) { case VpnProfile.TYPE_PPTP: mMppe.setVisibility(View.VISIBLE); break; case VpnProfile.TYPE_L2TP_IPSEC_PSK: mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: mView.findViewById(R.id.ipsec_psk).setVisibility(View.VISIBLE); mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE); break; case VpnProfile.TYPE_L2TP_IPSEC_RSA: mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: mView.findViewById(R.id.ipsec_user).setVisibility(View.VISIBLE); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through case VpnProfile.TYPE_IPSEC_HYBRID_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: mView.findViewById(R.id.ipsec_peer).setVisibility(View.VISIBLE); break; } Loading @@ -443,7 +375,8 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return false; } final int type = getSelectedVpnType(); final int position = mType.getSelectedItemPosition(); final int type = VPN_TYPES.get(position); if (!editing && requiresUsernamePassword(type)) { return mUsername.getText().length() != 0 && mPassword.getText().length() != 0; } Loading @@ -451,15 +384,8 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return false; } // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes if (isLegacyType(mProfile.type) && (!validateAddresses(mDnsServers.getText().toString(), false) || !validateAddresses(mRoutes.getText().toString(), true))) { return false; } // All IKEv2 methods require an identifier if (!isLegacyType(mProfile.type) && mIpsecIdentifier.getText().length() == 0) { if (mIpsecIdentifier.getText().length() == 0) { return false; } Loading @@ -468,56 +394,23 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } switch (type) { case VpnProfile.TYPE_PPTP: // fall through case VpnProfile.TYPE_IPSEC_HYBRID_RSA: // fall through case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: return true; case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through case VpnProfile.TYPE_L2TP_IPSEC_PSK: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: return mIpsecSecret.getText().length() != 0; case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through case VpnProfile.TYPE_L2TP_IPSEC_RSA: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: return mIpsecUserCert.getSelectedItemPosition() != 0; } 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 setTypesByFeature(Spinner typeSpinner) { String[] types = getContext().getResources().getStringArray(R.array.vpn_types); mTotalTypes = new ArrayList<>(Arrays.asList(types)); mAllowedTypes = new ArrayList<>(Arrays.asList(types)); if (types.length != VPN_TYPES.size()) { Log.wtf(TAG, "VPN_TYPES array length does not match string array"); } // Although FEATURE_IPSEC_TUNNELS should always be present in android S and beyond, // keep this check here just to be safe. if (!getContext().getPackageManager().hasSystemFeature( Loading @@ -532,17 +425,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mProfile.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS; } // Remove all types which are legacy types from the typesList if (!VpnProfile.isLegacyType(mProfile.type)) { for (int i = mAllowedTypes.size() - 1; i >= 0; i--) { // This must be removed from back to front in order to ensure index consistency if (VpnProfile.isLegacyType(i)) { mAllowedTypes.remove(i); } } types = mAllowedTypes.toArray(new String[0]); } final ArrayAdapter<String> adapter = new ArrayAdapter<String>( getContext(), android.R.layout.simple_spinner_item, types); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); Loading Loading @@ -606,20 +488,14 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // First, save common fields. VpnProfile profile = new VpnProfile(mProfile.key); profile.name = mName.getText().toString(); profile.type = getSelectedVpnType(); final int position = mType.getSelectedItemPosition(); profile.type = VPN_TYPES.get(position); profile.server = mServer.getText().toString().trim(); profile.username = mUsername.getText().toString(); profile.password = mPassword.getText().toString(); // Save fields based on VPN type. if (isLegacyType(profile.type)) { // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes profile.searchDomains = mSearchDomains.getText().toString().trim(); profile.dnsServers = mDnsServers.getText().toString().trim(); profile.routes = mRoutes.getText().toString().trim(); } else { profile.ipsecIdentifier = mIpsecIdentifier.getText().toString(); } if (hasProxy()) { String proxyHost = mProxyHost.getText().toString().trim(); Loading @@ -640,34 +516,17 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } // Then, save type-specific fields. switch (profile.type) { case VpnProfile.TYPE_PPTP: profile.mppe = mMppe.isChecked(); break; case VpnProfile.TYPE_L2TP_IPSEC_PSK: profile.l2tpSecret = mL2tpSecret.getText().toString(); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_PSK: profile.ipsecIdentifier = mIpsecIdentifier.getText().toString(); case VpnProfile.TYPE_IKEV2_IPSEC_PSK: profile.ipsecSecret = mIpsecSecret.getText().toString(); break; case VpnProfile.TYPE_IKEV2_IPSEC_RSA: if (mIpsecUserCert.getSelectedItemPosition() != 0) { profile.ipsecSecret = (String) mIpsecUserCert.getSelectedItem(); } // fall through case VpnProfile.TYPE_L2TP_IPSEC_RSA: profile.l2tpSecret = mL2tpSecret.getText().toString(); // fall through case VpnProfile.TYPE_IPSEC_XAUTH_RSA: if (mIpsecUserCert.getSelectedItemPosition() != 0) { profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem(); profile.ipsecSecret = profile.ipsecUserCert; } // fall through case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through case VpnProfile.TYPE_IPSEC_HYBRID_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: if (mIpsecCaCert.getSelectedItemPosition() != 0) { profile.ipsecCaCert = (String) mIpsecCaCert.getSelectedItem(); } Loading @@ -692,19 +551,13 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return ProxyUtils.validate(host, port, "") == ProxyUtils.PROXY_VALID; } private int getSelectedVpnType() { return convertAllowedIndexToProfileType(mType.getSelectedItemPosition()); } private int convertAllowedIndexToProfileType(int allowedSelectedPosition) { if (mAllowedTypes != null && mTotalTypes != null) { final String typeString = mAllowedTypes.get(allowedSelectedPosition); final int profileType = mTotalTypes.indexOf(typeString); return profileType; } else { Log.w(TAG, "Allowed or Total vpn types not initialized when converting protileType"); return allowedSelectedPosition; private int convertVpnProfileConstantToTypeIndex(int vpnType) { final int typeIndex = VPN_TYPES.indexOf(vpnType); if (typeIndex == -1) { // Existing legacy profile type Log.wtf(TAG, "Invalid existing profile type"); return 0; } return typeIndex; } } Loading
res/layout/vpn_dialog.xml +0 −44 Original line number Diff line number Diff line Loading @@ -66,25 +66,6 @@ <EditText style="@style/vpn_value" android:id="@+id/server"/> <CheckBox style="@style/vpn_value" android:id="@+id/mppe" android:text="@string/vpn_mppe" android:visibility="gone"/> <LinearLayout android:id="@+id/l2tp" 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_l2tp_secret" android:labelFor="@+id/l2tp_secret"/> <EditText style="@style/vpn_value" android:id="@+id/l2tp_secret" android:password="true" android:hint="@string/vpn_not_used"/> </LinearLayout> <LinearLayout android:id="@+id/options_ipsec_identity" android:layout_width="match_parent" android:layout_height="wrap_content" Loading Loading @@ -154,31 +135,6 @@ android:layout_height="wrap_content" android:orientation="vertical" android:visibility="gone"> <LinearLayout android:id="@+id/network_options" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView style="@style/vpn_label" android:text="@string/vpn_search_domains" android:labelFor="@+id/search_domains"/> <EditText style="@style/vpn_value" android:id="@+id/search_domains" android:hint="@string/vpn_not_used"/> <TextView style="@style/vpn_label" android:text="@string/vpn_dns_servers" android:labelFor="@+id/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" android:labelFor="@+id/routes"/> <EditText style="@style/vpn_value" android:id="@+id/routes" android:hint="@string/vpn_not_used"/> </LinearLayout> <TextView android:id="@+id/vpn_proxy_settings_title" style="@style/vpn_label" Loading
res/values/arrays.xml +1 −7 Original line number Diff line number Diff line Loading @@ -872,15 +872,9 @@ <item>1</item> </string-array> <!-- Match this with the constants in VpnProfile. --> <skip /> <!-- Match this with the array VPN_TYPES in ConfigDialog. --> <skip /> <!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] --> <string-array name="vpn_types" translatable="false"> <item>PPTP</item> <item>L2TP/IPSec PSK</item> <item>L2TP/IPSec RSA</item> <item>IPSec Xauth PSK</item> <item>IPSec Xauth RSA</item> <item>IPSec Hybrid RSA</item> <item>IKEv2/IPSec MSCHAPv2</item> <item>IKEv2/IPSec PSK</item> <item>IKEv2/IPSec RSA</item> Loading
res/values/strings.xml +0 −26 Original line number Diff line number Diff line Loading @@ -6087,10 +6087,6 @@ <string name="vpn_type">Type</string> <!-- Input label for the server address of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_server">Server address</string> <!-- Checkbox label to enable PPP encryption for a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_mppe">PPP encryption (MPPE)</string> <!-- Input label for the L2TP secret of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_l2tp_secret">L2TP secret</string> <!-- Input label for the IPSec identifier of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_ipsec_identifier">IPSec identifier</string> <!-- Input label for the IPSec pre-shared key of a VPN profile. [CHAR LIMIT=40] --> Loading @@ -6103,12 +6099,6 @@ <string name="vpn_ipsec_server_cert">IPSec server certificate</string> <!-- Checkbox label to show advanced options of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_show_options">Show advanced options</string> <!-- Input label for the DNS search domains of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_search_domains">DNS search domains</string> <!-- Input label for the DNS servers of a VPN profile. [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 profile. [CHAR LIMIT=40] --> <string name="vpn_routes">Forwarding routes (e.g. 10.0.0.0/8)</string> <!-- Input label for the username of a VPN profile. [CHAR LIMIT=40] --> <string name="vpn_username">Username</string> <!-- Input label for the password of a VPN profile. [CHAR LIMIT=40] --> Loading @@ -6121,22 +6111,6 @@ <string name="vpn_no_ca_cert">(don\u2019t verify server)</string> <!-- Option to use the server certificate received from the VPN server. [CHAR LIMIT=40] --> <string name="vpn_no_server_cert">(received from server)</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: the selected VPN type doesn't support always-on. [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_type">This VPN type can\'t stay connected at all times</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: the server address is not in numeric form (e.g. 8.8.8.8). [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_server">Always-on VPN only supports numeric server addresses</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: no DNS is found. [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_no_dns">A DNS server must be specified for always-on VPN</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: DNS server addresses are not in numeric form (e.g. 8.8.8.8). [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_dns">DNS server addresses must be numeric for always-on VPN</string> <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled: generic error. [CHAR LIMIT=120] --> <string name="vpn_always_on_invalid_reason_other">The information entered doesn\'t support
src/com/android/settings/vpn2/ConfigDialog.java +36 −183 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.settings.vpn2; import static com.android.internal.net.VpnProfile.isLegacyType; import android.content.Context; import android.content.DialogInterface; import android.content.pm.PackageManager; Loading @@ -43,9 +41,6 @@ import com.android.net.module.util.ProxyUtils; import com.android.settings.R; import com.android.settings.utils.AndroidKeystoreAliasLoader; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; Loading @@ -60,13 +55,18 @@ class ConfigDialog extends AlertDialog implements TextWatcher, View.OnClickListener, AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener { private static final String TAG = "ConfigDialog"; // Vpn profile constants to match with R.array.vpn_types. private static final List<Integer> VPN_TYPES = List.of( VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS, VpnProfile.TYPE_IKEV2_IPSEC_PSK, VpnProfile.TYPE_IKEV2_IPSEC_RSA ); private final DialogInterface.OnClickListener mListener; private final VpnProfile mProfile; private boolean mEditing; private boolean mExists; private List<String> mTotalTypes; private List<String> mAllowedTypes; private View mView; Loading @@ -75,14 +75,9 @@ class ConfigDialog extends AlertDialog implements TextWatcher, private TextView mServer; private TextView mUsername; private TextView mPassword; private TextView mSearchDomains; private TextView mDnsServers; private TextView mRoutes; private Spinner mProxySettings; private TextView mProxyHost; private TextView mProxyPort; private CheckBox mMppe; private TextView mL2tpSecret; private TextView mIpsecIdentifier; private TextView mIpsecSecret; private Spinner mIpsecUserCert; Loading Loading @@ -116,14 +111,9 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mServer = (TextView) mView.findViewById(R.id.server); 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); mProxySettings = (Spinner) mView.findViewById(R.id.vpn_proxy_settings); mProxyHost = (TextView) mView.findViewById(R.id.vpn_proxy_host); mProxyPort = (TextView) mView.findViewById(R.id.vpn_proxy_port); mMppe = (CheckBox) mView.findViewById(R.id.mppe); mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret); mIpsecIdentifier = (TextView) mView.findViewById(R.id.ipsec_identifier); mIpsecSecret = (TextView) mView.findViewById(R.id.ipsec_secret); mIpsecUserCert = (Spinner) mView.findViewById(R.id.ipsec_user_cert); Loading @@ -137,29 +127,17 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // Second, copy values from the profile. mName.setText(mProfile.name); setTypesByFeature(mType); // Not all types will be available to the user. Find the index corresponding to the // string of the profile's type. if (mAllowedTypes != null && mTotalTypes != null) { mType.setSelection(mAllowedTypes.indexOf(mTotalTypes.get(mProfile.type))); } else { Log.w(TAG, "Allowed or Total vpn types not initialized when setting initial selection"); } mType.setSelection(convertVpnProfileConstantToTypeIndex(mProfile.type)); mServer.setText(mProfile.server); if (mProfile.saveLogin) { mUsername.setText(mProfile.username); mPassword.setText(mProfile.password); } mSearchDomains.setText(mProfile.searchDomains); mDnsServers.setText(mProfile.dnsServers); mRoutes.setText(mProfile.routes); if (mProfile.proxy != null) { mProxyHost.setText(mProfile.proxy.getHost()); int port = mProfile.proxy.getPort(); mProxyPort.setText(port == 0 ? "" : Integer.toString(port)); } mMppe.setChecked(mProfile.mppe); mL2tpSecret.setText(mProfile.l2tpSecret); mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium); mIpsecIdentifier.setText(mProfile.ipsecIdentifier); mIpsecSecret.setText(mProfile.ipsecSecret); final AndroidKeystoreAliasLoader androidKeystoreAliasLoader = Loading @@ -185,8 +163,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mServer.addTextChangedListener(this); mUsername.addTextChangedListener(this); mPassword.addTextChangedListener(this); mDnsServers.addTextChangedListener(this); mRoutes.addTextChangedListener(this); mProxySettings.setOnItemSelectedListener(this); mProxyHost.addTextChangedListener(this); mProxyPort.addTextChangedListener(this); Loading Loading @@ -217,12 +193,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // Create a button to forget the profile if it has already been saved.. setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(R.string.vpn_forget), mListener); // Display warning subtitle if the existing VPN is an insecure type... if (VpnProfile.isLegacyType(mProfile.type)) { TextView subtitle = mView.findViewById(R.id.dialog_alert_subtitle); subtitle.setVisibility(View.VISIBLE); } } // Create a button to save the profile. Loading Loading @@ -285,10 +255,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher, @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (parent == mType) { // Because the spinner may not display all available types, // convert the selected position into the actual vpn profile type integer. final int profileType = convertAllowedIndexToProfileType(position); changeType(profileType); changeType(VPN_TYPES.get(position)); } else if (parent == mProxySettings) { updateProxyFieldsVisibility(position); } Loading Loading @@ -330,17 +297,7 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } else { mAlwaysOnVpn.setChecked(false); mAlwaysOnVpn.setEnabled(false); if (!profile.isTypeValidForLockdown()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_type); } else if (isLegacyType(profile.type) && !profile.isServerAddressNumeric()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_server); } else if (isLegacyType(profile.type) && !profile.hasDns()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_no_dns); } else if (isLegacyType(profile.type) && !profile.areDnsAddressesNumeric()) { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_dns); } else { mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_other); } mAlwaysOnInvalidReason.setVisibility(View.VISIBLE); } Loading Loading @@ -370,21 +327,14 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } private boolean isAdvancedOptionsEnabled() { return mSearchDomains.getText().length() > 0 || mDnsServers.getText().length() > 0 || mRoutes.getText().length() > 0 || mProxyHost.getText().length() > 0 || mProxyPort.getText().length() > 0; return mProxyHost.getText().length() > 0 || mProxyPort.getText().length() > 0; } private void configureAdvancedOptionsVisibility() { if (mShowOptions.isChecked() || isAdvancedOptionsEnabled()) { mView.findViewById(R.id.options).setVisibility(View.VISIBLE); mShowOptions.setVisibility(View.GONE); // Configure networking option visibility // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes final int visibility = isLegacyType(getSelectedVpnType()) ? View.VISIBLE : View.GONE; mView.findViewById(R.id.network_options).setVisibility(visibility); } else { mView.findViewById(R.id.options).setVisibility(View.GONE); mShowOptions.setVisibility(View.VISIBLE); Loading @@ -393,8 +343,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, private void changeType(int type) { // First, hide everything. mMppe.setVisibility(View.GONE); mView.findViewById(R.id.l2tp).setVisibility(View.GONE); mView.findViewById(R.id.ipsec_psk).setVisibility(View.GONE); mView.findViewById(R.id.ipsec_user).setVisibility(View.GONE); mView.findViewById(R.id.ipsec_peer).setVisibility(View.GONE); Loading @@ -403,34 +351,18 @@ class ConfigDialog extends AlertDialog implements TextWatcher, setUsernamePasswordVisibility(type); // Always enable identity for IKEv2/IPsec profiles. if (!isLegacyType(type)) { mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE); } // Then, unhide type-specific fields. switch (type) { case VpnProfile.TYPE_PPTP: mMppe.setVisibility(View.VISIBLE); break; case VpnProfile.TYPE_L2TP_IPSEC_PSK: mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: mView.findViewById(R.id.ipsec_psk).setVisibility(View.VISIBLE); mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE); break; case VpnProfile.TYPE_L2TP_IPSEC_RSA: mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: mView.findViewById(R.id.ipsec_user).setVisibility(View.VISIBLE); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through case VpnProfile.TYPE_IPSEC_HYBRID_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: mView.findViewById(R.id.ipsec_peer).setVisibility(View.VISIBLE); break; } Loading @@ -443,7 +375,8 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return false; } final int type = getSelectedVpnType(); final int position = mType.getSelectedItemPosition(); final int type = VPN_TYPES.get(position); if (!editing && requiresUsernamePassword(type)) { return mUsername.getText().length() != 0 && mPassword.getText().length() != 0; } Loading @@ -451,15 +384,8 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return false; } // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes if (isLegacyType(mProfile.type) && (!validateAddresses(mDnsServers.getText().toString(), false) || !validateAddresses(mRoutes.getText().toString(), true))) { return false; } // All IKEv2 methods require an identifier if (!isLegacyType(mProfile.type) && mIpsecIdentifier.getText().length() == 0) { if (mIpsecIdentifier.getText().length() == 0) { return false; } Loading @@ -468,56 +394,23 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } switch (type) { case VpnProfile.TYPE_PPTP: // fall through case VpnProfile.TYPE_IPSEC_HYBRID_RSA: // fall through case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: return true; case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through case VpnProfile.TYPE_L2TP_IPSEC_PSK: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_PSK: return mIpsecSecret.getText().length() != 0; case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through case VpnProfile.TYPE_L2TP_IPSEC_RSA: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: return mIpsecUserCert.getSelectedItemPosition() != 0; } 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 setTypesByFeature(Spinner typeSpinner) { String[] types = getContext().getResources().getStringArray(R.array.vpn_types); mTotalTypes = new ArrayList<>(Arrays.asList(types)); mAllowedTypes = new ArrayList<>(Arrays.asList(types)); if (types.length != VPN_TYPES.size()) { Log.wtf(TAG, "VPN_TYPES array length does not match string array"); } // Although FEATURE_IPSEC_TUNNELS should always be present in android S and beyond, // keep this check here just to be safe. if (!getContext().getPackageManager().hasSystemFeature( Loading @@ -532,17 +425,6 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mProfile.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS; } // Remove all types which are legacy types from the typesList if (!VpnProfile.isLegacyType(mProfile.type)) { for (int i = mAllowedTypes.size() - 1; i >= 0; i--) { // This must be removed from back to front in order to ensure index consistency if (VpnProfile.isLegacyType(i)) { mAllowedTypes.remove(i); } } types = mAllowedTypes.toArray(new String[0]); } final ArrayAdapter<String> adapter = new ArrayAdapter<String>( getContext(), android.R.layout.simple_spinner_item, types); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); Loading Loading @@ -606,20 +488,14 @@ class ConfigDialog extends AlertDialog implements TextWatcher, // First, save common fields. VpnProfile profile = new VpnProfile(mProfile.key); profile.name = mName.getText().toString(); profile.type = getSelectedVpnType(); final int position = mType.getSelectedItemPosition(); profile.type = VPN_TYPES.get(position); profile.server = mServer.getText().toString().trim(); profile.username = mUsername.getText().toString(); profile.password = mPassword.getText().toString(); // Save fields based on VPN type. if (isLegacyType(profile.type)) { // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes profile.searchDomains = mSearchDomains.getText().toString().trim(); profile.dnsServers = mDnsServers.getText().toString().trim(); profile.routes = mRoutes.getText().toString().trim(); } else { profile.ipsecIdentifier = mIpsecIdentifier.getText().toString(); } if (hasProxy()) { String proxyHost = mProxyHost.getText().toString().trim(); Loading @@ -640,34 +516,17 @@ class ConfigDialog extends AlertDialog implements TextWatcher, } // Then, save type-specific fields. switch (profile.type) { case VpnProfile.TYPE_PPTP: profile.mppe = mMppe.isChecked(); break; case VpnProfile.TYPE_L2TP_IPSEC_PSK: profile.l2tpSecret = mL2tpSecret.getText().toString(); // fall through case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through case VpnProfile.TYPE_IPSEC_XAUTH_PSK: profile.ipsecIdentifier = mIpsecIdentifier.getText().toString(); case VpnProfile.TYPE_IKEV2_IPSEC_PSK: profile.ipsecSecret = mIpsecSecret.getText().toString(); break; case VpnProfile.TYPE_IKEV2_IPSEC_RSA: if (mIpsecUserCert.getSelectedItemPosition() != 0) { profile.ipsecSecret = (String) mIpsecUserCert.getSelectedItem(); } // fall through case VpnProfile.TYPE_L2TP_IPSEC_RSA: profile.l2tpSecret = mL2tpSecret.getText().toString(); // fall through case VpnProfile.TYPE_IPSEC_XAUTH_RSA: if (mIpsecUserCert.getSelectedItemPosition() != 0) { profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem(); profile.ipsecSecret = profile.ipsecUserCert; } // fall through case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through case VpnProfile.TYPE_IPSEC_HYBRID_RSA: case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: if (mIpsecCaCert.getSelectedItemPosition() != 0) { profile.ipsecCaCert = (String) mIpsecCaCert.getSelectedItem(); } Loading @@ -692,19 +551,13 @@ class ConfigDialog extends AlertDialog implements TextWatcher, return ProxyUtils.validate(host, port, "") == ProxyUtils.PROXY_VALID; } private int getSelectedVpnType() { return convertAllowedIndexToProfileType(mType.getSelectedItemPosition()); } private int convertAllowedIndexToProfileType(int allowedSelectedPosition) { if (mAllowedTypes != null && mTotalTypes != null) { final String typeString = mAllowedTypes.get(allowedSelectedPosition); final int profileType = mTotalTypes.indexOf(typeString); return profileType; } else { Log.w(TAG, "Allowed or Total vpn types not initialized when converting protileType"); return allowedSelectedPosition; private int convertVpnProfileConstantToTypeIndex(int vpnType) { final int typeIndex = VPN_TYPES.indexOf(vpnType); if (typeIndex == -1) { // Existing legacy profile type Log.wtf(TAG, "Invalid existing profile type"); return 0; } return typeIndex; } }