Adding an option to install a certificate from the CA certificate menu

For CA ceritificate we only can install in Network Preferences > Advaned
> Install certificates. So we add the option for user to install when
you setup the wifi network. After you install the certificate, you can
see the certificate in your menu.

Bug: 176998563
Test: manual test
make RunSettingsRoboTests ROBOTEST_FILTER=WifiConfigController2Test

Change-Id: I532b12f9277c6a15c649907fa3711c807566c88e
diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java
index 2ed213b..4adc672 100644
--- a/src/com/android/settings/wifi/AddNetworkFragment.java
+++ b/src/com/android/settings/wifi/AddNetworkFragment.java
@@ -86,6 +86,13 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mUIController.showSecurityFields(
+            /* refreshEapMethods */ false, /* refreshCertificates */ true);
+    }
+
+    @Override
     public void onViewStateRestored(Bundle savedInstanceState) {
         super.onViewStateRestored(savedInstanceState);
         mUIController.updatePassword();
@@ -110,7 +117,6 @@
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         super.onActivityResult(requestCode, resultCode, data);
-
         if (requestCode == REQUEST_CODE_WIFI_DPP_ENROLLEE_QR_CODE_SCANNER) {
             if (resultCode != Activity.RESULT_OK) {
                 return;
diff --git a/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java b/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java
index c36a298..d2f5090 100644
--- a/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java
+++ b/src/com/android/settings/wifi/ConfigureWifiEntryFragment.java
@@ -128,6 +128,13 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mUiController.showSecurityFields(
+            /* refreshEapMethods */ false, /* refreshCertificates */ true);
+    }
+
+    @Override
     public void onViewStateRestored(Bundle savedInstanceState) {
         super.onViewStateRestored(savedInstanceState);
         mUiController.updatePassword();
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index 1967371..65ac451 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -16,7 +16,10 @@
 
 package com.android.settings.wifi;
 
+import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.net.InetAddresses;
 import android.net.IpConfiguration;
@@ -32,6 +35,7 @@
 import android.net.wifi.WifiEnterpriseConfig.Phase2;
 import android.net.wifi.WifiManager;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.security.keystore.KeyProperties;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -144,6 +148,15 @@
         UNDESIRED_CERTIFICATE_MACRANDSAPSECRET
     };
 
+    /* These values are for install certificate */
+    private static final String ACTION_INSTALL_CERTS = "android.credentials.INSTALL";
+    private static final String PACKAGE_INSTALL_CERTS = "com.android.certinstaller";
+    private static final String CLASS_INSTALL_CERTS = "com.android.certinstaller.CertInstallerMain";
+    private static final String KEY_INSTALL_CERTIFICATE = "certificate_install_usage";
+    private static final String INSTALL_CERTIFICATE_VALUE = "wifi";
+
+    protected int REQUEST_INSTALL_CERTS = 1;
+
     /* Phase2 methods supported by PEAP are limited */
     private ArrayAdapter<CharSequence> mPhase2PeapAdapter;
     /* Phase2 methods supported by TTLS are limited */
@@ -159,12 +172,13 @@
     private String mMultipleCertSetString;
     private String mUseSystemCertsString;
     private String mDoNotProvideEapUserCertString;
+    @VisibleForTesting String mInstallCertsString;
 
     private Spinner mSecuritySpinner;
     @VisibleForTesting Spinner mEapMethodSpinner;
     private int mLastShownEapMethod;
     @VisibleForTesting Spinner mEapSimSpinner;    // For EAP-SIM, EAP-AKA and EAP-AKA-PRIME.
-    private Spinner mEapCaCertSpinner;
+    @VisibleForTesting Spinner mEapCaCertSpinner;
     private Spinner mEapOcspSpinner;
     private TextView mEapDomainView;
     private Spinner mPhase2Spinner;
@@ -258,6 +272,7 @@
         mUseSystemCertsString = mContext.getString(R.string.wifi_use_system_certs);
         mDoNotProvideEapUserCertString =
             mContext.getString(R.string.wifi_do_not_provide_eap_user_cert);
+        mInstallCertsString = mContext.getString(R.string.wifi_install_credentials);
 
         mSsidScanButton = (ImageButton) mView.findViewById(R.id.ssid_scanner_button);
         mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
@@ -942,7 +957,7 @@
         }
     }
 
-    private void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
+    protected void showSecurityFields(boolean refreshEapMethods, boolean refreshCertificates) {
         if (mWifiEntrySecurity == WifiEntry.SECURITY_NONE
                 || mWifiEntrySecurity == WifiEntry.SECURITY_OWE) {
             mView.findViewById(R.id.security_fields).setVisibility(View.GONE);
@@ -1031,11 +1046,8 @@
                     mDoNotProvideEapUserCertString,
                     false /* showMultipleCerts */,
                     false /* showUsePreinstalledCertOption */);
-            // To avoid the user connects to a non-secure network unexpectedly,
-            // request using system trusted certificates by default
-            // unless the user explicitly chooses "Do not validate" or other
-            // CA certificates.
-            setSelection(mEapCaCertSpinner, mUseSystemCertsString);
+
+            setSelection(mEapCaCertSpinner, mUnspecifiedCertString);
         }
 
         // Modifying an existing network
