Merge "Update Settings UI for IKEv2/IPsec VPNs" am: 9579a76913 am: 033a021251

Change-Id: I62bce794bffab8425a4991484986481fd308933b
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index a626205..73f669b 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -65,7 +65,7 @@
                         android:hint="@string/vpn_not_used"/>
             </LinearLayout>
 
-            <LinearLayout android:id="@+id/ipsec_psk"
+            <LinearLayout android:id="@+id/options_ipsec_identity"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:orientation="vertical"
@@ -75,7 +75,13 @@
                         android:labelFor="@+id/ipsec_identifier"/>
                 <EditText style="@style/vpn_value" android:id="@+id/ipsec_identifier"
                         android:hint="@string/vpn_not_used"/>
+            </LinearLayout>
 
+            <LinearLayout android:id="@+id/ipsec_psk"
+                    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_ipsec_secret"
                         android:labelFor="@+id/ipsec_secret"/>
@@ -123,23 +129,28 @@
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
                 android:visibility="gone">
-            <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"/>
+            <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_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"/>
+                <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"
@@ -182,11 +193,10 @@
             </LinearLayout>
         </LinearLayout>
 
-        <LinearLayout android:id="@+id/login"
+        <LinearLayout android:id="@+id/userpass"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
-                android:orientation="vertical"
-                android:animateLayoutChanges="true">
+                android:orientation="vertical">
 
             <TextView style="@style/vpn_label"
                     android:text="@string/vpn_username"
@@ -202,6 +212,13 @@
             <CheckBox style="@style/vpn_value" android:id="@+id/save_login"
                     android:singleLine="false"
                     android:text="@string/vpn_save_login"/>
+        </LinearLayout>
+
+        <LinearLayout android:id="@+id/connect"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:animateLayoutChanges="true">
             <CheckBox style="@style/vpn_value" android:id="@+id/always_on_vpn"
                 android:singleLine="false"
                 android:text="@string/vpn_menu_lockdown"/>
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index 9f2176c..a0aac19 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.vpn2;
 
+import static com.android.internal.net.VpnProfile.isLegacyType;
+
 import android.content.Context;
 import android.content.DialogInterface;
 import android.net.Proxy;
@@ -191,12 +193,7 @@
             // Hide 'save login' when we are editing.
             mSaveLogin.setVisibility(View.GONE);
 
-            // Switch to advanced view immediately if any advanced options are on
-            if (!mProfile.searchDomains.isEmpty() || !mProfile.dnsServers.isEmpty() ||
-                    !mProfile.routes.isEmpty() || (mProfile.proxy != null &&
-                    (!mProfile.proxy.getHost().isEmpty() || mProfile.proxy.getPort() != 0))) {
-                showAdvancedOptions();
-            }
+            configureAdvancedOptionsVisibility();
 
             // Create a button to forget the profile if it has already been saved..
             if (mExists) {
@@ -210,6 +207,8 @@
         } else {
             setTitle(context.getString(R.string.vpn_connect_to, mProfile.name));
 
+            setUsernamePasswordVisibility(mProfile.type);
+
             // Create a button to connect the network.
             setButton(DialogInterface.BUTTON_POSITIVE,
                     context.getString(R.string.vpn_connect), mListener);
@@ -236,9 +235,7 @@
 
         // Visibility isn't restored by super.onRestoreInstanceState, so re-show the advanced
         // options here if they were already revealed or set.
-        if (mShowOptions.isChecked()) {
-            showAdvancedOptions();
-        }
+        configureAdvancedOptionsVisibility();
     }
 
     @Override
@@ -257,7 +254,7 @@
     @Override
     public void onClick(View view) {
         if (view == mShowOptions) {
-            showAdvancedOptions();
+            configureAdvancedOptionsVisibility();
         }
     }
 
@@ -308,11 +305,11 @@
             mAlwaysOnVpn.setEnabled(false);
             if (!profile.isTypeValidForLockdown()) {
                 mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_type);
-            } else if (!profile.isServerAddressNumeric()) {
+            } else if (isLegacyType(profile.type) && !profile.isServerAddressNumeric()) {
                 mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_server);
