Separated flow when installing different certificate types

This is part of the changes to improve the UX and language for installing certificates.
Previously when installing a certificate, the same dialog appeared for all certificates.
This CL introduces a separate flow for the different types:
 - CA certificate: confirm credential, select certificate, install
 - User certificate: select certificate, name dialog, install to keystore
 - WiFi certificate: select certificate, install to keystore

Bug: 139173976
Test: manual testing by installing different certificate types: CA, User and WiFi
      Including testing certificate which needs to be extracted
      go/enterprise-wifi-lab-access

Screenshot of the screen: https://hsv.googleplex.com/5666804900823040

Change-Id: I9b24c37b382eeecee6e5d0d74cbd4047c6d36182
diff --git a/res/layout/name_certificate_dialog.xml b/res/layout/name_certificate_dialog.xml
new file mode 100644
index 0000000..c838ba8
--- /dev/null
+++ b/res/layout/name_certificate_dialog.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+    <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:padding="16dp">
+
+        <TextView android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/name_credential_dialog_title"
+                  style="@style/dialog_title"/>
+
+        <TextView android:id="@+id/error"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:textColor="@color/red"
+                  android:textStyle="bold"
+                  android:visibility="gone" />
+
+        <TextView android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:text="@string/certificate_name"
+                  android:textAppearance="?android:attr/textAppearanceSmall"
+                  android:textColor="?android:attr/colorAccent"/>
+
+        <EditText android:id="@+id/certificate_name"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  style="@style/dialog_edit_text"/>
+
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout/name_credential_dialog.xml b/res/layout/name_credential_dialog.xml
deleted file mode 100644
index 6dd46ff..0000000
--- a/res/layout/name_credential_dialog.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-    <LinearLayout
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:padding="15dip">
-
-        <TextView android:id="@+id/error"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textColor="@color/red"
-                android:textStyle="bold"
-                android:visibility="gone" />
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/credential_name"
-            android:textAppearance="?android:attr/textAppearanceMedium" />
-
-        <EditText android:id="@+id/credential_name"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:singleLine="True"/>
-
-        <LinearLayout
-            android:id="@+id/credential_usage_group"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical" >
-
-            <TextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="12dp"
-                android:text="@string/credential_usage_label"
-                android:textAppearance="?android:attr/textAppearanceMedium" />
-
-            <Spinner
-                android:id="@+id/credential_usage"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:entries="@array/credential_usage" />
-
-            <TextView
-                android:id="@+id/credential_capabilities_warning"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingTop="12dp"
-                android:text="@string/certificate_capabilities_warning"
-                android:textColor="@color/red" />
-
-        </LinearLayout>
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingTop="12dp"
-            android:text="@string/credential_info" />
-
-        <TextView android:id="@+id/credential_info"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
-
-    </LinearLayout>
-</ScrollView>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 020a014..881fc6c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -26,10 +26,10 @@
     <string name="extracting_pkcs12">Extracting\u2026</string>
     <!-- Title of dialog to enter password for pkcs12 file -->
     <string name="pkcs12_file_password_dialog_title">Extract from %s</string>
-    <!-- Title of dialog to name a credential -->
-    <string name="name_credential_dialog_title">Name the certificate</string>
-    <!-- Description for the credential name input box -->
-    <string name="credential_name">Certificate name:</string>
+    <!-- Title of a dialog. This title is asking the user to name the certificate they're installing on their device. -->
+    <string name="name_credential_dialog_title">Name this certificate</string>
+    <!-- Input field in a dialog. This dialog is asking the user to name the certificate they are installing on their device. -->
+    <string name="certificate_name">Certificate name</string>
     <!-- Title of the credential info -->
     <!-- Description for the credential password input box -->
     <string name="credential_password">Type the password to extract the certificates.</string>
@@ -58,8 +58,12 @@
     <string name="action_missing_private_key">Private key required to install a certificate</string>
     <string name="action_missing_user_cert">Certificate required to install a private key</string>
 
