Adds test cases for positive button and title style

Test: atest CtsAutoFillServiceTestCases
Change-Id: Icf6bea75c58b784fdf8b9d30fae18792262ed025
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index 477d6d8..ab56c7f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -82,6 +82,7 @@
     private final String[] mIgnoredIds;
     private final int mNegativeActionStyle;
     private final IntentSender mNegativeActionListener;
+    private final int mPositiveActionStyle;
     private final int mSaveInfoFlags;
     private final int mFillResponseFlags;
     private final AutofillId mSaveTriggerId;
@@ -111,6 +112,7 @@
         mIgnoredIds = builder.mIgnoredIds;
         mNegativeActionStyle = builder.mNegativeActionStyle;
         mNegativeActionListener = builder.mNegativeActionListener;
+        mPositiveActionStyle = builder.mPositiveActionStyle;
         mSaveInfoFlags = builder.mSaveInfoFlags;
         mFillResponseFlags = builder.mFillResponseFlags;
         mSaveTriggerId = builder.mSaveTriggerId;
@@ -194,6 +196,9 @@
             if (mNegativeActionListener != null) {
                 saveInfoBuilder.setNegativeAction(mNegativeActionStyle, mNegativeActionListener);
             }
+
+            saveInfoBuilder.setPositiveAction(mPositiveActionStyle);
+
             if (mSaveTriggerId != null) {
                 saveInfoBuilder.setTriggerId(mSaveTriggerId);
             }
@@ -312,6 +317,7 @@
         private String[] mIgnoredIds;
         private int mNegativeActionStyle;
         private IntentSender mNegativeActionListener;
+        private int mPositiveActionStyle;
         private int mSaveInfoFlags;
         private int mFillResponseFlags;
         private AutofillId mSaveTriggerId;
@@ -415,6 +421,14 @@
             return this;
         }
 
+        /**
+         * Sets the positive action spec.
+         */
+        public Builder setPositiveAction(int style) {
+            mPositiveActionStyle = style;
+            return this;
+        }
+
         public CannedFillResponse build() {
             return new CannedFillResponse(this);
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index 9636026..507d289 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -52,9 +52,12 @@
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_DEBIT_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PAYMENT_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME;
 import static android.text.InputType.TYPE_NULL;
 import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
@@ -1811,7 +1814,43 @@
         customizedSaveTest(SAVE_DATA_TYPE_EMAIL_ADDRESS);
     }
 
+    @Test
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
+    public void testCustomizedSaveDebitCard() throws Exception {
+        customizedSaveTest(SAVE_DATA_TYPE_DEBIT_CARD);
+    }
+
+    @Test
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
+    public void testCustomizedSavePaymentCard() throws Exception {
+        customizedSaveTest(SAVE_DATA_TYPE_PAYMENT_CARD);
+    }
+
+    @Test
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
+    public void testCustomizedSaveGenericCard() throws Exception {
+        customizedSaveTest(SAVE_DATA_TYPE_GENERIC_CARD);
+    }
+
+    @Test
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
+    public void testCustomizedSaveTwoCardTypes() throws Exception {
+        customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD | SAVE_DATA_TYPE_DEBIT_CARD,
+                SAVE_DATA_TYPE_GENERIC_CARD);
+    }
+
+    @Test
+    @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough")
+    public void testCustomizedSaveThreeCardTypes() throws Exception {
+        customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD | SAVE_DATA_TYPE_DEBIT_CARD
+                | SAVE_DATA_TYPE_PAYMENT_CARD, SAVE_DATA_TYPE_GENERIC_CARD);
+    }
+
     private void customizedSaveTest(int type) throws Exception {
+        customizedSaveTest(type, type);
+    }
+
+    private void customizedSaveTest(int type, int expectedType) throws Exception {
         // Set service.
         enableService();
 
@@ -1842,7 +1881,7 @@
         assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
 
         // Assert the snack bar is shown and tap "Save".
-        final UiObject2 saveSnackBar = mUiBot.assertSaveShowing(saveDescription, type);
+        final UiObject2 saveSnackBar = mUiBot.assertSaveShowing(saveDescription, expectedType);
         mUiBot.saveForAutofill(saveSnackBar, true);
 
         // Assert save was called.
@@ -2001,6 +2040,36 @@
         assertThat(latch.await(500, TimeUnit.SECONDS)).isTrue();
     }
 