-            } else if (!profile.hasDns()) {
+            } else if (isLegacyType(profile.type) && !profile.hasDns()) {
                 mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_no_dns);
-            } else if (!profile.areDnsAddressesNumeric()) {
+            } 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);
@@ -345,9 +342,26 @@
         mView.findViewById(R.id.vpn_proxy_fields).setVisibility(visible);
     }
 
-    private void showAdvancedOptions() {
-        mView.findViewById(R.id.options).setVisibility(View.VISIBLE);
-        mShowOptions.setVisibility(View.GONE);
+    private boolean hasAdvancedOptionsEnabled() {
+        return mSearchDomains.getText().length() > 0 || mDnsServers.getText().length() > 0 ||
+                    mRoutes.getText().length() > 0 || mProxyHost.getText().length() > 0
+                    || mProxyPort.getText().length() > 0;
+    }
+
+    private void configureAdvancedOptionsVisibility() {
+        if (mShowOptions.isChecked() || hasAdvancedOptionsEnabled()) {
+            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(mType.getSelectedItemPosition()) ? 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);
+        }
     }
 
     private void changeType(int type) {
@@ -357,6 +371,14 @@
         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);
+        mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.GONE);
+
+        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) {
@@ -367,32 +389,50 @@
             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:
                 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:
                 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:
                 mView.findViewById(R.id.ipsec_peer).setVisibility(View.VISIBLE);
                 break;
         }
+
+        configureAdvancedOptionsVisibility();
     }
 
     private boolean validate(boolean editing) {
         if (mAlwaysOnVpn.isChecked() && !getProfile().isValidLockdownProfile()) {
             return false;
         }
-        if (!editing) {
+
+        final int type = mType.getSelectedItemPosition();
+        if (!editing && requiresUsernamePassword(type)) {
             return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
         }
-        if (mName.getText().length() == 0 || mServer.getText().length() == 0 ||
-                !validateAddresses(mDnsServers.getText().toString(), false) ||
-                !validateAddresses(mRoutes.getText().toString(), true)) {
+        if (mName.getText().length() == 0 || mServer.getText().length() == 0) {
+            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) {
             return false;
         }
 
@@ -400,16 +440,19 @@
             return false;
         }
 
-        switch (mType.getSelectedItemPosition()) {
-            case VpnProfile.TYPE_PPTP:
-            case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+        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_L2TP_IPSEC_PSK:
+            case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through
+            case VpnProfile.TYPE_L2TP_IPSEC_PSK: // fall through
             case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
                 return mIpsecSecret.getText().length() != 0;
 
-            case VpnProfile.TYPE_L2TP_IPSEC_RSA:
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
+            case VpnProfile.TYPE_L2TP_IPSEC_RSA: // fall through
             case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
                 return mIpsecUserCert.getSelectedItemPosition() != 0;
         }
@@ -470,6 +513,21 @@
         }
     }
 
+    private void setUsernamePasswordVisibility(int type) {
+        mView.findViewById(R.id.userpass).setVisibility(
+                requiresUsernamePassword(type) ? View.VISIBLE : View.GONE);
+    }
+
+    private boolean requiresUsernamePassword(int type) {
+        switch (type) {
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
+            case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
+                return false;
+            default:
+                return true;
+        }
+    }
+
     boolean isEditing() {
         return mEditing;
     }
@@ -486,9 +544,17 @@
         profile.server = mServer.getText().toString().trim();
         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();
+
+        // 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();
             String proxyPort = mProxyPort.getText().toString().trim();
@@ -508,6 +574,7 @@
             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();
                 profile.ipsecSecret = mIpsecSecret.getText().toString();
@@ -516,11 +583,13 @@
             case VpnProfile.TYPE_L2TP_IPSEC_RSA:
                 profile.l2tpSecret = mL2tpSecret.getText().toString();
                 // fall through
+            case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
             case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
                 if (mIpsecUserCert.getSelectedItemPosition() != 0) {
                     profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem();
                 }
                 // fall through
+            case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through
             case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
                 if (mIpsecCaCert.getSelectedItemPosition() != 0) {
                     profile.ipsecCaCert = (String) mIpsecCaCert.getSelectedItem();