-    <!-- toast message -->
-    <string name="cert_is_added"><xliff:g id="credential">%s</xliff:g> is installed.</string>
+    <!-- Confirmation toast. This toast lets the user know that they successfully installed a CA certificate on their device. -->
+    <string name="ca_cert_is_added">CA certificate installed</string>
+    <!-- Confirmation toast. This toast lets the user know that they successfully installed a user certificate on their device. -->
+    <string name="user_cert_is_added">User certificate installed</string>
+    <!-- Confirmation toast. This toast lets the user know that they successfully installed a Wi-Fi certificate on their device. -->
+    <string name="wifi_cert_is_added">Wi\u2011Fi certificate installed</string>
     <!-- toast message -->
     <string name="cert_too_large_error">Couldn\'t install because the certificate size is too large.</string>
     <!-- toast message -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b1d493e..877464b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -28,4 +28,14 @@
         <item name="android:textAppearance">@android:style/TextAppearance.Material.Subhead</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
     </style>
+    <style name="dialog_title">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:textSize">20sp</item>
+        <item name="android:layout_marginBottom">16dp</item>
+    </style>
+    <style name="dialog_edit_text">
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="android:backgroundTint">?android:attr/colorAccent</item>
+        <item name="android:singleLine">True</item>
+    </style>
 </resources>
diff --git a/src/com/android/certinstaller/CertInstaller.java b/src/com/android/certinstaller/CertInstaller.java
index cd99c8a..a87cec9 100644
--- a/src/com/android/certinstaller/CertInstaller.java
+++ b/src/com/android/certinstaller/CertInstaller.java
@@ -19,7 +19,6 @@
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.KeyguardManager;
 import android.app.ProgressDialog;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -27,6 +26,7 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Process;
+import android.security.Credentials;
 import android.security.KeyChain;
 import android.security.KeyChain.KeyChainConnection;
 import android.security.KeyStore;
@@ -34,10 +34,7 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.EditText;
-import android.widget.Spinner;
 import android.widget.Toast;
 
 import java.io.Serializable;
@@ -61,10 +58,6 @@
     // key to states Bundle
     private static final String NEXT_ACTION_KEY = "na";
 
-    // Values for usage type spinner
-    private static final int USAGE_TYPE_SYSTEM = 0;
-    private static final int USAGE_TYPE_WIFI = 1;
-
     private final ViewHelper mView = new ViewHelper();
 
     private int mState;
@@ -153,7 +146,7 @@
                 return createPkcs12PasswordDialog();
 
             case NAME_CREDENTIAL_DIALOG:
-                return createNameCredentialDialog();
+                return createNameCertificateDialog();
 
             case PROGRESS_BAR_DIALOG:
                 ProgressDialog dialog = new ProgressDialog(this);
@@ -178,9 +171,11 @@
                 }
 
                 Log.d(TAG, "credential is added: " + mCredentials.getName());
-                Toast.makeText(this, getString(R.string.cert_is_added, mCredentials.getName()),
-                        Toast.LENGTH_LONG).show();
-
+                if (mCredentials.getCertTypeSelected().equals(Credentials.CERTIFICATE_USAGE_WIFI)) {
+                    Toast.makeText(this, R.string.wifi_cert_is_added, Toast.LENGTH_LONG).show();
+                } else {
+                    Toast.makeText(this, R.string.user_cert_is_added, Toast.LENGTH_LONG).show();
+                }
                 setResult(RESULT_OK);
                 finish();
                 break;