+
+    @Test
+    public void testContinueStylePositiveSaveButton() throws Exception {
+        enableService();
+
+        // Set service behavior.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
+                .setPositiveAction(SaveInfo.POSITIVE_BUTTON_STYLE_CONTINUE)
+                .build());
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Wait for onFill() before proceeding.
+        sReplier.getNextFillRequest();
+
+        // Trigger save.
+        mActivity.onUsername((v) -> v.setText("foo"));
+        mActivity.onPassword((v) -> v.setText("foo"));
+        mActivity.tapLogin();
+
+        // Start watching for the negative intent
+        // Trigger the negative button.
+        mUiBot.saveForAutofill(SaveInfo.POSITIVE_BUTTON_STYLE_CONTINUE, SAVE_DATA_TYPE_PASSWORD);
+
+        // Assert save was called.
+        sReplier.getNextSaveRequest();
+    }
+
     @Test
     @AppModeFull(reason = "Unit test")
     public void testGetTextInputType() throws Exception {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 3c24967..8bd2d80 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -24,9 +24,12 @@
 import static android.autofillservice.cts.Timeouts.UI_TIMEOUT;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_DEBIT_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PAYMENT_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME;
 
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
@@ -99,10 +102,17 @@
     private static final String RESOURCE_STRING_SAVE_TYPE_USERNAME = "autofill_save_type_username";
     private static final String RESOURCE_STRING_SAVE_TYPE_EMAIL_ADDRESS =
             "autofill_save_type_email_address";
+    private static final String RESOURCE_STRING_SAVE_TYPE_DEBIT_CARD =
+            "autofill_save_type_debit_card";
+    private static final String RESOURCE_STRING_SAVE_TYPE_PAYMENT_CARD =
+            "autofill_save_type_payment_card";
+    private static final String RESOURCE_STRING_SAVE_TYPE_GENERIC_CARD =
+            "autofill_save_type_generic_card";
     private static final String RESOURCE_STRING_SAVE_BUTTON_NOT_NOW = "save_password_notnow";
     private static final String RESOURCE_STRING_SAVE_BUTTON_NO_THANKS = "autofill_save_no";
     private static final String RESOURCE_STRING_SAVE_BUTTON_YES = "autofill_save_yes";
     private static final String RESOURCE_STRING_UPDATE_BUTTON_YES = "autofill_update_yes";
+    private static final String RESOURCE_STRING_CONTINUE_BUTTON_YES = "autofill_continue_yes";
     private static final String RESOURCE_STRING_UPDATE_TITLE = "autofill_update_title";
     private static final String RESOURCE_STRING_UPDATE_TITLE_WITH_TYPE =
             "autofill_update_title_with_type";
@@ -618,6 +628,15 @@
             case SAVE_DATA_TYPE_EMAIL_ADDRESS:
                 typeResourceName = RESOURCE_STRING_SAVE_TYPE_EMAIL_ADDRESS;
                 break;
+            case SAVE_DATA_TYPE_DEBIT_CARD:
+                typeResourceName = RESOURCE_STRING_SAVE_TYPE_DEBIT_CARD;
+                break;
+            case SAVE_DATA_TYPE_PAYMENT_CARD:
+                typeResourceName = RESOURCE_STRING_SAVE_TYPE_PAYMENT_CARD;
+                break;
+            case SAVE_DATA_TYPE_GENERIC_CARD:
+                typeResourceName = RESOURCE_STRING_SAVE_TYPE_GENERIC_CARD;
+                break;
             default:
                 throw new IllegalArgumentException("Unsupported type: " + type);
         }
@@ -641,9 +660,21 @@
                 SAVE_TIMEOUT, types);
     }
 
+    public UiObject2 assertSaveShowing(int positiveButtonStyle, int... types) throws Exception {
+        return assertSaveOrUpdateShowing(/* update= */ false, SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL,
+                positiveButtonStyle, /* description= */ null, SAVE_TIMEOUT, types);
+    }
 
     public UiObject2 assertSaveOrUpdateShowing(boolean update, int negativeButtonStyle,
             String description, Timeout timeout, int... types) throws Exception {
+        return assertSaveOrUpdateShowing(update, negativeButtonStyle,
+                SaveInfo.POSITIVE_BUTTON_STYLE_SAVE, description, timeout, types);
+    }
+
+    public UiObject2 assertSaveOrUpdateShowing(boolean update, int negativeButtonStyle,
+            int positiveButtonStyle, String description, Timeout timeout, int... types)
+            throws Exception {
+
         final UiObject2 snackbar = waitForObject(SAVE_UI_SELECTOR, timeout);
 
         final UiObject2 titleView =
@@ -697,8 +728,15 @@
             assertWithMessage("save subtitle(%s)", description).that(saveSubTitle).isNotNull();
         }
 
-        final String positiveButtonStringId = update ? RESOURCE_STRING_UPDATE_BUTTON_YES
-                : RESOURCE_STRING_SAVE_BUTTON_YES;
+        final String positiveButtonStringId;
+        switch (positiveButtonStyle) {
+            case SaveInfo.POSITIVE_BUTTON_STYLE_CONTINUE:
+                positiveButtonStringId = RESOURCE_STRING_CONTINUE_BUTTON_YES;
+                break;
+            default:
+                positiveButtonStringId = update ? RESOURCE_STRING_UPDATE_BUTTON_YES
+                        : RESOURCE_STRING_SAVE_BUTTON_YES;
+        }
         final String expectedPositiveButtonText = getString(positiveButtonStringId).toUpperCase();
         final UiObject2 positiveButton = waitForObject(snackbar,
                 By.res("android", RESOURCE_ID_SAVE_BUTTON_YES), timeout);
@@ -747,11 +785,21 @@
      */
     public void saveForAutofill(int negativeButtonStyle, boolean yesDoIt, int... types)
             throws Exception {
-        final UiObject2 saveSnackBar = assertSaveShowing(negativeButtonStyle,null, types);
+        final UiObject2 saveSnackBar = assertSaveShowing(negativeButtonStyle, null, types);
         saveForAutofill(saveSnackBar, yesDoIt);
     }
 
     /**
+     * Taps the positive button in the save snackbar.
+     *
+     * @param types expected types of save info.
+     */
+    public void saveForAutofill(int positiveButtonStyle, int... types) throws Exception {
+        final UiObject2 saveSnackBar = assertSaveShowing(positiveButtonStyle, types);
+        saveForAutofill(saveSnackBar, /* yesDoIt= */ true);
+    }
+
+    /**
      * Taps an option in the save snackbar.
      *
      * @param saveSnackBar Save snackbar, typically obtained through