CTS tests for augmented autofill auth flow
Tests for Id21c8f074bd0f49992e01445d50b1503af4720b6
Bug: 157863999
Test: atest CtsAutoFillServiceTestCases:InlineAugmentedAuthTest
Change-Id: Iacc5a17cb3d2f1b991b78c95330cbd0f0254cbe5
Merged-In: Iacc5a17cb3d2f1b991b78c95330cbd0f0254cbe5
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index d4d5459..f690678 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -134,6 +134,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+ <activity android:name=".augmented.AugmentedAuthActivity" />
<activity android:name=".SimpleAfterLoginActivity" />
<activity android:name=".SimpleBeforeLoginActivity" />
<activity android:name=".NonAutofillableActivity" />
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index 6c229e0..838d4ab 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -26,6 +26,7 @@
import android.app.PendingIntent;
import android.autofillservice.cts.InstrumentedAutoFillService.Replier;
+import android.autofillservice.cts.augmented.AugmentedAuthActivity;
import android.autofillservice.cts.inline.InlineUiBot;
import android.content.ClipboardManager;
import android.content.Context;
@@ -388,6 +389,7 @@
InstrumentedAutoFillService.resetStaticState();
AuthenticationActivity.resetStaticState();
+ AugmentedAuthActivity.resetStaticState();
sReplier.reset();
}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAuthActivity.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAuthActivity.java
new file mode 100644
index 0000000..8de9eb7
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAuthActivity.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.autofillservice.cts.augmented;
+
+import android.app.PendingIntent;
+import android.autofillservice.cts.AbstractAutoFillActivity;
+import android.autofillservice.cts.R;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.service.autofill.Dataset;
+import android.util.Log;
+import android.view.autofill.AutofillManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Activity for testing Augmented Autofill authentication flow. This activity shows a simple UI;
+ * when the UI is tapped, it returns whatever data was configured via the auth intent.
+ */
+public class AugmentedAuthActivity extends AbstractAutoFillActivity {
+ private static final String TAG = "AugmentedAuthActivity";
+
+ public static final String ID_AUTH_ACTIVITY_BUTTON = "button";
+
+ private static final String EXTRA_DATASET_TO_RETURN = "dataset_to_return";
+ private static final String EXTRA_CLIENT_STATE_TO_RETURN = "client_state_to_return";
+ private static final String EXTRA_RESULT_CODE_TO_RETURN = "result_code_to_return";
+
+ private static final List<PendingIntent> sPendingIntents = new ArrayList<>(1);
+
+ public static void resetStaticState() {
+ for (PendingIntent pendingIntent : sPendingIntents) {
+ pendingIntent.cancel();
+ }
+ sPendingIntents.clear();
+ }
+
+ public static IntentSender createSender(Context context, int requestCode,
+ Dataset datasetToReturn, Bundle clientStateToReturn, int resultCodeToReturn) {
+ Intent intent = new Intent(context, AugmentedAuthActivity.class);
+ intent.putExtra(EXTRA_DATASET_TO_RETURN, datasetToReturn);
+ intent.putExtra(EXTRA_CLIENT_STATE_TO_RETURN, clientStateToReturn);
+ intent.putExtra(EXTRA_RESULT_CODE_TO_RETURN, resultCodeToReturn);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, requestCode, intent, 0);
+ sPendingIntents.add(pendingIntent);
+ return pendingIntent.getIntentSender();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Log.d(TAG, "Auth activity invoked, showing auth UI");
+ setContentView(R.layout.single_button_activity);
+ findViewById(R.id.button).setOnClickListener((v) -> {
+ Log.d(TAG, "Auth UI tapped, returning result");
+
+ Intent intent = getIntent();
+ Dataset dataset = intent.getParcelableExtra(EXTRA_DATASET_TO_RETURN);
+ Bundle clientState = intent.getParcelableExtra(EXTRA_CLIENT_STATE_TO_RETURN);
+ int resultCode = intent.getIntExtra(EXTRA_RESULT_CODE_TO_RETURN, RESULT_OK);
+ Log.d(TAG, "Output: dataset=" + dataset + ", clientState=" + clientState
+ + ", resultCode=" + resultCode);
+
+ Intent result = new Intent();
+ result.putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, dataset);
+ result.putExtra(AutofillManager.EXTRA_CLIENT_STATE, clientState);
+ setResult(resultCode, result);
+
+ finish();
+ });
+ }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java
index a8a26a3..af1229b 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/CannedAugmentedFillResponse.java
@@ -19,6 +19,7 @@
import android.autofillservice.cts.R;
import android.content.Context;
+import android.content.IntentSender;
import android.os.Bundle;
import android.service.autofill.InlinePresentation;
import android.service.autofill.augmented.FillCallback;
@@ -189,6 +190,7 @@
final AutofillId id = pair.first;
datasetBuilder.setFieldInlinePresentation(id, pair.second, null,
dataset.mFieldPresentationById.get(id));
+ datasetBuilder.setAuthentication(dataset.mAuthentication);
}
list.add(datasetBuilder.build());
}
@@ -279,12 +281,14 @@
private final Map<AutofillId, InlinePresentation> mFieldPresentationById;
private final String mPresentation;
private final AutofillValue mOnlyFieldValue;
+ private final IntentSender mAuthentication;
private Dataset(@NonNull Builder builder) {
mFieldValuesById = builder.mFieldValuesById;
mPresentation = builder.mPresentation;
mOnlyFieldValue = builder.mOnlyFieldValue;
mFieldPresentationById = builder.mFieldPresentationById;
+ this.mAuthentication = builder.mAuthentication;
}
@NonNull
@@ -304,6 +308,7 @@
return "Dataset: [presentation=" + mPresentation
+ ", onlyField=" + mOnlyFieldValue
+ ", fields=" + mFieldValuesById
+ + ", auth=" + mAuthentication
+ "]";
}
@@ -314,6 +319,7 @@
private final String mPresentation;
private AutofillValue mOnlyFieldValue;
+ private IntentSender mAuthentication;
public Builder(@NonNull String presentation) {
mPresentation = Objects.requireNonNull(presentation);
@@ -356,6 +362,13 @@
return this;
}
+ /**
+ * Sets the authentication intent for this dataset.
+ */
+ public Builder setAuthentication(IntentSender authentication) {
+ mAuthentication = authentication;
+ return this;
+ }
public Dataset build() {
return new Dataset(this);
diff --git a/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java
new file mode 100644
index 0000000..bb81399
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/inline/InlineAugmentedAuthTest.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.autofillservice.cts.inline;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+import static android.autofillservice.cts.CannedFillResponse.NO_RESPONSE;
+import static android.autofillservice.cts.Helper.ID_USERNAME;
+import static android.autofillservice.cts.augmented.AugmentedHelper.assertBasicRequestInfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.autofillservice.cts.AutofillActivityTestRule;
+import android.autofillservice.cts.augmented.AugmentedAuthActivity;
+import android.autofillservice.cts.augmented.AugmentedAutofillAutoActivityLaunchTestCase;
+import android.autofillservice.cts.augmented.AugmentedLoginActivity;
+import android.autofillservice.cts.augmented.CannedAugmentedFillResponse;
+import android.autofillservice.cts.augmented.CtsAugmentedAutofillService;
+import android.content.IntentSender;
+import android.service.autofill.Dataset;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.widget.EditText;
+
+import org.junit.Test;
+
+public class InlineAugmentedAuthTest
+ extends AugmentedAutofillAutoActivityLaunchTestCase<AugmentedLoginActivity> {
+
+ protected AugmentedLoginActivity mActivity;
+
+ public InlineAugmentedAuthTest() {
+ super(getInlineUiBot());
+ }
+
+ @Override
+ protected AutofillActivityTestRule<AugmentedLoginActivity> getActivityRule() {
+ return new AutofillActivityTestRule<AugmentedLoginActivity>(AugmentedLoginActivity.class) {
+ @Override
+ protected void afterActivityLaunched() {
+ mActivity = getActivity();
+ }
+ };
+ }
+
+ @Test
+ public void testDatasetAuth_resultOk_validDataset() throws Exception {
+ // Set services
+ enableService();
+ enableAugmentedService();
+
+ // Set expectations
+ final EditText unField = mActivity.getUsername();
+ final AutofillId unFieldId = unField.getAutofillId();
+ final AutofillValue unValue = unField.getAutofillValue();
+ sReplier.addResponse(NO_RESPONSE);
+ Dataset authResult = new Dataset.Builder(createInlinePresentation("auth"))
+ .setId("dummyId")
+ .setValue(unFieldId, AutofillValue.forText("Auth Result"))
+ .build();
+ IntentSender authAction = AugmentedAuthActivity.createSender(mContext, 1,
+ authResult, null, RESULT_OK);
+ sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+ .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("bla").build(),
+ unFieldId)
+ .addInlineSuggestion(new CannedAugmentedFillResponse.Dataset.Builder("inline")
+ .setField(unFieldId, "John Smith", createInlinePresentation("John"))
+ .setAuthentication(authAction)
+ .build())
+ .build());
+
+ // Trigger autofill request
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdle();
+ sReplier.getNextFillRequest();
+ CtsAugmentedAutofillService.AugmentedFillRequest request1 =
+ sAugmentedReplier.getNextFillRequest();
+
+ // Assert request
+ assertBasicRequestInfo(request1, mActivity, unFieldId, unValue);
+
+ // Confirm suggestions
+ mUiBot.assertDatasets("John");
+
+ // Tap on suggestion
+ mUiBot.selectDataset("John");
+ mUiBot.waitForIdle();
+
+ // Tap on the auth activity button and assert that the dataset from the auth activity is
+ // filled into the field.
+ mActivity.expectAutoFill("Auth Result");
+ mUiBot.selectByRelativeId(AugmentedAuthActivity.ID_AUTH_ACTIVITY_BUTTON);
+ mUiBot.waitForIdle();
+ mActivity.assertAutoFilled();
+ assertThat(unField.getText().toString()).isEqualTo("Auth Result");
+ mUiBot.assertNoDatasets();
+ }
+
+ @Test
+ public void testDatasetAuth_resultOk_nullDataset() throws Exception {
+ // Set services
+ enableService();
+ enableAugmentedService();
+
+ // Set expectations
+ final EditText unField = mActivity.getUsername();
+ final AutofillId unFieldId = unField.getAutofillId();
+ final AutofillValue unValue = unField.getAutofillValue();
+ sReplier.addResponse(NO_RESPONSE);
+ IntentSender authAction = AugmentedAuthActivity.createSender(mContext, 1,
+ null, null, RESULT_OK);
+ sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+ .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("bla").build(),
+ unFieldId)
+ .addInlineSuggestion(new CannedAugmentedFillResponse.Dataset.Builder("inline")
+ .setField(unFieldId, "John Smith", createInlinePresentation("John"))
+ .setAuthentication(authAction)
+ .build())
+ .build());
+
+ // Trigger autofill request
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdle();
+ sReplier.getNextFillRequest();
+ CtsAugmentedAutofillService.AugmentedFillRequest request1 =
+ sAugmentedReplier.getNextFillRequest();
+
+ // Assert request
+ assertBasicRequestInfo(request1, mActivity, unFieldId, unValue);
+
+ // Confirm suggestions
+ mUiBot.assertDatasets("John");
+
+ // Tap on suggestion
+ mUiBot.selectDataset("John");
+ mUiBot.waitForIdle();
+
+ // Tap on the auth activity button and assert that the field is left unchanged (since the
+ // dataset returned from the auth activity is null).
+ mUiBot.selectByRelativeId(AugmentedAuthActivity.ID_AUTH_ACTIVITY_BUTTON);
+ mUiBot.waitForIdle();
+ assertThat(unField.getText().toString()).isEqualTo("");
+ }
+
+ @Test
+ public void testDatasetAuth_resultCancel() throws Exception {
+ // Set services
+ enableService();
+ enableAugmentedService();
+
+ // Set expectations
+ final EditText unField = mActivity.getUsername();
+ final AutofillId unFieldId = unField.getAutofillId();
+ final AutofillValue unValue = unField.getAutofillValue();
+ sReplier.addResponse(NO_RESPONSE);
+ Dataset authResult = new Dataset.Builder(createInlinePresentation("auth"))
+ .setId("dummyId")
+ .setValue(unFieldId, AutofillValue.forText("Auth Result"))
+ .build();
+ IntentSender authAction = AugmentedAuthActivity.createSender(mContext, 1,
+ authResult, null, RESULT_CANCELED);
+ sAugmentedReplier.addResponse(new CannedAugmentedFillResponse.Builder()
+ .setDataset(new CannedAugmentedFillResponse.Dataset.Builder("bla").build(),
+ unFieldId)
+ .addInlineSuggestion(new CannedAugmentedFillResponse.Dataset.Builder("inline")
+ .setField(unFieldId, "John Smith", createInlinePresentation("John"))
+ .setAuthentication(authAction)
+ .build())
+ .build());
+
+ // Trigger autofill request
+ mUiBot.selectByRelativeId(ID_USERNAME);
+ mUiBot.waitForIdle();
+ sReplier.getNextFillRequest();
+ CtsAugmentedAutofillService.AugmentedFillRequest request1 =
+ sAugmentedReplier.getNextFillRequest();
+
+ // Assert request
+ assertBasicRequestInfo(request1, mActivity, unFieldId, unValue);
+
+ // Confirm suggestions
+ mUiBot.assertDatasets("John");
+
+ // Tap on suggestion
+ mUiBot.selectDataset("John");
+ mUiBot.waitForIdle();
+
+ // Tap on the auth activity button and assert that the field is left unchanged (since the
+ // result code returned by the auth activity is RESULT_CANCELED).
+ mUiBot.selectByRelativeId(AugmentedAuthActivity.ID_AUTH_ACTIVITY_BUTTON);
+ mUiBot.waitForIdle();
+ assertThat(unField.getText().toString()).isEqualTo("");
+ }
+}