• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.saveui;
17 
18 import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_INPUT;
19 import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_PASSWORD;
20 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_HIDE;
21 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_PASSWORD_MASKED;
22 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_PASSWORD_PLAIN;
23 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_SHOW;
24 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_USERNAME_MASKED;
25 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_USERNAME_PLAIN;
26 import static android.autofillservice.cts.testcore.CustomDescriptionHelper.newCustomDescriptionWithHiddenFields;
27 import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD_LABEL;
28 import static android.autofillservice.cts.testcore.Helper.ID_USERNAME_LABEL;
29 import static android.autofillservice.cts.testcore.Helper.assertTextAndValue;
30 import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId;
31 import static android.autofillservice.cts.testcore.Helper.findNodeByResourceId;
32 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
33 
34 import android.autofillservice.cts.R;
35 import android.autofillservice.cts.activities.SimpleSaveActivity;
36 import android.autofillservice.cts.commontests.AutoFillServiceTestCase;
37 import android.autofillservice.cts.testcore.AutofillActivityTestRule;
38 import android.autofillservice.cts.testcore.CannedFillResponse;
39 import android.autofillservice.cts.testcore.InstrumentedAutoFillService.SaveRequest;
40 import android.autofillservice.cts.testcore.Timeouts;
41 import android.platform.test.annotations.AppModeFull;
42 import android.service.autofill.CharSequenceTransformation;
43 import android.service.autofill.FillContext;
44 import android.service.autofill.OnClickAction;
45 import android.service.autofill.VisibilitySetterAction;
46 import android.view.View;
47 import android.view.autofill.AutofillId;
48 
49 import androidx.test.uiautomator.UiObject2;
50 
51 import org.junit.Test;
52 
53 import java.util.regex.Pattern;
54 
55 /**
56  * Integration tests for the {@link OnClickAction} implementations.
57  */
58 @AppModeFull(reason = "Service-specific test")
59 public class OnClickActionTest
60         extends AutoFillServiceTestCase.AutoActivityLaunch<SimpleSaveActivity> {
61 
62     private static final Pattern MATCH_ALL = Pattern.compile("^(.*)$");
63 
64     private SimpleSaveActivity mActivity;
65 
66     @Override
getActivityRule()67     protected AutofillActivityTestRule<SimpleSaveActivity> getActivityRule() {
68         return new AutofillActivityTestRule<SimpleSaveActivity>(SimpleSaveActivity.class) {
69             @Override
70             protected void afterActivityLaunched() {
71                 mActivity = getActivity();
72             }
73         };
74     }
75 
76     @Test
77     public void testHideAndShow() throws Exception {
78         // Set service.
79         enableService();
80 
81         // Set expectations.
82         sReplier.addResponse(new CannedFillResponse.Builder()
83                 .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT, ID_PASSWORD)
84                 .setSaveInfoVisitor((contexts, builder) -> {
85                     final FillContext context = contexts.get(0);
86                     final AutofillId usernameId = findAutofillIdByResourceId(context, ID_INPUT);
87                     final AutofillId passwordId = findAutofillIdByResourceId(context, ID_PASSWORD);
88 
89                     final CharSequenceTransformation usernameTrans = new CharSequenceTransformation
90                             .Builder(usernameId, MATCH_ALL, "$1").build();
91                     final CharSequenceTransformation passwordTrans = new CharSequenceTransformation
92                             .Builder(passwordId, MATCH_ALL, "$1").build();
93                     builder.setCustomDescription(newCustomDescriptionWithHiddenFields()
94                             .addChild(R.id.username_plain, usernameTrans)
95                             .addChild(R.id.password_plain, passwordTrans)
96                             .addOnClickAction(R.id.show, new VisibilitySetterAction
97                                     .Builder(R.id.hide, View.VISIBLE)
98                                     .setVisibility(R.id.show, View.GONE)
99                                     .setVisibility(R.id.username_plain, View.VISIBLE)
100                                     .setVisibility(R.id.password_plain, View.VISIBLE)
101                                     .setVisibility(R.id.username_masked, View.GONE)
102                                     .setVisibility(R.id.password_masked, View.GONE)
103                                     .build())
104                             .addOnClickAction(R.id.hide, new VisibilitySetterAction
105                                     .Builder(R.id.show, View.VISIBLE)
106                                     .setVisibility(R.id.hide, View.GONE)
107                                     .setVisibility(R.id.username_masked, View.VISIBLE)
108                                     .setVisibility(R.id.password_masked, View.VISIBLE)
109                                     .setVisibility(R.id.username_plain, View.GONE)
110                                     .setVisibility(R.id.password_plain, View.GONE)
111                                     .build())
112                             .build());
113                 })
114                 .build());
115 
116         // Trigger autofill.
117         mActivity.syncRunOnUiThread(() -> mActivity.mInput.requestFocus());
118         sReplier.getNextFillRequest();
119 
120         // Trigger save.
121         mActivity.setTextAndWaitTextChange(/* input= */ "42", /* password= */  "108");
122         mActivity.syncRunOnUiThread(() -> {
123             mActivity.mCommit.performClick();
124         });
125         final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
126 
127         // Assert initial UI is hidden the password.
128         final UiObject2 showButton = assertHidden(saveUi);
129 
130         // Then tap SHOW and assert it's showing how
131         showButton.click();
132         final UiObject2 hideButton = assertShown(saveUi);
133 
134         // Hide again
135         hideButton.click();
136         assertHidden(saveUi);
137 
138         // Rinse-and repeat a couple times
139         showButton.click(); assertShown(saveUi);
140         hideButton.click(); assertHidden(saveUi);
141         showButton.click(); assertShown(saveUi);
142         hideButton.click(); assertHidden(saveUi);
143 
144         // Then save it...
145         mUiBot.saveForAutofill(saveUi, true);
146 
147         // ... and assert results
148         final SaveRequest saveRequest = sReplier.getNextSaveRequest();
149         assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "42");
150         assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_PASSWORD), "108");
151     }
152 
153     /**
154      * Asserts that the Save UI is in the hiding the password field, returning the {@code SHOW}
155      * button.
156      */
157     private UiObject2 assertHidden(UiObject2 saveUi) throws Exception {
158         // Username
159         mUiBot.assertChildText(saveUi, ID_USERNAME_LABEL, "User:");
160         mUiBot.assertChildText(saveUi, ID_USERNAME_MASKED, "****");
161         assertInvisible(saveUi, ID_USERNAME_PLAIN);
162 
163         // Password
164         mUiBot.assertChildText(saveUi, ID_PASSWORD_LABEL, "Pass:");
165         mUiBot.assertChildText(saveUi, ID_PASSWORD_MASKED, "....");
166         assertInvisible(saveUi, ID_PASSWORD_PLAIN);
167 
168         // Buttons
169         assertInvisible(saveUi, ID_HIDE);
170         return mUiBot.assertChildText(saveUi, ID_SHOW, "SHOW");
171     }
172 
173     /**
174      * Asserts that the Save UI is in the showing the password field, returning the {@code HIDE}
175      * button.
176      */
177     private UiObject2 assertShown(UiObject2 saveUi) throws Exception {
178         // Username
179         mUiBot.assertChildText(saveUi, ID_USERNAME_LABEL, "User:");
180         mUiBot.assertChildText(saveUi, ID_USERNAME_PLAIN, "42");
181         assertInvisible(saveUi, ID_USERNAME_MASKED);
182 
183         // Password
184         mUiBot.assertChildText(saveUi, ID_PASSWORD_LABEL, "Pass:");
185         mUiBot.assertChildText(saveUi, ID_PASSWORD_PLAIN, "108");
186         assertInvisible(saveUi, ID_PASSWORD_MASKED);
187 
188         // Buttons
189         assertInvisible(saveUi, ID_SHOW);
190         return mUiBot.assertChildText(saveUi, ID_HIDE, "HIDE");
191     }
192 
193     private void assertInvisible(UiObject2 saveUi, String resourceId) {
194         mUiBot.assertGoneByRelativeId(saveUi, resourceId, Timeouts.UI_TIMEOUT);
195     }
196 }
197