blob: fb5ea80e6ed1c8024ccf38e09f3ba5ab9d500dd9 [file] [log] [blame]
Felipe Lemebc907152018-05-02 14:57:23 -07001/*
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
17package android.view.autofill;
18
Felipe Leme984cfdf2018-05-02 16:50:50 -070019import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_HIDDEN;
20import static android.view.autofill.AutofillManager.AutofillCallback.EVENT_INPUT_SHOWN;
Felipe Lemebc907152018-05-02 14:57:23 -070021
koushik panuganti93658912018-12-17 11:46:51 -080022import android.perftests.utils.BenchmarkState;
Riddle Hsu1be1dd62019-09-24 17:54:38 -060023import android.perftests.utils.PerfTestActivity;
koushik panuganti93658912018-12-17 11:46:51 -080024import android.view.View;
25import android.widget.EditText;
26
27import com.android.perftests.autofill.R;
28
29import org.junit.Test;
30
Felipe Lemebc907152018-05-02 14:57:23 -070031public class LoginTest extends AbstractAutofillPerfTestCase {
32
33 private EditText mUsername;
34 private EditText mPassword;
Felipe Leme984cfdf2018-05-02 16:50:50 -070035 private AutofillManager mAfm;
Felipe Lemebc907152018-05-02 14:57:23 -070036
37 public LoginTest() {
38 super(R.layout.test_autofill_login);
39 }
40
41 @Override
Riddle Hsu1be1dd62019-09-24 17:54:38 -060042 protected void onCreate(PerfTestActivity activity) {
Felipe Lemebc907152018-05-02 14:57:23 -070043 View root = activity.getWindow().getDecorView();
44 mUsername = root.findViewById(R.id.username);
45 mPassword = root.findViewById(R.id.password);
Felipe Leme984cfdf2018-05-02 16:50:50 -070046 mAfm = activity.getSystemService(AutofillManager.class);
Felipe Lemebc907152018-05-02 14:57:23 -070047 }
48
49 /**
50 * This is the baseline test for focusing the 2 views when autofill is disabled.
51 */
52 @Test
53 public void testFocus_noService() throws Throwable {
54 resetService();
55
Felipe Lemeb251b7f2018-06-14 10:23:31 -070056 mActivityRule.runOnUiThread(() -> {
57 BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
58 while (state.keepRunning()) {
59 mUsername.requestFocus();
60 mPassword.requestFocus();
61 }
62 });
Felipe Lemebc907152018-05-02 14:57:23 -070063 }
64
65 /**
66 * This time the service is called, but it returns a {@code null} response so the UI behaves
67 * as if autofill was disabled.
68 */
69 @Test
70 public void testFocus_serviceDoesNotAutofill() throws Throwable {
71 MyAutofillService.newCannedResponse().reply();
72 setService();
73
Felipe Lemeb251b7f2018-06-14 10:23:31 -070074 // Must first focus in a field to trigger autofill and wait for service response
75 // outside the loop
76 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
77 MyAutofillService.getLastFillRequest();
78 // Then focus on password so loop start with focus away from username
79 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
80
81 mActivityRule.runOnUiThread(() -> {
82 BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
83 while (state.keepRunning()) {
84 mUsername.requestFocus();
85 mPassword.requestFocus();
86 }
87 });
Felipe Lemebc907152018-05-02 14:57:23 -070088 }
89
90 /**
91 * Now the service returns autofill data, for both username and password.
92 */
93 @Test
94 public void testFocus_autofillBothFields() throws Throwable {
95 MyAutofillService.newCannedResponse()
96 .setUsername(mUsername.getAutofillId(), "user")
97 .setPassword(mPassword.getAutofillId(), "pass")
98 .reply();
99 setService();
100
Felipe Lemeb251b7f2018-06-14 10:23:31 -0700101 // Callback is used to slow down the calls made to the autofill server so the
102 // app is not crashed due to binder exhaustion. But the time spent waiting for the callbacks
103 // is not measured here...
104 MyAutofillCallback callback = new MyAutofillCallback();
105 mAfm.registerCallback(callback);
106
107 // Must first trigger autofill and wait for service response outside the loop
108 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
109 MyAutofillService.getLastFillRequest();
110 callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
111
112 // Then focus on password so loop start with focus away from username
113 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
114 callback.expectEvent(mUsername, EVENT_INPUT_HIDDEN);
115 callback.expectEvent(mPassword, EVENT_INPUT_SHOWN);
116
117
118 // NOTE: we cannot run the whole loop inside the UI thread, because the autofill callback
119 // is called on it, which would cause a deadlock on expectEvent().
120 try {
121 BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
122 while (state.keepRunning()) {
123 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
124 state.pauseTiming(); // Ignore time spent waiting for callbacks
125 callback.expectEvent(mPassword, EVENT_INPUT_HIDDEN);
126 callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
127 state.resumeTiming();
128 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
129 state.pauseTiming(); // Ignore time spent waiting for callbacks
130 callback.expectEvent(mUsername, EVENT_INPUT_HIDDEN);
131 callback.expectEvent(mPassword, EVENT_INPUT_SHOWN);
132 state.resumeTiming();
133 }
134
135 // Sanity check
136 callback.assertNoAsyncErrors();
137 } finally {
138 mAfm.unregisterCallback(callback);
139 }
Felipe Lemebc907152018-05-02 14:57:23 -0700140 }
141
142 /**
143 * Now the service returns autofill data, but just for username.
144 */
145 @Test
146 public void testFocus_autofillUsernameOnly() throws Throwable {
147 // Must set ignored ids so focus on password does not trigger new requests
148 MyAutofillService.newCannedResponse()
149 .setUsername(mUsername.getAutofillId(), "user")
150 .setIgnored(mPassword.getAutofillId())
151 .reply();
152 setService();
153
Felipe Lemeb251b7f2018-06-14 10:23:31 -0700154 // Callback is used to slow down the calls made to the autofill server so the
155 // app is not crashed due to binder exhaustion. But the time spent waiting for the callbacks
156 // is not measured here...
157 MyAutofillCallback callback = new MyAutofillCallback();
158 mAfm.registerCallback(callback);
Felipe Lemebc907152018-05-02 14:57:23 -0700159
Felipe Lemeb251b7f2018-06-14 10:23:31 -0700160 // Must first trigger autofill and wait for service response outside the loop
Felipe Lemebc907152018-05-02 14:57:23 -0700161 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
Felipe Lemeb251b7f2018-06-14 10:23:31 -0700162 MyAutofillService.getLastFillRequest();
163 callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
164
165 // Then focus on password so loop start with focus away from username
166 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
167 callback.expectEvent(mUsername, EVENT_INPUT_HIDDEN);
168
169 // NOTE: we cannot run the whole loop inside the UI thread, because the autofill callback
170 // is called on it, which would cause a deadlock on expectEvent().
171 try {
Felipe Lemebc907152018-05-02 14:57:23 -0700172 BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
173 while (state.keepRunning()) {
Felipe Lemeb251b7f2018-06-14 10:23:31 -0700174 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
175 state.pauseTiming(); // Ignore time spent waiting for callbacks
176 callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
177 state.resumeTiming();
178 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
179 state.pauseTiming(); // Ignore time spent waiting for callbacks
180 callback.expectEvent(mUsername, EVENT_INPUT_HIDDEN);
181 state.resumeTiming();
Felipe Lemebc907152018-05-02 14:57:23 -0700182 }
Felipe Lemeb251b7f2018-06-14 10:23:31 -0700183
184 // Sanity check
185 callback.assertNoAsyncErrors();
186 } finally {
187 mAfm.unregisterCallback(callback);
188 }
Felipe Lemebc907152018-05-02 14:57:23 -0700189 }
190
191 /**
192 * This is the baseline test for changing the 2 views when autofill is disabled.
193 */
194 @Test
195 public void testChange_noService() throws Throwable {
196 resetService();
197
198 changeTest(false);
199 }
200
201 /**
202 * This time the service is called, but it returns a {@code null} response so the UI behaves
203 * as if autofill was disabled.
204 */
205 @Test
206 public void testChange_serviceDoesNotAutofill() throws Throwable {
207 MyAutofillService.newCannedResponse().reply();
208 setService();
209
210 changeTest(true);
Felipe Lemebc907152018-05-02 14:57:23 -0700211 }
212
213 /**
214 * Now the service returns autofill data, for both username and password.
215 */
216 @Test
217 public void testChange_autofillBothFields() throws Throwable {
218 MyAutofillService.newCannedResponse()
219 .setUsername(mUsername.getAutofillId(), "user")
220 .setPassword(mPassword.getAutofillId(), "pass")
221 .reply();
222 setService();
223
224 changeTest(true);
Felipe Lemebc907152018-05-02 14:57:23 -0700225 }
226
227 /**
228 * Now the service returns autofill data, but just for username.
229 */
230 @Test
231 public void testChange_autofillUsernameOnly() throws Throwable {
232 // Must set ignored ids so focus on password does not trigger new requests
233 MyAutofillService.newCannedResponse()
234 .setUsername(mUsername.getAutofillId(), "user")
235 .setIgnored(mPassword.getAutofillId())
236 .reply();
237 setService();
238
239 changeTest(true);
Felipe Lemebc907152018-05-02 14:57:23 -0700240 }
241
242 private void changeTest(boolean waitForService) throws Throwable {
243 // Must first focus in a field to trigger autofill and wait for service response
244 // outside the loop
245 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
246 if (waitForService) {
247 MyAutofillService.getLastFillRequest();
248 }
249 mActivityRule.runOnUiThread(() -> {
250
251 BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
252 while (state.keepRunning()) {
253 mUsername.setText("");
254 mUsername.setText("a");
255 mPassword.setText("");
256 mPassword.setText("x");
257 }
258 });
259 }
Felipe Leme984cfdf2018-05-02 16:50:50 -0700260
261 @Test
262 public void testCallbacks() throws Throwable {
263 MyAutofillService.newCannedResponse()
264 .setUsername(mUsername.getAutofillId(), "user")
265 .setPassword(mPassword.getAutofillId(), "pass")
266 .reply();
267 setService();
268
269 MyAutofillCallback callback = new MyAutofillCallback();
270 mAfm.registerCallback(callback);
271
272 // Must first focus in a field to trigger autofill and wait for service response
273 // outside the loop
274 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
275 MyAutofillService.getLastFillRequest();
276 callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
277
278 // Now focus on password to prepare loop state
279 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
280 callback.expectEvent(mUsername, EVENT_INPUT_HIDDEN);
281 callback.expectEvent(mPassword, EVENT_INPUT_SHOWN);
282
283 // NOTE: we cannot run the whole loop inside the UI thread, because the autofill callback
284 // is called on it, which would cause a deadlock on expectEvent().
285 try {
286 BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
287 while (state.keepRunning()) {
288 mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
289 callback.expectEvent(mPassword, EVENT_INPUT_HIDDEN);
290 callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
291 mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
292 callback.expectEvent(mUsername, EVENT_INPUT_HIDDEN);
293 callback.expectEvent(mPassword, EVENT_INPUT_SHOWN);
294 }
295
296 // Sanity check
297 callback.assertNoAsyncErrors();
Felipe Leme984cfdf2018-05-02 16:50:50 -0700298 } finally {
299 mAfm.unregisterCallback(callback);
300 }
301 }
Felipe Lemebc907152018-05-02 14:57:23 -0700302}