@@ -206,7 +201,8 @@
 
     private class InstallVpnAndAppsTrustAnchorsTask extends AsyncTask<Void, Void, Boolean> {
 
-        @Override protected Boolean doInBackground(Void... unused) {
+        @Override
+        protected Boolean doInBackground(Void... unused) {
             try {
                 try (KeyChainConnection keyChainConnection = KeyChain.bind(CertInstaller.this)) {
                     return mCredentials.installVpnAndAppsTrustAnchors(CertInstaller.this,
@@ -218,8 +214,11 @@
             }
         }
 
-        @Override protected void onPostExecute(Boolean success) {
+        @Override
+        protected void onPostExecute(Boolean success) {
             if (success) {
+                Toast.makeText(getApplicationContext(), R.string.ca_cert_is_added,
+                        Toast.LENGTH_LONG).show();
                 setResult(RESULT_OK);
             }
             finish();
@@ -242,13 +241,23 @@
             return;
         }
 
-        nameCredential();
+        installCertificateOrShowNameDialog();
     }
 
-    private void nameCredential() {
+    private void installCertificateOrShowNameDialog() {
         if (!mCredentials.hasAnyForSystemInstall()) {
             toastErrorAndFinish(R.string.no_cert_to_saved);
+        } else if (mCredentials.getCertTypeSelected().equals(Credentials.CERTIFICATE_USAGE_WIFI)) {
+            mCredentials.setInstallAsUid(Process.WIFI_UID);
+            installCertificateToKeystore(this);
+        } else if (mCredentials.hasOnlyVpnAndAppsTrustAnchors()) {
+            // If there's only a CA certificate to install, then it's going to be used
+            // as a trust anchor. Install it and skip importing to Keystore.
+
+            // more work to do, don't finish just yet
+            new InstallVpnAndAppsTrustAnchorsTask().execute();
         } else {
+            // Name is required if installing User certificate
             showDialog(NAME_CREDENTIAL_DIALOG);
         }
     }
@@ -278,7 +287,7 @@
         removeDialog(PROGRESS_BAR_DIALOG);
         if (success) {
             removeDialog(PKCS12_PASSWORD_DIALOG);
-            nameCredential();
+            installCertificateOrShowNameDialog();
         } else {
             showDialog(PKCS12_PASSWORD_DIALOG);
             mView.setText(R.id.credential_password, "");
@@ -313,53 +322,22 @@
         return d;
     }
 
-    private Dialog createNameCredentialDialog() {
-        ViewGroup view = (ViewGroup) View.inflate(this, R.layout.name_credential_dialog, null);
+    private Dialog createNameCertificateDialog() {
+        ViewGroup view = (ViewGroup) View.inflate(this, R.layout.name_certificate_dialog, null);
         mView.setView(view);
         if (mView.getHasEmptyError()) {
             mView.showError(R.string.name_empty_error);
             mView.setHasEmptyError(false);
         }
-        mView.setText(R.id.credential_info, mCredentials.getDescription(this).toString());
-        final EditText nameInput = view.findViewById(R.id.credential_name);
-        if (mCredentials.isInstallAsUidSet()) {
-            view.findViewById(R.id.credential_usage_group).setVisibility(View.GONE);
-        } else {
-            final Spinner usageSpinner = view.findViewById(R.id.credential_usage);
-            final View ca_capabilities_warning = view.findViewById(R.id.credential_capabilities_warning);
-
-            usageSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
-                @Override
-                public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-                    switch ((int) id) {
-                        case USAGE_TYPE_SYSTEM:
-                            ca_capabilities_warning.setVisibility(
-                                    mCredentials.hasOnlyVpnAndAppsTrustAnchors() ?
-                                    View.VISIBLE : View.GONE);
-                            mCredentials.setInstallAsUid(KeyStore.UID_SELF);
-                            break;
-                        case USAGE_TYPE_WIFI:
-                            ca_capabilities_warning.setVisibility(View.GONE);
-                            mCredentials.setInstallAsUid(Process.WIFI_UID);
-                            break;
-                        default:
-                            Log.w(TAG, "Unknown selection for scope: " + id);
-                    }
-                }
-
-                @Override
-                public void onNothingSelected(AdapterView<?> parent) {
-                }
-            });
-        }
+        final EditText nameInput = view.findViewById(R.id.certificate_name);
         nameInput.setText(getDefaultName());
         nameInput.selectAll();
         final Context appContext = getApplicationContext();
+
         Dialog d = new AlertDialog.Builder(this)
                 .setView(view)
-                .setTitle(R.string.name_credential_dialog_title)
                 .setPositiveButton(android.R.string.ok, (dialog, id) -> {
-                    String name = mView.getText(R.id.credential_name);
+                    String name = mView.getText(R.id.certificate_name);
                     if (TextUtils.isEmpty(name)) {
                         mView.setHasEmptyError(true);
                         removeDialog(NAME_CREDENTIAL_DIALOG);
@@ -367,24 +345,8 @@
                     } else {
                         removeDialog(NAME_CREDENTIAL_DIALOG);
                         mCredentials.setName(name);
-
-                        // If there's only a CA certificate to install, then it's going to be used
-                        // as a trust anchor. Install it and skip importing to Keystore.
-                        if (mCredentials.hasOnlyVpnAndAppsTrustAnchors()) {
-                            // more work to do, don't finish just yet
-                            new InstallVpnAndAppsTrustAnchorsTask().execute();
-                            return;
-                        }
-
-                        // install everything to system keystore
-                        try {
-                            startActivityForResult(
-                                    mCredentials.createSystemInstallIntent(appContext),
-                                    REQUEST_SYSTEM_INSTALL_CODE);
-                        } catch (ActivityNotFoundException e) {
-                            Log.w(TAG, "systemInstall(): " + e);
-                            toastErrorAndFinish(R.string.cert_not_saved);
-                        }
+                        mCredentials.setInstallAsUid(KeyStore.UID_SELF);
+                        installCertificateToKeystore(appContext);
                     }
                 })
                 .setNegativeButton(android.R.string.cancel,
@@ -394,6 +356,17 @@
         return d;
     }
 
+    private void installCertificateToKeystore(Context context) {
+        try {
+            startActivityForResult(
+                    mCredentials.createSystemInstallIntent(context),
+                    REQUEST_SYSTEM_INSTALL_CODE);
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "installCertificateToKeystore(): ", e);
+            toastErrorAndFinish(R.string.cert_not_saved);
+        }
+    }
+
     private String getDefaultName() {
         String name = mCredentials.getName();
         if (TextUtils.isEmpty(name)) {
diff --git a/src/com/android/certinstaller/CertInstallerMain.java b/src/com/android/certinstaller/CertInstallerMain.java
index 972afec..48608d3 100644
--- a/src/com/android/certinstaller/CertInstallerMain.java
+++ b/src/com/android/certinstaller/CertInstallerMain.java
@@ -29,6 +29,8 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import libcore.io.IoUtils;
+
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -36,8 +38,6 @@
 import java.util.HashMap;
 import java.util.Map;
 
-import libcore.io.IoUtils;
-
 /**
  * The main class for installing certificates to the system keystore. It reacts
  * to the public {@link Credentials#INSTALL_ACTION} intent.
@@ -136,10 +136,10 @@
     }
 
     private boolean installingCaCertificate(Bundle bundle) {
-        return bundle.size() == 1 && bundle.containsKey(Credentials.EXTRA_CERTIFICATE_USAGE)
-                && bundle.getString(Credentials.EXTRA_CERTIFICATE_USAGE).equals(
-                Credentials.CERTIFICATE_USAGE_CA);
+        return bundle != null && bundle.size() == 1 && Credentials.CERTIFICATE_USAGE_CA.equals(
+                bundle.getString(Credentials.EXTRA_CERTIFICATE_USAGE));
     }
+
     private void confirmDeviceCredential() {
         KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
         Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null,
@@ -203,10 +203,9 @@
 
                 final byte[] raw = readWithLimit(in);
 
-                Intent intent = new Intent(this, CertInstaller.class);
+                Intent intent = getIntent();
                 intent.putExtra(target, raw);
                 startInstallActivity(intent);
-
             } catch (IOException e) {
                 Log.e(TAG, "Failed to read certificate: " + e);
                 Toast.makeText(this, R.string.cert_read_error, Toast.LENGTH_LONG).show();
diff --git a/src/com/android/certinstaller/CredentialHelper.java b/src/com/android/certinstaller/CredentialHelper.java
index 7c8607d..4b4a428 100644
--- a/src/com/android/certinstaller/CredentialHelper.java
+++ b/src/com/android/certinstaller/CredentialHelper.java
@@ -71,6 +71,7 @@
     private HashMap<String, byte[]> mBundle = new HashMap<String, byte[]>();
 
     private String mName = "";
+    private String mCertTypeSelected = "";
     private int mUid = -1;
     private PrivateKey mUserKey;
     private X509Certificate mUserCert;
@@ -91,6 +92,12 @@
             mName = name;
         }
 
+        String certTypeSelected = bundle.getString(Credentials.EXTRA_CERTIFICATE_USAGE);
+        bundle.remove(Credentials.EXTRA_CERTIFICATE_USAGE);
+        if (certTypeSelected != null) {
+            mCertTypeSelected = certTypeSelected;
+        }
+
         mUid = bundle.getInt(Credentials.EXTRA_INSTALL_AS_UID, -1);
         bundle.remove(Credentials.EXTRA_INSTALL_AS_UID);
 
@@ -274,6 +281,10 @@
         return mUid;
     }
 
+    String getCertTypeSelected() {
+        return mCertTypeSelected;
+    }
+
     Intent createSystemInstallIntent(final Context context) {
         Intent intent = new Intent("com.android.credentials.INSTALL");
         // To prevent the private key from being sniffed, we explicitly spell