1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.autofillservice.cts; 17 18 import static android.autofillservice.cts.AbstractDatePickerActivity.ID_DATE_PICKER; 19 import static android.autofillservice.cts.AbstractDatePickerActivity.ID_OUTPUT; 20 import static android.autofillservice.cts.Helper.getContext; 21 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC; 22 23 import static com.google.common.truth.Truth.assertThat; 24 25 import android.autofillservice.cts.CannedFillResponse.CannedDataset; 26 import android.icu.text.SimpleDateFormat; 27 import android.platform.test.annotations.AppModeFull; 28 import android.service.autofill.CustomDescription; 29 import android.service.autofill.DateTransformation; 30 import android.service.autofill.DateValueSanitizer; 31 import android.support.test.uiautomator.By; 32 import android.support.test.uiautomator.UiObject2; 33 import android.view.autofill.AutofillId; 34 import android.widget.RemoteViews; 35 36 import org.junit.Before; 37 import org.junit.Rule; 38 import org.junit.Test; 39 40 import java.util.Calendar; 41 42 @AppModeFull // Service-specific test 43 public class CustomDescriptionDateTest extends AutoFillServiceTestCase { 44 45 @Rule 46 public final AutofillActivityTestRule<DatePickerSpinnerActivity> mActivityRule = new 47 AutofillActivityTestRule<DatePickerSpinnerActivity>(DatePickerSpinnerActivity.class); 48 49 private DatePickerSpinnerActivity mActivity; 50 51 @Before 52 public void setActivity() { 53 mActivity = mActivityRule.getActivity(); 54 } 55 56 @Test 57 public void testCustomSave() throws Exception { 58 // Set service. 59 enableService(); 60 61 final AutofillId id = mActivity.getDatePicker().getAutofillId(); 62 63 // Set expectations. 64 sReplier.addResponse(new CannedFillResponse.Builder() 65 .setCustomDescription(new CustomDescription 66 .Builder(newTemplate(R.layout.two_horizontal_text_fields)) 67 .addChild(R.id.first, 68 new DateTransformation(id, new SimpleDateFormat("MM/yyyy"))) 69 .addChild(R.id.second, 70 new DateTransformation(id, new SimpleDateFormat("MM-yy"))) 71 .build()) 72 .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_OUTPUT, ID_DATE_PICKER) 73 .build()); 74 75 // Trigger auto-fill. 76 mActivity.onOutput((v) -> v.requestFocus()); 77 sReplier.getNextFillRequest(); 78 79 // Autofill it. 80 mUiBot.assertNoDatasetsEver(); 81 82 // Trigger save. 83 mActivity.setDate(2010, Calendar.DECEMBER, 12); 84 mActivity.tapOk(); 85 86 // First, make sure the UI is shown... 87 final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC); 88 89 // Then, make sure it does have the custom view on it... 90 final UiObject2 staticText = saveUi.findObject(By.res(mPackageName, "static_text")); 91 assertThat(staticText).isNotNull(); 92 assertThat(staticText.getText()).isEqualTo("YO:"); 93 94 // Finally, assert the custom lines are shown 95 mUiBot.assertChild(saveUi, "first", (o) -> assertThat(o.getText()).isEqualTo("12/2010")); 96 mUiBot.assertChild(saveUi, "second", (o) -> assertThat(o.getText()).isEqualTo("12-10")); 97 } 98 99 @Test 100 public void testSaveSameValue_usingSanitization() throws Exception { 101 sanitizationTest(true); 102 } 103 104 @Test 105 public void testSaveSameValue_withoutSanitization() throws Exception { 106 sanitizationTest(false); 107 } 108 109 private void sanitizationTest(boolean withSanitization) throws Exception { 110 // Set service. 111 enableService(); 112 113 final AutofillId id = mActivity.getDatePicker().getAutofillId(); 114 115 // Set expectations. 116 final Calendar cal = Calendar.getInstance(); 117 cal.clear(); 118 cal.set(Calendar.YEAR, 2012); 119 cal.set(Calendar.MONTH, Calendar.DECEMBER); 120 121 // Set expectations. 122 123 // NOTE: ID_OUTPUT is used to trigger autofill, but it's value will be automatically 124 // changed, hence we need to set the expected value as the formated one. Ideally 125 // we shouldn't worry about that, but that would require creating a new activitiy with 126 // a custom edit text that uses date autofill values... 127 final CannedFillResponse.Builder response = new CannedFillResponse.Builder() 128 .addDataset(new CannedDataset.Builder() 129 .setPresentation(createPresentation("The end of the world")) 130 .setField(ID_OUTPUT, "2012/11/25") 131 .setField(ID_DATE_PICKER, cal.getTimeInMillis()) 132 .build()) 133 .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_OUTPUT, ID_DATE_PICKER); 134 135 if (withSanitization) { 136 response.addSanitizer(new DateValueSanitizer(new SimpleDateFormat("MM/yyyy")), id); 137 } 138 sReplier.addResponse(response.build()); 139 140 // Trigger autofill. 141 mActivity.onOutput((v) -> v.requestFocus()); 142 sReplier.getNextFillRequest(); 143 mUiBot.assertDatasets("The end of the world"); 144 145 // Manually set same values as dataset. 146 mActivity.onOutput((v) -> v.setText("whatever")); 147 mActivity.setDate(2012, Calendar.DECEMBER, 25); 148 mActivity.tapOk(); 149 150 // Verify save behavior. 151 if (withSanitization) { 152 mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC); 153 } else { 154 mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC); 155 } 156 } 157 158 private RemoteViews newTemplate(int resourceId) { 159 return new RemoteViews(getContext().getPackageName(), resourceId); 160 } 161 } 162