AndroidKeyStore: add Builder for param spec

Change-Id: I13403197e1ac7ac607efa10979eb73bde0135a2a
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
index 79a7630..83faf35 100644
--- a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
@@ -28,10 +28,28 @@
 import javax.security.auth.x500.X500Principal;
 
 /**
- * This provides the required parameters needed for initializing the KeyPair
- * generator that works with
- * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
- * facility</a>.
+ * This provides the required parameters needed for initializing the
+ * {@code KeyPairGenerator} that works with <a href="{@docRoot}
+ * guide/topics/security/keystore.html">Android KeyStore facility</a>. The
+ * Android KeyStore facility is accessed through a
+ * {@link java.security.KeyPairGenerator} API using the
+ * {@code AndroidKeyPairGenerator} provider. The {@code context} passed in may
+ * be used to pop up some UI to ask the user to unlock or initialize the Android
+ * keystore facility.
+ * <p>
+ * After generation, the {@code keyStoreAlias} is used with the
+ * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
+ * interface to retrieve the {@link PrivateKey} and its associated
+ * {@link Certificate} chain.
+ * <p>
+ * The KeyPair generator will create a self-signed certificate with the subject
+ * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer
+ * Distinguished Name along with the other parameters specified with the
+ * {@link Builder}.
+ * <p>
+ * The self-signed certificate may be replaced at a later time by a certificate
+ * signed by a real Certificate Authority.
+ *
  * @hide
  */
 public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
@@ -74,6 +92,7 @@
      *            period
      * @throws IllegalArgumentException when any argument is {@code null} or
      *             {@code endDate} is before {@code startDate}.
+     * @hide should be built with AndroidKeyPairGeneratorSpecBuilder
      */
     public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
             X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
@@ -142,4 +161,121 @@
     Date getEndDate() {
         return mEndDate;
     }
+
+    /**
+     * Builder class for {@link AndroidKeyPairGeneratorSpec} objects.
+     * <p>
+     * This will build a parameter spec for use with the <a href="{@docRoot}
+     * guide/topics/security/keystore.html">Android KeyStore facility</a>.
+     * <p>
+     * The required fields must be filled in with the builder.
+     * <p>
+     * Example:
+     *
+     * <pre class="prettyprint">
+     * Calendar start = new Calendar();
+     * Calendar end = new Calendar();
+     * end.add(1, Calendar.YEAR);
+     *
+     * AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(mContext)
+     *         .setAlias("myKey")
+     *         .setSubject(new X500Principal("CN=myKey"))
+     *         .setSerial(BigInteger.valueOf(1337))
+     *         .setStartDate(start.getTime())
+     *         .setEndDate(end.getTime())
+     *         .build();
+     * </pre>
+     */
+    public static class Builder {
+        private final Context mContext;
+
+        private String mKeystoreAlias;
+
+        private X500Principal mSubjectDN;
+
+        private BigInteger mSerialNumber;
+
+        private Date mStartDate;
+
+        private Date mEndDate;
+
+        public Builder(Context context) {
+            if (context == null) {
+                throw new NullPointerException("context == null");
+            }
+            mContext = context;
+        }
+
+        /**
+         * Sets the alias to be used to retrieve the key later from a
+         * {@link java.security.KeyStore} instance using the
+         * {@code AndroidKeyStore} provider.
+         */
+        public Builder setAlias(String alias) {
+            if (alias == null) {
+                throw new NullPointerException("alias == null");
+            }
+            mKeystoreAlias = alias;
+            return this;
+        }
+
+        /**
+         * Sets the subject used for the self-signed certificate of the
+         * generated key pair.
+         */
+        public Builder setSubject(X500Principal subject) {
+            if (subject == null) {
+                throw new NullPointerException("subject == null");
+            }
+            mSubjectDN = subject;
+            return this;
+        }
+
+        /**
+         * Sets the serial number used for the self-signed certificate of the
+         * generated key pair.
+         */
+        public Builder setSerialNumber(BigInteger serialNumber) {
+            if (serialNumber == null) {
+                throw new NullPointerException("serialNumber == null");
+            }
+            mSerialNumber = serialNumber;
+            return this;
+        }
+
+        /**
+         * Sets the start of the validity period for the self-signed certificate
+         * of the generated key pair.
+         */
+        public Builder setStartDate(Date startDate) {
+            if (startDate == null) {
+                throw new NullPointerException("startDate == null");
+            }
+            mStartDate = startDate;
+            return this;
+        }
+
+        /**
+         * Sets the end of the validity period for the self-signed certificate
+         * of the generated key pair.
+         */
+        public Builder setEndDate(Date endDate) {
+            if (endDate == null) {
+                throw new NullPointerException("endDate == null");
+            }
+            mEndDate = endDate;
+            return this;
+        }
+
+        /**
+         * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}.
+         *
+         * @throws IllegalArgumentException if a required field is missing
+         * @return built instance of {@code AndroidKeyPairGeneratorSpec}
+         */
+        public AndroidKeyPairGeneratorSpec build() {
+            return new AndroidKeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN,
+                    mSerialNumber, mStartDate, mEndDate);
+        }
+    }
 }
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
index e6a3750..3d275cd 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
@@ -53,6 +53,26 @@
         assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
     }
 
+    public void testBuilder_Success() throws Exception {
+        AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(getContext())
+                .setAlias(TEST_ALIAS_1)
+                .setSubject(TEST_DN_1)
+                .setSerialNumber(SERIAL_1)
+                .setStartDate(NOW)
+                .setEndDate(NOW_PLUS_10_YEARS)
+                .build();
+
+        assertEquals("Context should be the one specified", getContext(), spec.getContext());
+
+        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
+
+        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
+
+        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
+
+        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
+    }
+
     public void testConstructor_NullContext_Failure() throws Exception {
         try {
             new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,