@@ -1494,6 +1506,7 @@
         }
         if (showUsePreinstalledCertOption) {
             certs.add(mUseSystemCertsString);
+            certs.add(mInstallCertsString);
         }
 
         if (choices != null && choices.size() != 0) {
@@ -1658,9 +1671,13 @@
             final int selectedItemPosition = mEapMethodSpinner.getSelectedItemPosition();
             if (mLastShownEapMethod != selectedItemPosition) {
                 mLastShownEapMethod = selectedItemPosition;
-                showSecurityFields(/* refreshEapMethods */ false, /* refreshCertificates */ true);
+                showSecurityFields(/* refreshEapMethods */false, /* refreshCertificates */ true);
             }
         } else if (parent == mEapCaCertSpinner) {
+            String selectedItem = parent.getItemAtPosition(position).toString();
+            if (selectedItem.equals(mInstallCertsString)) {
+                startActivityForInstallCerts();
+            }
             showSecurityFields(/* refreshEapMethods */ false, /* refreshCertificates */ false);
         } else if (parent == mPhase2Spinner
                 && mEapMethodSpinner.getSelectedItemPosition() == WIFI_EAP_METHOD_PEAP) {
@@ -1683,6 +1700,18 @@
     }
 
     /**
+     * Start the install page for user to install the existing certificate.
+     */
+    private void startActivityForInstallCerts() {
+        Intent intent = new Intent(ACTION_INSTALL_CERTS);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setComponent(new ComponentName(PACKAGE_INSTALL_CERTS, CLASS_INSTALL_CERTS));
+        intent.putExtra(KEY_INSTALL_CERTIFICATE, INSTALL_CERTIFICATE_VALUE);
+
+        mContext.startActivity(intent);
+    }
+
+    /**
      * Make the characters of the password visible if show_password is checked.
      */
     public void updatePassword() {
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
index d227ac1..ff0d7b2 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
@@ -18,11 +18,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Resources;
 import android.net.IpConfiguration;
 import android.net.wifi.WifiConfiguration;
@@ -30,12 +36,14 @@
 import android.net.wifi.WifiEnterpriseConfig.Eap;
 import android.net.wifi.WifiEnterpriseConfig.Phase2;
 import android.net.wifi.WifiManager;
+import android.os.UserHandle;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.CheckBox;
 import android.widget.LinearLayout;
@@ -54,6 +62,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -81,6 +90,7 @@
     private Spinner mHiddenSettingsSpinner;
     private Spinner mEapCaCertSpinner;
     private Spinner mEapUserCertSpinner;
+    private String mUnspecifiedCertString;
     private String mUseSystemCertsString;
     private String mDoNotProvideEapUserCertString;
     private ShadowSubscriptionManager mShadowSubscriptionManager;
@@ -107,10 +117,16 @@
     private static final String SAVED_CA_CERT = "saved CA cert";
     private static final String SAVED_USER_CERT = "saved user cert";
 
+    private static final int POSITION_SYSTEM_CERT = 1;
+    private static final int POSITION_INSTALL_CERT = 2;
+    private static final String ACTION_INSTALL_CERTS = "android.credentials.INSTALL";
+    private static final String KEY_INSTALL_CERTIFICATE = "certificate_install_usage";
+    private static final String INSTALL_CERTIFICATE_VALUE = "wifi";
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = spy(RuntimeEnvironment.application);
         when(mConfigUiBase.getContext()).thenReturn(mContext);
         when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_PSK);
         mView = LayoutInflater.from(mContext).inflate(R.layout.wifi_dialog, null);
@@ -119,6 +135,7 @@
         mEapCaCertSpinner = mView.findViewById(R.id.ca_cert);
         mEapUserCertSpinner = mView.findViewById(R.id.user_cert);
         mUseSystemCertsString = mContext.getString(R.string.wifi_use_system_certs);
+        mUnspecifiedCertString = mContext.getString(R.string.wifi_unspecified);
         mDoNotProvideEapUserCertString =
                 mContext.getString(R.string.wifi_do_not_provide_eap_user_cert);
         ipSettingsSpinner.setSelection(DHCP);
@@ -709,7 +726,6 @@
                 Phase2.AKA_PRIME);
     }
 
-
     @Test
     public void getEapConfig_withPeapPhase2Unknown_shouldContainNoneMethod() {
         setUpModifyingSavedPeapConfigController();
@@ -835,10 +851,31 @@
     public void loadCaCertificateValue_shouldPersistentAsDefault() {
         setUpModifyingSavedCertificateConfigController(null, null);
 
+        mEapCaCertSpinner.setSelection(POSITION_SYSTEM_CERT);
         assertThat(mEapCaCertSpinner.getSelectedItem()).isEqualTo(mUseSystemCertsString);
     }
 
     @Test
+    public void onItemSelected_shouldPersistentInstallCertsAndStartInstallActivity() {
+        String installCertsString = "install_certs";
+        Spinner eapCaCertSpinner = mock(Spinner.class);
+        AdapterView view = mock(AdapterView.class);
+        when(eapCaCertSpinner.getItemAtPosition(anyInt())).thenReturn(view);
+        when(view.toString()).thenReturn(installCertsString);
+        mController.mInstallCertsString = installCertsString;
+        mController.mEapCaCertSpinner = eapCaCertSpinner;
+
+        mController.onItemSelected(eapCaCertSpinner, null, POSITION_INSTALL_CERT, 0);
+
+        final ArgumentCaptor<Intent> argumentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext).startActivity(argumentCaptor.capture());
+        final Intent intent = argumentCaptor.getValue();
+        assertThat(intent.getAction()).isEqualTo(ACTION_INSTALL_CERTS);
+        assertThat(intent.getExtra(KEY_INSTALL_CERTIFICATE, ""))
+                .isEqualTo(INSTALL_CERTIFICATE_VALUE);
+    }
+
+    @Test
     public void loadSavedCaCertificateValue_shouldBeCorrectValue() {
         setUpModifyingSavedCertificateConfigController(SAVED_CA_CERT, null);