blob: 1e3535e13aaa54ccf2a22ff52563b97ebb850bb2 [file] [log] [blame]
/*
* Copyright (C) 2017 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.dropdown;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_ADDRESS;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_CC_EXPIRATION;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_CC_NUMBER;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_DATE_PICKER;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_HOME_ADDRESS;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_SAVE_CC;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_TIME_PICKER;
import static android.autofillservice.cts.activities.CheckoutActivity.ID_WORK_ADDRESS;
import static android.autofillservice.cts.activities.CheckoutActivity.INDEX_ADDRESS_WORK;
import static android.autofillservice.cts.activities.CheckoutActivity.INDEX_CC_EXPIRATION_NEVER;
import static android.autofillservice.cts.activities.CheckoutActivity.INDEX_CC_EXPIRATION_TODAY;
import static android.autofillservice.cts.activities.CheckoutActivity.INDEX_CC_EXPIRATION_TOMORROW;
import static android.autofillservice.cts.testcore.Helper.assertListValue;
import static android.autofillservice.cts.testcore.Helper.assertTextAndValue;
import static android.autofillservice.cts.testcore.Helper.assertTextIsSanitized;
import static android.autofillservice.cts.testcore.Helper.assertToggleIsSanitized;
import static android.autofillservice.cts.testcore.Helper.assertToggleValue;
import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId;
import static android.autofillservice.cts.testcore.Helper.findNodeByResourceId;
import static android.autofillservice.cts.testcore.Helper.getContext;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
import static android.view.View.AUTOFILL_TYPE_LIST;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.assist.AssistStructure.ViewNode;
import android.autofillservice.cts.R;
import android.autofillservice.cts.activities.CheckoutActivity;
import android.autofillservice.cts.commontests.AutoFillServiceTestCase;
import android.autofillservice.cts.testcore.AutofillActivityTestRule;
import android.autofillservice.cts.testcore.CannedFillResponse;
import android.autofillservice.cts.testcore.CannedFillResponse.CannedDataset;
import android.autofillservice.cts.testcore.Helper;
import android.autofillservice.cts.testcore.InstrumentedAutoFillService.FillRequest;
import android.autofillservice.cts.testcore.InstrumentedAutoFillService.SaveRequest;
import android.autofillservice.cts.testcore.MultipleTimesRadioGroupListener;
import android.autofillservice.cts.testcore.MultipleTimesTimeListener;
import android.autofillservice.cts.testcore.OneTimeCompoundButtonListener;
import android.autofillservice.cts.testcore.OneTimeDateListener;
import android.autofillservice.cts.testcore.OneTimeSpinnerListener;
import android.autofillservice.cts.testcore.OneTimeTextWatcher;
import android.icu.util.Calendar;
import android.platform.test.annotations.AppModeFull;
import android.service.autofill.CharSequenceTransformation;
import android.service.autofill.CustomDescription;
import android.service.autofill.FillContext;
import android.service.autofill.ImageTransformation;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.RemoteViews;
import android.widget.Spinner;
import android.widget.TimePicker;
import org.junit.Test;
import java.util.Arrays;
import java.util.regex.Pattern;
/**
* Test case for an activity containing non-TextField views.
*/
public class CheckoutActivityTest
extends AutoFillServiceTestCase.AutoActivityLaunch<CheckoutActivity> {
private CheckoutActivity mActivity;
@Override
protected AutofillActivityTestRule<CheckoutActivity> getActivityRule() {
return new AutofillActivityTestRule<CheckoutActivity>(CheckoutActivity.class) {
@Override
protected void afterActivityLaunched() {
mActivity = getActivity();
}
};
}
@Test
public void testAutofill() throws Exception {
// Set service.
enableService();
// Set expectations.
sReplier.addResponse(new CannedDataset.Builder()
.setPresentation(createPresentation("ACME CC"))
.setField(ID_CC_NUMBER, "4815162342")
.setField(ID_CC_EXPIRATION, INDEX_CC_EXPIRATION_NEVER)
.setField(ID_ADDRESS, 1)
.setField(ID_SAVE_CC, true)
.build());
mActivity.expectAutoFill("4815162342", INDEX_CC_EXPIRATION_NEVER, R.id.work_address,
true);
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
final FillRequest fillRequest = sReplier.getNextFillRequest();
// Assert properties of Spinner field.
final ViewNode ccExpirationNode =
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
.containsExactly((Object [])
getContext().getResources().getStringArray(R.array.cc_expiration_values))
.inOrder();
// Auto-fill it.
mUiBot.selectDataset("ACME CC");
// Check the results.
mActivity.assertAutoFilled();
}
@Test
@AppModeFull(reason = "testAutofill() is enough")
public void testAutofillDynamicAdapter() throws Exception {
// Set activity.
mActivity.onCcExpiration((v) -> v.setAdapter(new ArrayAdapter<String>(getContext(),
android.R.layout.simple_spinner_item,
Arrays.asList("YESTERDAY", "TODAY", "TOMORROW", "NEVER"))));
// Set service.
enableService();
// Set expectations.
sReplier.addResponse(new CannedDataset.Builder()
.setPresentation(createPresentation("ACME CC"))
.setField(ID_CC_NUMBER, "4815162342")
.setField(ID_CC_EXPIRATION, INDEX_CC_EXPIRATION_NEVER)
.setField(ID_ADDRESS, 1)
.setField(ID_SAVE_CC, true)
.build());
mActivity.expectAutoFill("4815162342", INDEX_CC_EXPIRATION_NEVER, R.id.work_address,
true);
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
final FillRequest fillRequest = sReplier.getNextFillRequest();
// Assert properties of Spinner field.
final ViewNode ccExpirationNode =
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNull();
// Auto-fill it.
mUiBot.selectDataset("ACME CC");
// Check the results.
mActivity.assertAutoFilled();
}
// TODO: this should be a pure unit test exercising onProvideAutofillStructure(),
// but that would require creating a custom ViewStructure.
@Test
@AppModeFull(reason = "Unit test")
public void testGetAutofillOptionsSorted() throws Exception {
// Set service.
enableService();
// Set activity.
mActivity.onCcExpirationAdapter((adapter) -> adapter.sort((a, b) -> {
return ((String) a).compareTo((String) b);
}));
// Set expectations.
sReplier.addResponse(new CannedDataset.Builder()
.setPresentation(createPresentation("ACME CC"))
.setField(ID_CC_NUMBER, "4815162342")
.setField(ID_CC_EXPIRATION, INDEX_CC_EXPIRATION_NEVER)
.setField(ID_ADDRESS, 1)
.setField(ID_SAVE_CC, true)
.build());
mActivity.expectAutoFill("4815162342", INDEX_CC_EXPIRATION_NEVER, R.id.work_address,
true);
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
final FillRequest fillRequest = sReplier.getNextFillRequest();
// Assert properties of Spinner field.
final ViewNode ccExpirationNode =
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
final CharSequence[] options = ccExpirationNode.getAutofillOptions();
assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
.containsExactly("never", "today", "tomorrow", "yesterday").inOrder();
// Auto-fill it.
mUiBot.selectDataset("ACME CC");
// Check the results.
mActivity.assertAutoFilled();
}
@Test
public void testSanitization() throws Exception {
// Set service.
enableService();
// Set expectations.
sReplier.addResponse(new CannedFillResponse.Builder()
.setRequiredSavableIds(SAVE_DATA_TYPE_CREDIT_CARD,
ID_CC_NUMBER, ID_CC_EXPIRATION, ID_ADDRESS, ID_SAVE_CC)
.build());
// Dynamically change view contents
mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TOMORROW, true));
mActivity.onHomeAddress((v) -> v.setChecked(true));
mActivity.onSaveCc((v) -> v.setChecked(true));
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
// Assert sanitization on fill request: everything should be sanitized!
final FillRequest fillRequest = sReplier.getNextFillRequest();
assertTextIsSanitized(fillRequest.structure, ID_CC_NUMBER);
assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
assertToggleIsSanitized(fillRequest.structure, ID_HOME_ADDRESS);
assertToggleIsSanitized(fillRequest.structure, ID_SAVE_CC);
// Trigger save.
mActivity.onCcNumber((v) -> v.setText("4815162342"));
mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TODAY));
mActivity.onAddress((v) -> v.check(R.id.work_address));
mActivity.onSaveCc((v) -> v.setChecked(false));
mActivity.tapBuy();
mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_CREDIT_CARD);
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
// Assert sanitization on save: everything should be available!
assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_CC_NUMBER), "4815162342");
assertListValue(findNodeByResourceId(saveRequest.structure, ID_CC_EXPIRATION),
INDEX_CC_EXPIRATION_TODAY);
assertListValue(findNodeByResourceId(saveRequest.structure, ID_ADDRESS),
INDEX_ADDRESS_WORK);
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_HOME_ADDRESS), false);
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_WORK_ADDRESS), true);
assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_SAVE_CC), false);
}
@Test
@AppModeFull(reason = "Service-specific test")
public void testCustomizedSaveUi() throws Exception {
customizedSaveUi(false);
}
@Test
@AppModeFull(reason = "Service-specific test")
public void testCustomizedSaveUiWithContentDescription() throws Exception {
customizedSaveUi(true);
}
/**
* Tests that a spinner can be used on custom save descriptions.
*/
private void customizedSaveUi(boolean withContentDescription) throws Exception {
// Set service.
enableService();
// Set expectations.
final String packageName = getContext().getPackageName();
sReplier.addResponse(new CannedFillResponse.Builder()
.setRequiredSavableIds(SAVE_DATA_TYPE_CREDIT_CARD, ID_CC_NUMBER, ID_CC_EXPIRATION)
.setSaveInfoVisitor((contexts, builder) -> {
final RemoteViews presentation = new RemoteViews(packageName,
R.layout.two_horizontal_text_fields);
final FillContext context = contexts.get(0);
final AutofillId ccNumberId = findAutofillIdByResourceId(context,
ID_CC_NUMBER);
final AutofillId ccExpirationId = findAutofillIdByResourceId(context,
ID_CC_EXPIRATION);
final CharSequenceTransformation trans1 = new CharSequenceTransformation
.Builder(ccNumberId, Pattern.compile("(.*)"), "$1")
.build();
final CharSequenceTransformation trans2 = new CharSequenceTransformation
.Builder(ccExpirationId, Pattern.compile("(.*)"), "$1")
.build();
final ImageTransformation trans3 = (withContentDescription
? new ImageTransformation.Builder(ccNumberId,
Pattern.compile("(.*)"), R.drawable.android,
"One image is worth thousand words")
: new ImageTransformation.Builder(ccNumberId,
Pattern.compile("(.*)"), R.drawable.android))
.build();
final CustomDescription customDescription =
new CustomDescription.Builder(presentation)
.addChild(R.id.first, trans1)
.addChild(R.id.second, trans2)
.addChild(R.id.img, trans3)
.build();
builder.setCustomDescription(customDescription);
})
.build());
// Dynamically change view contents
mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TOMORROW, true));
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Trigger save.
mActivity.onCcNumber((v) -> v.setText("4815162342"));
mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TODAY));
mActivity.tapBuy();
// First make sure the UI is shown...
final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_CREDIT_CARD);
// Then make sure it does have the custom views on it...
final UiObject2 staticText = saveUi.findObject(By.res(packageName, Helper.ID_STATIC_TEXT));
assertThat(staticText).isNotNull();
assertThat(staticText.getText()).isEqualTo("YO:");
final UiObject2 number = saveUi.findObject(By.res(packageName, "first"));
assertThat(number).isNotNull();
assertThat(number.getText()).isEqualTo("4815162342");
final UiObject2 expiration = saveUi.findObject(By.res(packageName, "second"));
assertThat(expiration).isNotNull();
assertThat(expiration.getText()).isEqualTo("today");
final UiObject2 image = saveUi.findObject(By.res(packageName, "img"));
assertThat(image).isNotNull();
final String contentDescription = image.getContentDescription();
if (withContentDescription) {
assertThat(contentDescription).isEqualTo("One image is worth thousand words");
} else {
assertThat(contentDescription).isNull();
}
}
/**
* Tests that a custom save description is ignored when the selected spinner element is not
* available in the autofill options.
*/
@Test
public void testCustomizedSaveUiWhenListResolutionFails() throws Exception {
// Set service.
enableService();
// Change spinner to return just one item so the transformation throws an exception when
// fetching it.
mActivity.getCcExpirationAdapter().setAutofillOptions("D'OH!");
// Set expectations.
final String packageName = getContext().getPackageName();
sReplier.addResponse(new CannedFillResponse.Builder()
.setRequiredSavableIds(SAVE_DATA_TYPE_CREDIT_CARD, ID_CC_NUMBER, ID_CC_EXPIRATION)
.setSaveInfoVisitor((contexts, builder) -> {
final FillContext context = contexts.get(0);
final AutofillId ccNumberId = findAutofillIdByResourceId(context,
ID_CC_NUMBER);
final AutofillId ccExpirationId = findAutofillIdByResourceId(context,
ID_CC_EXPIRATION);
final RemoteViews presentation = new RemoteViews(packageName,
R.layout.two_horizontal_text_fields);
final CharSequenceTransformation trans1 = new CharSequenceTransformation
.Builder(ccNumberId, Pattern.compile("(.*)"), "$1")
.build();
final CharSequenceTransformation trans2 = new CharSequenceTransformation
.Builder(ccExpirationId, Pattern.compile("(.*)"), "$1")
.build();
final CustomDescription customDescription =
new CustomDescription.Builder(presentation)
.addChild(R.id.first, trans1)
.addChild(R.id.second, trans2)
.build();
builder.setCustomDescription(customDescription);
})
.build());
// Dynamically change view contents
mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TOMORROW, true));
// Trigger auto-fill.
mActivity.onCcNumber((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Trigger save.
mActivity.onCcNumber((v) -> v.setText("4815162342"));
mActivity.onCcExpiration((v) -> v.setSelection(INDEX_CC_EXPIRATION_TODAY));
mActivity.tapBuy();
// First make sure the UI is shown...
final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_CREDIT_CARD);
// Then make sure it does not have the custom views on it...
assertThat(saveUi.findObject(By.res(packageName, Helper.ID_STATIC_TEXT))).isNull();
}
// ============================================================================================
// Tests to verify EditText by setting with AutofillValue.
// ============================================================================================
@Test
public void autofillValidTextValue() throws Exception {
autofillEditText(AutofillValue.forText("filled"), "filled", true);
}
@Test
public void autofillEmptyTextValue() throws Exception {
autofillEditText(AutofillValue.forText(""), "", true);
}
@Test
public void autofillTextWithListValue() throws Exception {
autofillEditText(AutofillValue.forList(0), "", false);
}
private void autofillEditText(AutofillValue value, String expectedText,
boolean expectAutoFill) throws Exception {
// Enable service.
enableService();
// Set expectations and trigger Autofill.
sReplier.addResponse(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_CC_NUMBER, value)
.setPresentation(createPresentation("dataset"))
.build());
mActivity.onCcNumber((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Autofill it and check the result.
EditText editText = mActivity.getCcNumber();
OneTimeTextWatcher textWatcher = new OneTimeTextWatcher(ID_CC_NUMBER, editText,
expectedText);
editText.addTextChangedListener(textWatcher);
mUiBot.selectDataset("dataset");
if (expectAutoFill) {
textWatcher.assertAutoFilled();
} else {
assertThat(editText.getText().toString()).isEqualTo(expectedText);
}
}
@Test
public void getEditTextAutoFillValue() throws Exception {
EditText editText = mActivity.getCcNumber();
mActivity.syncRunOnUiThread(() -> editText.setText("test"));
assertThat(editText.getAutofillValue()).isEqualTo(AutofillValue.forText("test"));
mActivity.syncRunOnUiThread(() -> editText.setEnabled(false));
assertThat(editText.getAutofillValue()).isNull();
}
// ============================================================================================
// Tests to verify CheckBox by setting with AutofillValue.
// ============================================================================================
@Test
public void autofillToggleValueWithTrue() throws Exception {
autofillCompoundButton(AutofillValue.forToggle(true), true, true);
}
@Test
public void autofillToggleValueWithFalse() throws Exception {
autofillCompoundButton(AutofillValue.forToggle(false), false, false);
}
@Test
public void autofillCompoundButtonWithTextValue() throws Exception {
autofillCompoundButton(AutofillValue.forText(""), false, false);
}
private void autofillCompoundButton(AutofillValue value, boolean expectedValue,
boolean expectAutoFill) throws Exception {
// Enable service.
enableService();
// Set expectations and trigger Autofill.
sReplier.addResponse(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_SAVE_CC, value)
.setPresentation(createPresentation("dataset"))
.build());
mActivity.onSaveCc((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Autofill it and check the result.
CheckBox compoundButton = mActivity.getSaveCc();
OneTimeCompoundButtonListener checkedWatcher = new OneTimeCompoundButtonListener(
ID_SAVE_CC, compoundButton, expectedValue);
compoundButton.setOnCheckedChangeListener(checkedWatcher);
mUiBot.selectDataset("dataset");
if (expectAutoFill) {
checkedWatcher.assertAutoFilled();
} else {
assertThat(compoundButton.isChecked()).isEqualTo(expectedValue);
}
}
@Test
public void getCompoundButtonAutoFillValue() throws Exception {
CheckBox compoundButton = mActivity.getSaveCc();
mActivity.syncRunOnUiThread(() -> compoundButton.setChecked(true));
assertThat(compoundButton.getAutofillValue()).isEqualTo(AutofillValue.forToggle(true));
mActivity.syncRunOnUiThread(() -> compoundButton.setEnabled(false));
assertThat(compoundButton.getAutofillValue()).isNull();
}
// ============================================================================================
// Tests to verify Spinner by setting with AutofillValue
// ============================================================================================
private void autofillListValue(AutofillValue value, int expectedValue,
boolean expectAutoFill) throws Exception {
// Enable service.
enableService();
// Set expectations and trigger Autofill.
sReplier.addResponse(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_CC_EXPIRATION, value)
.setPresentation(createPresentation("dataset"))
.build());
mActivity.onCcExpiration((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Autofill it and check the result.
Spinner spinner = mActivity.getCcExpiration();
OneTimeSpinnerListener spinnerWatcher = new OneTimeSpinnerListener(
ID_CC_EXPIRATION, spinner, expectedValue);
spinner.setOnItemSelectedListener(spinnerWatcher);
mUiBot.selectDatasetSync("dataset");
if (expectAutoFill) {
spinnerWatcher.assertAutoFilled();
} else {
assertThat(spinner.getSelectedItemPosition()).isEqualTo(expectedValue);
}
}
@Test
public void autofillZeroListValueToSpinner() throws Exception {
autofillListValue(AutofillValue.forList(0), 0, false);
}
@Test
public void autofillOneListValueToSpinner() throws Exception {
autofillListValue(AutofillValue.forList(1), 1, true);
}
@Test
public void autofillInvalidListValueToSpinner() throws Exception {
autofillListValue(AutofillValue.forList(-1), 0, false);
}
@Test
public void autofillSpinnerWithTextValue() throws Exception {
autofillListValue(AutofillValue.forText(""), 0, false);
}
@Test
public void getSpinnerAutoFillValue() throws Exception {
Spinner spinner = mActivity.getCcExpiration();
mActivity.syncRunOnUiThread(() -> spinner.setSelection(1));
assertThat(spinner.getAutofillValue()).isEqualTo(AutofillValue.forList(1));
mActivity.syncRunOnUiThread(() -> spinner.setEnabled(false));
assertThat(spinner.getAutofillValue()).isNull();
}
// ============================================================================================
// Tests to verify DatePicker by setting with AutofillValue
// ============================================================================================
@Test
public void autofillValidDateValueToDatePicker() throws Exception {
autofillDateValueToDatePicker(AutofillValue.forDate(getDateAsMillis(2017, 3, 7, 12, 32)),
true);
}
@Test
public void autofillDatePickerWithTextValue() throws Exception {
autofillDateValueToDatePicker(AutofillValue.forText(""), false);
}
private void autofillDateValueToDatePicker(AutofillValue value,
boolean expectAutoFill) throws Exception {
// Enable service.
enableService();
// Set expectations and trigger Autofill.
sReplier.addResponse(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_DATE_PICKER, value)
.setField(ID_CC_NUMBER, "filled")
.setPresentation(createPresentation("dataset"))
.build());
DatePicker datePicker = mActivity.getDatePicker();
int nonAutofilledYear = datePicker.getYear();
int nonAutofilledMonth = datePicker.getMonth();
int nonAutofilledDay = datePicker.getDayOfMonth();
mActivity.onCcNumber((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Autofill it and check the result.
OneTimeDateListener dateWatcher = new OneTimeDateListener(ID_DATE_PICKER, datePicker,
2017, 3, 7);
datePicker.setOnDateChangedListener(dateWatcher);
mUiBot.selectDataset("dataset");
if (expectAutoFill) {
dateWatcher.assertAutoFilled();
} else {
Helper.assertDateValue(datePicker, nonAutofilledYear, nonAutofilledMonth,
nonAutofilledDay);
}
}
private long getDateAsMillis(int year, int month, int day, int hour, int minute) {
Calendar calendar = Calendar.getInstance(
mActivity.getResources().getConfiguration().getLocales().get(0));
calendar.set(year, month, day, hour, minute);
return calendar.getTimeInMillis();
}
@Test
public void getDatePickerAutoFillValue() throws Exception {
DatePicker datePicker = mActivity.getDatePicker();
mActivity.syncRunOnUiThread(() -> datePicker.updateDate(2017, 3, 7));
Helper.assertDateValue(datePicker, 2017, 3, 7);
mActivity.syncRunOnUiThread(() -> datePicker.setEnabled(false));
assertThat(datePicker.getAutofillValue()).isNull();
}
// ============================================================================================
// Tests to verify TimePicker by setting with AutofillValue
// ============================================================================================
@Test
public void autofillValidDateValueToTimePicker() throws Exception {
autofillDateValueToTimePicker(AutofillValue.forDate(getDateAsMillis(2017, 3, 7, 12, 32)),
true);
}
@Test
public void autofillTimePickerWithTextValue() throws Exception {
autofillDateValueToTimePicker(AutofillValue.forText(""), false);
}
private void autofillDateValueToTimePicker(AutofillValue value,
boolean expectAutoFill) throws Exception {
// Set service.
enableService();
// Set expectations and trigger Autofill.
sReplier.addResponse(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_TIME_PICKER, value)
.setField(ID_CC_NUMBER, "filled")
.setPresentation(createPresentation("dataset"))
.build());
TimePicker timePicker = mActivity.getTimePicker();
mActivity.syncRunOnUiThread(() -> {
timePicker.setIs24HourView(true);
});
int nonAutofilledHour = timePicker.getHour();
int nonAutofilledMinute = timePicker.getMinute();
mActivity.onCcNumber((v) -> v.requestFocus());
sReplier.getNextFillRequest();
// Autofill it and check the result.
MultipleTimesTimeListener timeWatcher = new MultipleTimesTimeListener(ID_TIME_PICKER, 1,
timePicker, 12, 32);
timePicker.setOnTimeChangedListener(timeWatcher);
mUiBot.selectDataset("dataset");
if (expectAutoFill) {
timeWatcher.assertAutoFilled();
} else {
Helper.assertTimeValue(timePicker, nonAutofilledHour, nonAutofilledMinute);
}
}
@Test
public void getTimePickerAutoFillValue() throws Exception {
TimePicker timePicker = mActivity.getTimePicker();
mActivity.syncRunOnUiThread(() -> {
timePicker.setHour(12);
timePicker.setMinute(32);
});
Helper.assertTimeValue(timePicker, 12, 32);
mActivity.syncRunOnUiThread(() -> timePicker.setEnabled(false));
assertThat(timePicker.getAutofillValue()).isNull();
}
// ============================================================================================
// Tests to verify RadioGroup by setting with AutofillValue
// ============================================================================================
@Test
public void autofillZeroListValueToRadioGroup() throws Exception {
autofillRadioGroup(AutofillValue.forList(0), 0, false);
}
@Test
public void autofillOneListValueToRadioGroup() throws Exception {
autofillRadioGroup(AutofillValue.forList(1), 1, true);
}
@Test
public void autofillInvalidListValueToRadioGroup() throws Exception {
autofillRadioGroup(AutofillValue.forList(-1), 0, false);
}
@Test
public void autofillRadioGroupWithTextValue() throws Exception {
autofillRadioGroup(AutofillValue.forText(""), 0, false);
}
private void autofillRadioGroup(AutofillValue value, int expectedValue,
boolean expectAutoFill) throws Exception {
// Set service.
enableService();
// Set expectations and trigger Autofill.
sReplier.addResponse(new CannedFillResponse.CannedDataset.Builder()
.setField(ID_ADDRESS, value)
.setField(ID_CC_NUMBER, "filled")
.setPresentation(createPresentation("dataset"))
.build());
mActivity.onHomeAddress((v) -> v.setChecked(true));
mActivity.onCcNumber((v) -> v.requestFocus());
sReplier.getNextFillRequest();
RadioGroup radioGroup = mActivity.getAddress();
MultipleTimesRadioGroupListener radioGroupWatcher = new MultipleTimesRadioGroupListener(
ID_ADDRESS, 2, radioGroup, expectedValue);
radioGroup.setOnCheckedChangeListener(radioGroupWatcher);
// Autofill it and check the result.
mUiBot.selectDataset("dataset");
if (expectAutoFill) {
radioGroupWatcher.assertAutoFilled();
} else {
if (expectedValue == 0) {
mActivity.assertRadioButtonValue(/* homeAddrValue= */
true, /* workAddrValue= */ false);
} else {
mActivity.assertRadioButtonValue(/* homeAddrValue= */
false, /* workAddrValue= */true);
}
}
}
@Test
public void getRadioGroupAutoFillValue() throws Exception {
RadioGroup radioGroup = mActivity.getAddress();
mActivity.onWorkAddress((v) -> v.setChecked(true));
assertThat(radioGroup.getAutofillValue()).isEqualTo(AutofillValue.forList(1));
mActivity.syncRunOnUiThread(() -> radioGroup.setEnabled(false));
assertThat(radioGroup.getAutofillValue()).isNull();
}
}