1 /* 2 * Copyright (C) 2017 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 17 package android.autofillservice.cts.dropdown; 18 19 import static android.autofillservice.cts.activities.LoginActivity.AUTHENTICATION_MESSAGE; 20 import static android.autofillservice.cts.activities.LoginActivity.BACKDOOR_USERNAME; 21 import static android.autofillservice.cts.activities.LoginActivity.ID_USERNAME_CONTAINER; 22 import static android.autofillservice.cts.activities.LoginActivity.getWelcomeMessage; 23 import static android.autofillservice.cts.testcore.CannedFillResponse.DO_NOT_REPLY_RESPONSE; 24 import static android.autofillservice.cts.testcore.CannedFillResponse.FAIL; 25 import static android.autofillservice.cts.testcore.CannedFillResponse.NO_RESPONSE; 26 import static android.autofillservice.cts.testcore.Helper.ID_CANCEL_FILL; 27 import static android.autofillservice.cts.testcore.Helper.ID_EMPTY; 28 import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD; 29 import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD_LABEL; 30 import static android.autofillservice.cts.testcore.Helper.ID_USERNAME; 31 import static android.autofillservice.cts.testcore.Helper.ID_USERNAME_LABEL; 32 import static android.autofillservice.cts.testcore.Helper.allowOverlays; 33 import static android.autofillservice.cts.testcore.Helper.assertHasFlags; 34 import static android.autofillservice.cts.testcore.Helper.assertNumberOfChildrenWithWindowTitle; 35 import static android.autofillservice.cts.testcore.Helper.assertTextAndValue; 36 import static android.autofillservice.cts.testcore.Helper.assertTextIsSanitized; 37 import static android.autofillservice.cts.testcore.Helper.assertTextOnly; 38 import static android.autofillservice.cts.testcore.Helper.assertValue; 39 import static android.autofillservice.cts.testcore.Helper.assertViewAutofillState; 40 import static android.autofillservice.cts.testcore.Helper.disallowOverlays; 41 import static android.autofillservice.cts.testcore.Helper.dumpStructure; 42 import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId; 43 import static android.autofillservice.cts.testcore.Helper.findNodeByResourceId; 44 import static android.autofillservice.cts.testcore.Helper.getActivityTitle; 45 import static android.autofillservice.cts.testcore.Helper.isAutofillWindowFullScreen; 46 import static android.autofillservice.cts.testcore.Helper.setUserComplete; 47 import static android.autofillservice.cts.testcore.InstrumentedAutoFillService.SERVICE_CLASS; 48 import static android.autofillservice.cts.testcore.InstrumentedAutoFillService.SERVICE_PACKAGE; 49 import static android.autofillservice.cts.testcore.InstrumentedAutoFillService.isConnected; 50 import static android.autofillservice.cts.testcore.InstrumentedAutoFillService.waitUntilConnected; 51 import static android.autofillservice.cts.testcore.InstrumentedAutoFillService.waitUntilDisconnected; 52 import static android.content.Context.CLIPBOARD_SERVICE; 53 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST; 54 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS; 55 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD; 56 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_DEBIT_CARD; 57 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS; 58 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC; 59 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC_CARD; 60 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PASSWORD; 61 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_PAYMENT_CARD; 62 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME; 63 import static android.text.InputType.TYPE_NULL; 64 import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD; 65 import static android.view.View.IMPORTANT_FOR_AUTOFILL_NO; 66 import static android.view.WindowManager.LayoutParams.FLAG_SECURE; 67 68 import static com.android.compatibility.common.util.ShellUtils.sendKeyEvent; 69 import static com.android.compatibility.common.util.ShellUtils.tap; 70 71 import static com.google.common.truth.Truth.assertThat; 72 import static com.google.common.truth.Truth.assertWithMessage; 73 74 import android.app.PendingIntent; 75 import android.app.assist.AssistStructure.ViewNode; 76 import android.autofillservice.cts.R; 77 import android.autofillservice.cts.activities.DummyActivity; 78 import android.autofillservice.cts.activities.EmptyActivity; 79 import android.autofillservice.cts.commontests.LoginActivityCommonTestCase; 80 import android.autofillservice.cts.testcore.BadAutofillService; 81 import android.autofillservice.cts.testcore.CannedFillResponse; 82 import android.autofillservice.cts.testcore.CannedFillResponse.CannedDataset; 83 import android.autofillservice.cts.testcore.DismissType; 84 import android.autofillservice.cts.testcore.Helper; 85 import android.autofillservice.cts.testcore.InstrumentedAutoFillService.FillRequest; 86 import android.autofillservice.cts.testcore.InstrumentedAutoFillService.SaveRequest; 87 import android.autofillservice.cts.testcore.MyAutofillCallback; 88 import android.autofillservice.cts.testcore.NoOpAutofillService; 89 import android.autofillservice.cts.testcore.OneTimeCancellationSignalListener; 90 import android.autofillservice.cts.testcore.OneTimeTextWatcher; 91 import android.autofillservice.cts.testcore.Timeouts; 92 import android.content.BroadcastReceiver; 93 import android.content.ClipData; 94 import android.content.ClipboardManager; 95 import android.content.ComponentName; 96 import android.content.Context; 97 import android.content.Intent; 98 import android.content.IntentFilter; 99 import android.content.IntentSender; 100 import android.graphics.Color; 101 import android.graphics.Rect; 102 import android.os.Bundle; 103 import android.os.SystemClock; 104 import android.platform.test.annotations.AppModeFull; 105 import android.platform.test.annotations.Presubmit; 106 import android.service.autofill.FillContext; 107 import android.service.autofill.SaveInfo; 108 import android.support.test.uiautomator.UiObject2; 109 import android.util.Log; 110 import android.view.View; 111 import android.view.View.AccessibilityDelegate; 112 import android.view.ViewGroup; 113 import android.view.WindowManager; 114 import android.view.accessibility.AccessibilityNodeInfo; 115 import android.view.accessibility.AccessibilityNodeProvider; 116 import android.view.autofill.AutofillManager; 117 import android.widget.EditText; 118 import android.widget.RemoteViews; 119 120 import androidx.test.InstrumentationRegistry; 121 import androidx.test.filters.FlakyTest; 122 123 import com.android.compatibility.common.util.RetryableException; 124 125 import org.junit.Test; 126 127 import java.util.concurrent.CountDownLatch; 128 import java.util.concurrent.TimeUnit; 129 import java.util.concurrent.atomic.AtomicInteger; 130 131 /** 132 * This is the test case covering most scenarios - other test cases will cover characteristics 133 * specific to that test's activity (for example, custom views). 134 */ 135 public class LoginActivityTest extends LoginActivityCommonTestCase { 136 137 private static final String TAG = "LoginActivityTest"; 138 139 @Test 140 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutofillAutomaticallyAfterServiceReturnedNoDatasets()141 public void testAutofillAutomaticallyAfterServiceReturnedNoDatasets() throws Exception { 142 // Set service. 143 enableService(); 144 145 // Set expectations. 146 sReplier.addResponse(NO_RESPONSE); 147 mActivity.expectAutoFill("dude", "sweet"); 148 149 // Trigger autofill. 150 mActivity.onUsername(View::requestFocus); 151 sReplier.getNextFillRequest(); 152 153 // Make sure UI is not shown. 154 mUiBot.assertNoDatasetsEver(); 155 156 // Try again, in a field that was added after the first request 157 final EditText child = new EditText(mActivity); 158 child.setId(R.id.empty); 159 mActivity.addChild(child); 160 final OneTimeTextWatcher watcher = new OneTimeTextWatcher("child", child, 161 "new view on the block"); 162 child.addTextChangedListener(watcher); 163 sReplier.addResponse(new CannedDataset.Builder() 164 .setField(ID_USERNAME, "dude") 165 .setField(ID_PASSWORD, "sweet") 166 .setField(ID_EMPTY, "new view on the block") 167 .setPresentation(createPresentation("The Dude")) 168 .build()); 169 mActivity.syncRunOnUiThread(() -> child.requestFocus()); 170 171 sReplier.getNextFillRequest(); 172 173 // Select the dataset. 174 mUiBot.selectDataset("The Dude"); 175 176 // Check the results. 177 mActivity.assertAutoFilled(); 178 watcher.assertAutoFilled(); 179 } 180 181 @Test 182 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutofillManuallyAfterServiceReturnedNoDatasets()183 public void testAutofillManuallyAfterServiceReturnedNoDatasets() throws Exception { 184 // Set service. 185 enableService(); 186 187 // Set expectations. 188 sReplier.addResponse(NO_RESPONSE); 189 mActivity.expectAutoFill("dude", "sweet"); 190 191 // Trigger autofill. 192 mActivity.onUsername(View::requestFocus); 193 sReplier.getNextFillRequest(); 194 195 // Make sure UI is not shown. 196 mUiBot.assertNoDatasetsEver(); 197 198 // Try again, forcing it 199 sReplier.addResponse(new CannedDataset.Builder() 200 .setField(ID_USERNAME, "dude") 201 .setField(ID_PASSWORD, "sweet") 202 .setPresentation(createPresentation("The Dude")) 203 .build()); 204 205 mActivity.forceAutofillOnUsername(); 206 207 final FillRequest fillRequest = sReplier.getNextFillRequest(); 208 assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST); 209 210 // Select the dataset. 211 mUiBot.selectDataset("The Dude"); 212 213 // Check the results. 214 mActivity.assertAutoFilled(); 215 } 216 217 @Test 218 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutofillManuallyAndSaveAfterServiceReturnedNoDatasets()219 public void testAutofillManuallyAndSaveAfterServiceReturnedNoDatasets() throws Exception { 220 // Set service. 221 enableService(); 222 223 // Set expectations. 224 sReplier.addResponse(NO_RESPONSE); 225 226 // Trigger autofill. 227 // NOTE: must be on password, as saveOnlyTest() will trigger on username 228 mActivity.onPassword(View::requestFocus); 229 sReplier.getNextFillRequest(); 230 231 // Make sure UI is not shown. 232 mUiBot.assertNoDatasetsEver(); 233 sReplier.assertNoUnhandledFillRequests(); 234 mActivity.onPassword(View::requestFocus); 235 mUiBot.assertNoDatasetsEver(); 236 sReplier.assertNoUnhandledFillRequests(); 237 238 // Try again, forcing it 239 saveOnlyTest(/* manually= */ true); 240 } 241 242 @Test 243 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutofillAutomaticallyAndSaveAfterServiceReturnedNoDatasets()244 public void testAutofillAutomaticallyAndSaveAfterServiceReturnedNoDatasets() throws Exception { 245 // Set service. 246 enableService(); 247 248 // Set expectations. 249 sReplier.addResponse(NO_RESPONSE); 250 mActivity.expectAutoFill("dude", "sweet"); 251 252 // Trigger autofill. 253 mActivity.onUsername(View::requestFocus); 254 sReplier.getNextFillRequest(); 255 256 // Make sure UI is not shown. 257 mUiBot.assertNoDatasetsEver(); 258 259 // Try again, in a field that was added after the first request 260 final EditText child = new EditText(mActivity); 261 child.setId(R.id.empty); 262 mActivity.addChild(child); 263 sReplier.addResponse(new CannedFillResponse.Builder() 264 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, 265 ID_USERNAME, 266 ID_PASSWORD, 267 ID_EMPTY) 268 .build()); 269 mActivity.syncRunOnUiThread(() -> child.requestFocus()); 270 271 // Validation check. 272 mUiBot.assertNoDatasetsEver(); 273 274 // Wait for onFill() before proceeding, otherwise the fields might be changed before 275 // the session started 276 sReplier.getNextFillRequest(); 277 278 // Set credentials... 279 mActivity.onUsername((v) -> v.setText("malkovich")); 280 mActivity.onPassword((v) -> v.setText("malkovich")); 281 mActivity.runOnUiThread(() -> child.setText("NOT MR.M")); 282 283 // ...and login 284 final String expectedMessage = getWelcomeMessage("malkovich"); 285 final String actualMessage = mActivity.tapLogin(); 286 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 287 288 // Assert the snack bar is shown and tap "Save". 289 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 290 291 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 292 sReplier.assertNoUnhandledSaveRequests(); 293 assertThat(saveRequest.datasetIds).isNull(); 294 295 // Assert value of expected fields - should not be sanitized. 296 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 297 assertTextAndValue(username, "malkovich"); 298 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 299 assertTextAndValue(password, "malkovich"); 300 final ViewNode childNode = findNodeByResourceId(saveRequest.structure, ID_EMPTY); 301 assertTextAndValue(childNode, "NOT MR.M"); 302 } 303 304 /** 305 * More detailed test of what should happen after a service returns a {@code null} FillResponse: 306 * views that have already been visit should not trigger a new session, unless a manual autofill 307 * workflow was requested. 308 */ 309 @Test 310 @AppModeFull(reason = "testAutoFillNoDatasets() is enough") testMultipleIterationsAfterServiceReturnedNoDatasets()311 public void testMultipleIterationsAfterServiceReturnedNoDatasets() throws Exception { 312 // Set service. 313 enableService(); 314 315 // Trigger autofill on username - should call service 316 sReplier.addResponse(NO_RESPONSE); 317 mActivity.onUsername(View::requestFocus); 318 sReplier.getNextFillRequest(); 319 waitUntilDisconnected(); 320 321 // Every other call should be ignored 322 mActivity.onPassword(View::requestFocus); 323 mActivity.onUsername(View::requestFocus); 324 mActivity.onPassword(View::requestFocus); 325 326 // Trigger autofill by manually requesting username - should call service 327 sReplier.addResponse(NO_RESPONSE); 328 mActivity.forceAutofillOnUsername(); 329 final FillRequest manualRequest1 = sReplier.getNextFillRequest(); 330 assertHasFlags(manualRequest1.flags, FLAG_MANUAL_REQUEST); 331 waitUntilDisconnected(); 332 333 // Trigger autofill by manually requesting password - should call service 334 sReplier.addResponse(NO_RESPONSE); 335 mActivity.forceAutofillOnPassword(); 336 final FillRequest manualRequest2 = sReplier.getNextFillRequest(); 337 assertHasFlags(manualRequest2.flags, FLAG_MANUAL_REQUEST); 338 waitUntilDisconnected(); 339 } 340 341 @FlakyTest(bugId = 162372863) 342 @Test 343 @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough") testAutofillManuallyAlwaysCallServiceAgain()344 public void testAutofillManuallyAlwaysCallServiceAgain() throws Exception { 345 // Set service. 346 enableService(); 347 348 // First request 349 sReplier.addResponse(new CannedDataset.Builder() 350 .setField(ID_USERNAME, "dude") 351 .setField(ID_PASSWORD, "sweet") 352 .setPresentation(createPresentation("The Dude")) 353 .build()); 354 mActivity.onUsername(View::requestFocus); 355 // Waits for the fill request to be sent to the autofill service 356 mUiBot.waitForIdleSync(); 357 358 sReplier.getNextFillRequest(); 359 mUiBot.assertDatasets("The Dude"); 360 361 // Second request 362 sReplier.addResponse(new CannedDataset.Builder() 363 .setField(ID_USERNAME, "DUDE") 364 .setField(ID_PASSWORD, "SWEET") 365 .setPresentation(createPresentation("THE DUDE")) 366 .build()); 367 368 mUiBot.waitForWindowChange(() -> mActivity.forceAutofillOnUsername()); 369 370 final FillRequest secondRequest = sReplier.getNextFillRequest(); 371 assertHasFlags(secondRequest.flags, FLAG_MANUAL_REQUEST); 372 mUiBot.assertDatasets("THE DUDE"); 373 } 374 375 @Presubmit 376 @Test testAutoFillOneDataset()377 public void testAutoFillOneDataset() throws Exception { 378 autofillOneDatasetTest(BorderType.NONE); 379 } 380 381 @Test 382 @AppModeFull(reason = "testAutoFillOneDataset_withHeaderAndFooter() is enough") testAutoFillOneDataset_withHeader()383 public void testAutoFillOneDataset_withHeader() throws Exception { 384 autofillOneDatasetTest(BorderType.HEADER_ONLY); 385 } 386 387 @Test 388 @AppModeFull(reason = "testAutoFillOneDataset_withHeaderAndFooter() is enough") testAutoFillOneDataset_withFooter()389 public void testAutoFillOneDataset_withFooter() throws Exception { 390 autofillOneDatasetTest(BorderType.FOOTER_ONLY); 391 } 392 393 @Presubmit 394 @Test testAutoFillOneDataset_withHeaderAndFooter()395 public void testAutoFillOneDataset_withHeaderAndFooter() throws Exception { 396 autofillOneDatasetTest(BorderType.BOTH); 397 } 398 399 private enum BorderType { 400 NONE, 401 HEADER_ONLY, 402 FOOTER_ONLY, 403 BOTH 404 } 405 autofillOneDatasetTest(BorderType borderType)406 private void autofillOneDatasetTest(BorderType borderType) throws Exception { 407 // Set service. 408 enableService(); 409 410 // Set expectations. 411 String expectedHeader = null, expectedFooter = null; 412 413 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 414 .addDataset(new CannedDataset.Builder() 415 .setField(ID_USERNAME, "dude") 416 .setField(ID_PASSWORD, "sweet") 417 .setPresentation(createPresentation("The Dude")) 418 .build()); 419 if (borderType == BorderType.BOTH || borderType == BorderType.HEADER_ONLY) { 420 expectedHeader = "Head"; 421 builder.setHeader(createPresentation(expectedHeader)); 422 } 423 if (borderType == BorderType.BOTH || borderType == BorderType.FOOTER_ONLY) { 424 expectedFooter = "Tails"; 425 builder.setFooter(createPresentation(expectedFooter)); 426 } 427 sReplier.addResponse(builder.build()); 428 mActivity.expectAutoFill("dude", "sweet"); 429 430 // Dynamically set password to make sure it's sanitized. 431 mActivity.onPassword((v) -> v.setText("I AM GROOT")); 432 433 // Trigger auto-fill. 434 requestFocusOnUsername(); 435 436 // Auto-fill it. 437 final UiObject2 picker = mUiBot.assertDatasetsWithBorders(expectedHeader, expectedFooter, 438 "The Dude"); 439 440 mUiBot.selectDataset(picker, "The Dude"); 441 442 // Check the results. 443 mActivity.assertAutoFilled(); 444 445 // Validation checks. 446 447 // Make sure input was sanitized. 448 final FillRequest request = sReplier.getNextFillRequest(); 449 assertWithMessage("CancelationSignal is null").that(request.cancellationSignal).isNotNull(); 450 assertTextIsSanitized(request.structure, ID_PASSWORD); 451 final FillContext fillContext = request.contexts.get(request.contexts.size() - 1); 452 assertThat(fillContext.getFocusedId()) 453 .isEqualTo(findAutofillIdByResourceId(fillContext, ID_USERNAME)); 454 455 // Make sure initial focus was properly set. 456 assertWithMessage("Username node is not focused").that( 457 findNodeByResourceId(request.structure, ID_USERNAME).isFocused()).isTrue(); 458 assertWithMessage("Password node is focused").that( 459 findNodeByResourceId(request.structure, ID_PASSWORD).isFocused()).isFalse(); 460 } 461 462 463 @Test 464 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutofillAgainAfterOnFailure()465 public void testAutofillAgainAfterOnFailure() throws Exception { 466 // Set service. 467 enableService(); 468 469 // Set expectations. 470 sReplier.addResponse(FAIL); 471 472 // Trigger autofill. 473 requestFocusOnUsernameNoWindowChange(); 474 sReplier.getNextFillRequest(); 475 mUiBot.assertNoDatasetsEver(); 476 477 // Try again 478 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 479 .addDataset(new CannedDataset.Builder() 480 .setField(ID_USERNAME, "dude") 481 .setField(ID_PASSWORD, "sweet") 482 .setPresentation(createPresentation("The Dude")) 483 .build()); 484 sReplier.addResponse(builder.build()); 485 486 // Trigger autofill. 487 clearFocus(); 488 requestFocusOnUsername(); 489 sReplier.getNextFillRequest(); 490 mActivity.expectAutoFill("dude", "sweet"); 491 mUiBot.selectDataset("The Dude"); 492 493 // Check the results. 494 mActivity.assertAutoFilled(); 495 } 496 497 @Test testDatasetPickerPosition()498 public void testDatasetPickerPosition() throws Exception { 499 final boolean pickerAndViewBoundsMatches = !isAutofillWindowFullScreen(mContext); 500 501 // Set service. 502 enableService(); 503 final MyAutofillCallback callback = mActivity.registerCallback(); 504 final View username = mActivity.getUsername(); 505 final View password = mActivity.getPassword(); 506 507 // Set expectations. 508 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 509 .addDataset(new CannedDataset.Builder() 510 .setField(ID_USERNAME, "dude", createPresentation("DUDE")) 511 .setField(ID_PASSWORD, "sweet", createPresentation("SWEET")) 512 .build()); 513 sReplier.addResponse(builder.build()); 514 515 // Trigger autofill on username 516 final Rect usernameBoundaries1 = mUiBot.selectByRelativeId(ID_USERNAME).getVisibleBounds(); 517 sReplier.getNextFillRequest(); 518 callback.assertUiShownEvent(username); 519 final Rect usernamePickerBoundaries1 = mUiBot.assertDatasets("DUDE").getVisibleBounds(); 520 Log.v(TAG, 521 "Username1 at " + usernameBoundaries1 + "; picker at " + usernamePickerBoundaries1); 522 523 if (pickerAndViewBoundsMatches) { 524 boolean isMockImeAvailable = sMockImeSessionRule.getMockImeSession() != null; 525 if (!isMockImeAvailable) { 526 // If Mock IME cannot be installed, depending on the height of the IME, 527 // picker may not be displayed just-below/just-above EditText. 528 // So, picker should be allowed to overlap with EditText. 529 // And it should be visible to the user. 530 // Gets the Activity visible frame to appWindowFrame. 531 // And checks whether all of the following conditions are matched. 532 // 1) Picker.top <= Username1.bottom 533 // 2) Picker.bottom >= Username1.top 534 // 3) Picker ∈ appWindowFrame 535 final Rect appWindowFrame = new Rect(); 536 mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(appWindowFrame); 537 Log.v(TAG, "appWindowFrame at " + appWindowFrame); 538 539 assertThat(usernamePickerBoundaries1.top).isAtMost(usernameBoundaries1.bottom); 540 assertThat(usernamePickerBoundaries1.bottom).isAtLeast(usernameBoundaries1.top); 541 assertThat(appWindowFrame.contains(usernamePickerBoundaries1)).isTrue(); 542 } else { 543 // TODO(b/37566627): assertions below might be too aggressive - use range instead? 544 if (usernamePickerBoundaries1.top < usernameBoundaries1.bottom) { 545 assertThat(usernamePickerBoundaries1.bottom).isEqualTo(usernameBoundaries1.top); 546 } else { 547 assertThat(usernamePickerBoundaries1.top).isEqualTo(usernameBoundaries1.bottom); 548 } 549 } 550 assertThat(usernamePickerBoundaries1.left).isEqualTo(usernameBoundaries1.left); 551 } 552 553 // Move to password 554 final Rect passwordBoundaries1 = mUiBot.selectByRelativeId(ID_PASSWORD).getVisibleBounds(); 555 callback.assertUiHiddenEvent(username); 556 callback.assertUiShownEvent(password); 557 final Rect passwordPickerBoundaries1 = mUiBot.assertDatasets("SWEET").getVisibleBounds(); 558 Log.v(TAG, 559 "Password1 at " + passwordBoundaries1 + "; picker at " + passwordPickerBoundaries1); 560 // TODO(b/37566627): assertions below might be too aggressive - use range instead? 561 if (pickerAndViewBoundsMatches) { 562 if (passwordPickerBoundaries1.top < passwordBoundaries1.bottom) { 563 assertThat(passwordPickerBoundaries1.bottom).isEqualTo(passwordBoundaries1.top); 564 } else { 565 assertThat(passwordPickerBoundaries1.top).isEqualTo(passwordBoundaries1.bottom); 566 } 567 assertThat(passwordPickerBoundaries1.left).isEqualTo(passwordBoundaries1.left); 568 } 569 570 // Then back to username 571 final Rect usernameBoundaries2 = mUiBot.selectByRelativeId(ID_USERNAME).getVisibleBounds(); 572 callback.assertUiHiddenEvent(password); 573 callback.assertUiShownEvent(username); 574 final Rect usernamePickerBoundaries2 = mUiBot.assertDatasets("DUDE").getVisibleBounds(); 575 Log.v(TAG, 576 "Username2 at " + usernameBoundaries2 + "; picker at " + usernamePickerBoundaries2); 577 578 // And back to the password again.. 579 final Rect passwordBoundaries2 = mUiBot.selectByRelativeId(ID_PASSWORD).getVisibleBounds(); 580 callback.assertUiHiddenEvent(username); 581 callback.assertUiShownEvent(password); 582 final Rect passwordPickerBoundaries2 = mUiBot.assertDatasets("SWEET").getVisibleBounds(); 583 Log.v(TAG, 584 "Password2 at " + passwordBoundaries2 + "; picker at " + passwordPickerBoundaries2); 585 586 // Assert final state matches initial... 587 // ... for username 588 assertWithMessage("Username2 at %s; Username1 at %s", usernameBoundaries2, 589 usernamePickerBoundaries1).that(usernameBoundaries2).isEqualTo(usernameBoundaries1); 590 assertWithMessage("Username2 picker at %s; Username1 picker at %s", 591 usernamePickerBoundaries2, usernamePickerBoundaries1).that( 592 usernamePickerBoundaries2).isEqualTo(usernamePickerBoundaries1); 593 594 // ... for password 595 assertWithMessage("Password2 at %s; Password1 at %s", passwordBoundaries2, 596 passwordBoundaries1).that(passwordBoundaries2).isEqualTo(passwordBoundaries1); 597 assertWithMessage("Password2 picker at %s; Password1 picker at %s", 598 passwordPickerBoundaries2, passwordPickerBoundaries1).that( 599 passwordPickerBoundaries2).isEqualTo(passwordPickerBoundaries1); 600 601 // Final validation check 602 callback.assertNumberUnhandledEvents(0); 603 } 604 605 @Test 606 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillTwoDatasetsSameNumberOfFields()607 public void testAutoFillTwoDatasetsSameNumberOfFields() throws Exception { 608 // Set service. 609 enableService(); 610 611 // Set expectations. 612 sReplier.addResponse(new CannedFillResponse.Builder() 613 .addDataset(new CannedDataset.Builder() 614 .setField(ID_USERNAME, "dude") 615 .setField(ID_PASSWORD, "sweet") 616 .setPresentation(createPresentation("The Dude")) 617 .build()) 618 .addDataset(new CannedDataset.Builder() 619 .setField(ID_USERNAME, "DUDE") 620 .setField(ID_PASSWORD, "SWEET") 621 .setPresentation(createPresentation("THE DUDE")) 622 .build()) 623 .build()); 624 mActivity.expectAutoFill("dude", "sweet"); 625 626 // Trigger auto-fill. 627 requestFocusOnUsername(); 628 sReplier.getNextFillRequest(); 629 630 // Make sure all datasets are available... 631 mUiBot.assertDatasets("The Dude", "THE DUDE"); 632 633 // ... on all fields. 634 requestFocusOnPassword(); 635 mUiBot.assertDatasets("The Dude", "THE DUDE"); 636 637 // Auto-fill it. 638 mUiBot.selectDataset("The Dude"); 639 640 // Check the results. 641 mActivity.assertAutoFilled(); 642 } 643 644 @Test 645 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsAll()646 public void testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsAll() throws Exception { 647 autoFillTwoDatasetsUnevenNumberOfFieldsTest(true); 648 } 649 650 @Test 651 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsOne()652 public void testAutoFillTwoDatasetsUnevenNumberOfFieldsFillsOne() throws Exception { 653 autoFillTwoDatasetsUnevenNumberOfFieldsTest(false); 654 } 655 autoFillTwoDatasetsUnevenNumberOfFieldsTest(boolean fillsAll)656 private void autoFillTwoDatasetsUnevenNumberOfFieldsTest(boolean fillsAll) throws Exception { 657 // Set service. 658 enableService(); 659 660 // Set expectations. 661 sReplier.addResponse(new CannedFillResponse.Builder() 662 .addDataset(new CannedDataset.Builder() 663 .setField(ID_USERNAME, "dude") 664 .setField(ID_PASSWORD, "sweet") 665 .setPresentation(createPresentation("The Dude")) 666 .build()) 667 .addDataset(new CannedDataset.Builder() 668 .setField(ID_USERNAME, "DUDE") 669 .setPresentation(createPresentation("THE DUDE")) 670 .build()) 671 .build()); 672 if (fillsAll) { 673 mActivity.expectAutoFill("dude", "sweet"); 674 } else { 675 mActivity.expectAutoFill("DUDE"); 676 } 677 678 // Trigger auto-fill. 679 requestFocusOnUsername(); 680 sReplier.getNextFillRequest(); 681 682 // Make sure all datasets are available on username... 683 mUiBot.assertDatasets("The Dude", "THE DUDE"); 684 685 // ... but just one for password 686 requestFocusOnPassword(); 687 mUiBot.assertDatasets("The Dude"); 688 689 // Auto-fill it. 690 requestFocusOnUsername(); 691 mUiBot.assertDatasets("The Dude", "THE DUDE"); 692 if (fillsAll) { 693 mUiBot.selectDataset("The Dude"); 694 } else { 695 mUiBot.selectDataset("THE DUDE"); 696 } 697 698 // Check the results. 699 mActivity.assertAutoFilled(); 700 } 701 702 @Test 703 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillDatasetWithoutFieldIsIgnored()704 public void testAutoFillDatasetWithoutFieldIsIgnored() throws Exception { 705 // Set service. 706 enableService(); 707 708 // Set expectations. 709 sReplier.addResponse(new CannedFillResponse.Builder() 710 .addDataset(new CannedDataset.Builder() 711 .setField(ID_USERNAME, "dude") 712 .setField(ID_PASSWORD, "sweet") 713 .setPresentation(createPresentation("The Dude")) 714 .build()) 715 .addDataset(new CannedDataset.Builder() 716 .setField(ID_USERNAME, "DUDE") 717 .setField(ID_PASSWORD, "SWEET") 718 .build()) 719 .build()); 720 mActivity.expectAutoFill("dude", "sweet"); 721 722 // Trigger auto-fill. 723 requestFocusOnUsername(); 724 sReplier.getNextFillRequest(); 725 726 // Make sure all datasets are available... 727 mUiBot.assertDatasets("The Dude"); 728 729 // ... on all fields. 730 requestFocusOnPassword(); 731 mUiBot.assertDatasets("The Dude"); 732 733 // Auto-fill it. 734 mUiBot.selectDataset("The Dude"); 735 736 // Check the results. 737 mActivity.assertAutoFilled(); 738 } 739 740 @Presubmit 741 @Test testAutoFillWhenViewHasChildAccessibilityNodes()742 public void testAutoFillWhenViewHasChildAccessibilityNodes() throws Exception { 743 mActivity.onUsername((v) -> v.setAccessibilityDelegate(new AccessibilityDelegate() { 744 @Override 745 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 746 return new AccessibilityNodeProvider() { 747 @Override 748 public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { 749 final AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(); 750 if (virtualViewId == View.NO_ID) { 751 info.addChild(v, 108); 752 } 753 return info; 754 } 755 }; 756 } 757 })); 758 759 testAutoFillOneDataset(); 760 } 761 762 @Presubmit 763 @Test testAutoFillOneDatasetAndMoveFocusAround()764 public void testAutoFillOneDatasetAndMoveFocusAround() throws Exception { 765 // Set service. 766 enableService(); 767 768 // Set expectations. 769 sReplier.addResponse(new CannedDataset.Builder() 770 .setField(ID_USERNAME, "dude") 771 .setField(ID_PASSWORD, "sweet") 772 .setPresentation(createPresentation("The Dude")) 773 .build()); 774 mActivity.expectAutoFill("dude", "sweet"); 775 776 // Trigger auto-fill. 777 requestFocusOnUsername(); 778 sReplier.getNextFillRequest(); 779 780 // Make sure tapping on other fields from the dataset does not trigger it again 781 requestFocusOnPassword(); 782 sReplier.assertNoUnhandledFillRequests(); 783 784 requestFocusOnUsername(); 785 sReplier.assertNoUnhandledFillRequests(); 786 787 // Auto-fill it. 788 mUiBot.selectDataset("The Dude"); 789 790 // Check the results. 791 mActivity.assertAutoFilled(); 792 793 // Make sure tapping on other fields from the dataset does not trigger it again 794 requestFocusOnPassword(); 795 mUiBot.assertNoDatasets(); 796 requestFocusOnUsernameNoWindowChange(); 797 mUiBot.assertNoDatasetsEver(); 798 } 799 800 @Test testUiNotShownAfterAutofilled()801 public void testUiNotShownAfterAutofilled() throws Exception { 802 // Set service. 803 enableService(); 804 805 // Set expectations. 806 sReplier.addResponse(new CannedDataset.Builder() 807 .setField(ID_USERNAME, "dude") 808 .setField(ID_PASSWORD, "sweet") 809 .setPresentation(createPresentation("The Dude")) 810 .build()); 811 mActivity.expectAutoFill("dude", "sweet"); 812 813 // Trigger auto-fill. 814 requestFocusOnUsername(); 815 sReplier.getNextFillRequest(); 816 mUiBot.selectDataset("The Dude"); 817 818 // Check the results. 819 mActivity.assertAutoFilled(); 820 821 // Make sure tapping on autofilled field does not trigger it again 822 requestFocusOnPassword(); 823 mUiBot.assertNoDatasets(); 824 825 requestFocusOnUsernameNoWindowChange(); 826 mUiBot.assertNoDatasetsEver(); 827 } 828 829 @Presubmit 830 @Test testAutofillTapOutside()831 public void testAutofillTapOutside() throws Exception { 832 // Set service. 833 enableService(); 834 final MyAutofillCallback callback = mActivity.registerCallback(); 835 836 // Set expectations. 837 sReplier.addResponse(new CannedDataset.Builder() 838 .setField(ID_USERNAME, "dude") 839 .setField(ID_PASSWORD, "sweet") 840 .setPresentation(createPresentation("The Dude")) 841 .build()); 842 mActivity.expectAutoFill("dude", "sweet"); 843 844 // Trigger autofill. 845 requestFocusOnUsername(); 846 sReplier.getNextFillRequest(); 847 final View username = mActivity.getUsername(); 848 849 callback.assertUiShownEvent(username); 850 mUiBot.assertDatasets("The Dude"); 851 852 // tapping outside autofill window should close it and raise ui hidden event 853 mUiBot.waitForWindowChange(() -> tap(mActivity.getUsernameLabel())); 854 callback.assertUiHiddenEvent(username); 855 856 mUiBot.assertNoDatasets(); 857 } 858 859 @Presubmit 860 @Test testAutofillCallbacks()861 public void testAutofillCallbacks() throws Exception { 862 // Set service. 863 enableService(); 864 final MyAutofillCallback callback = mActivity.registerCallback(); 865 866 // Set expectations. 867 sReplier.addResponse(new CannedDataset.Builder() 868 .setField(ID_USERNAME, "dude") 869 .setField(ID_PASSWORD, "sweet") 870 .setPresentation(createPresentation("The Dude")) 871 .build()); 872 mActivity.expectAutoFill("dude", "sweet"); 873 874 // Trigger autofill. 875 requestFocusOnUsername(); 876 sReplier.getNextFillRequest(); 877 final View username = mActivity.getUsername(); 878 final View password = mActivity.getPassword(); 879 880 callback.assertUiShownEvent(username); 881 882 requestFocusOnPassword(); 883 callback.assertUiHiddenEvent(username); 884 callback.assertUiShownEvent(password); 885 886 // Unregister callback to make sure no more events are received 887 mActivity.unregisterCallback(); 888 requestFocusOnUsername(); 889 // Blindly sleep - we cannot wait on any event as none should have been sent 890 SystemClock.sleep(MyAutofillCallback.MY_TIMEOUT.ms()); 891 callback.assertNumberUnhandledEvents(0); 892 893 // Autofill it. 894 mUiBot.selectDataset("The Dude"); 895 896 // Check the results. 897 mActivity.assertAutoFilled(); 898 } 899 900 @Test 901 @AppModeFull(reason = "testAutofillCallbacks() is enough") testAutofillCallbackDisabled()902 public void testAutofillCallbackDisabled() throws Exception { 903 // Set service. 904 disableService(); 905 906 final MyAutofillCallback callback = mActivity.registerCallback(); 907 908 // Trigger auto-fill. 909 mActivity.onUsername(View::requestFocus); 910 911 // Assert callback was called 912 final View username = mActivity.getUsername(); 913 callback.assertUiUnavailableEvent(username); 914 } 915 916 @Test 917 @AppModeFull(reason = "testAutofillCallbacks() is enough") testAutofillCallbackNoDatasets()918 public void testAutofillCallbackNoDatasets() throws Exception { 919 callbackUnavailableTest(NO_RESPONSE); 920 } 921 922 @Test 923 @AppModeFull(reason = "testAutofillCallbacks() is enough") testAutofillCallbackNoDatasetsButSaveInfo()924 public void testAutofillCallbackNoDatasetsButSaveInfo() throws Exception { 925 callbackUnavailableTest(new CannedFillResponse.Builder() 926 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 927 .build()); 928 } 929 callbackUnavailableTest(CannedFillResponse response)930 private void callbackUnavailableTest(CannedFillResponse response) throws Exception { 931 // Set service. 932 enableService(); 933 final MyAutofillCallback callback = mActivity.registerCallback(); 934 935 // Set expectations. 936 sReplier.addResponse(response); 937 938 // Trigger auto-fill. 939 mActivity.onUsername(View::requestFocus); 940 sReplier.getNextFillRequest(); 941 942 // Auto-fill it. 943 mUiBot.assertNoDatasetsEver(); 944 945 // Assert callback was called 946 final View username = mActivity.getUsername(); 947 callback.assertUiUnavailableEvent(username); 948 } 949 950 @Presubmit 951 @Test testAutoFillOneDatasetAndSave()952 public void testAutoFillOneDatasetAndSave() throws Exception { 953 // Set service. 954 enableService(); 955 956 // Set expectations. 957 final Bundle extras = new Bundle(); 958 extras.putString("numbers", "4815162342"); 959 960 sReplier.addResponse(new CannedFillResponse.Builder() 961 .addDataset(new CannedDataset.Builder() 962 .setId("I'm the alpha and the omega") 963 .setField(ID_USERNAME, "dude") 964 .setField(ID_PASSWORD, "sweet") 965 .setPresentation(createPresentation("The Dude")) 966 .build()) 967 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 968 .setExtras(extras) 969 .build()); 970 mActivity.expectAutoFill("dude", "sweet"); 971 972 // Trigger auto-fill. 973 requestFocusOnUsername(); 974 975 // Since this is a Presubmit test, wait for connection to avoid flakiness. 976 waitUntilConnected(); 977 978 final FillRequest fillRequest = sReplier.getNextFillRequest(); 979 980 // Make sure input was sanitized... 981 assertTextIsSanitized(fillRequest.structure, ID_USERNAME); 982 assertTextIsSanitized(fillRequest.structure, ID_PASSWORD); 983 984 // ...but labels weren't 985 assertTextOnly(fillRequest.structure, ID_USERNAME_LABEL, "Username"); 986 assertTextOnly(fillRequest.structure, ID_PASSWORD_LABEL, "Password"); 987 988 // Auto-fill it. 989 mUiBot.selectDataset("The Dude"); 990 991 // Check the results. 992 mActivity.assertAutoFilled(); 993 assertViewAutofillState(mActivity.getPassword(), true); 994 995 // Try to login, it will fail. 996 final String loginMessage = mActivity.tapLogin(); 997 998 assertWithMessage("Wrong login msg").that(loginMessage).isEqualTo(AUTHENTICATION_MESSAGE); 999 1000 // Set right password... 1001 mActivity.onPassword((v) -> v.setText("dude")); 1002 assertViewAutofillState(mActivity.getPassword(), false); 1003 1004 // ... and try again 1005 final String expectedMessage = getWelcomeMessage("dude"); 1006 final String actualMessage = mActivity.tapLogin(); 1007 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1008 1009 // Assert the snack bar is shown and tap "Save". 1010 mUiBot.updateForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1011 1012 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1013 1014 assertThat(saveRequest.datasetIds).containsExactly("I'm the alpha and the omega"); 1015 1016 // Assert value of expected fields - should not be sanitized. 1017 assertTextAndValue(saveRequest.structure, ID_USERNAME, "dude"); 1018 assertTextAndValue(saveRequest.structure, ID_PASSWORD, "dude"); 1019 assertTextOnly(saveRequest.structure, ID_USERNAME_LABEL, "Username"); 1020 assertTextOnly(saveRequest.structure, ID_PASSWORD_LABEL, "Password"); 1021 1022 // Make sure extras were passed back on onSave() 1023 assertThat(saveRequest.data).isNotNull(); 1024 final String extraValue = saveRequest.data.getString("numbers"); 1025 assertWithMessage("extras not passed on save").that(extraValue).isEqualTo("4815162342"); 1026 } 1027 1028 @Presubmit 1029 @Test testAutoFillOneDatasetAndSaveHidingOverlays()1030 public void testAutoFillOneDatasetAndSaveHidingOverlays() throws Exception { 1031 // Set service. 1032 enableService(); 1033 1034 // Set expectations. 1035 final Bundle extras = new Bundle(); 1036 extras.putString("numbers", "4815162342"); 1037 1038 sReplier.addResponse(new CannedFillResponse.Builder() 1039 .addDataset(new CannedDataset.Builder() 1040 .setField(ID_USERNAME, "dude") 1041 .setField(ID_PASSWORD, "sweet") 1042 .setPresentation(createPresentation("The Dude")) 1043 .build()) 1044 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1045 .setExtras(extras) 1046 .build()); 1047 mActivity.expectAutoFill("dude", "sweet"); 1048 1049 // Trigger auto-fill. 1050 requestFocusOnUsername(); 1051 1052 // Since this is a Presubmit test, wait for connection to avoid flakiness. 1053 waitUntilConnected(); 1054 1055 sReplier.getNextFillRequest(); 1056 1057 // Add an overlay on top of the whole screen 1058 final View[] overlay = new View[1]; 1059 try { 1060 // Allow ourselves to add overlays 1061 allowOverlays(); 1062 1063 // Make sure the fill UI is shown. 1064 mUiBot.assertDatasets("The Dude"); 1065 1066 final CountDownLatch latch = new CountDownLatch(1); 1067 1068 mActivity.runOnUiThread(() -> { 1069 // This overlay is focusable, full-screen, which should block interaction 1070 // with the fill UI unless the platform successfully hides overlays. 1071 final WindowManager.LayoutParams params = new WindowManager.LayoutParams(); 1072 params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 1073 params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 1074 params.width = ViewGroup.LayoutParams.MATCH_PARENT; 1075 params.height = ViewGroup.LayoutParams.MATCH_PARENT; 1076 1077 final View view = new View(mContext) { 1078 @Override 1079 protected void onAttachedToWindow() { 1080 super.onAttachedToWindow(); 1081 latch.countDown(); 1082 } 1083 }; 1084 view.setBackgroundColor(Color.RED); 1085 WindowManager windowManager = mContext.getSystemService(WindowManager.class); 1086 windowManager.addView(view, params); 1087 overlay[0] = view; 1088 }); 1089 1090 // Wait for the window being added. 1091 assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); 1092 1093 // Auto-fill it. 1094 mUiBot.selectDataset("The Dude"); 1095 1096 // Check the results. 1097 mActivity.assertAutoFilled(); 1098 1099 // Try to login, it will fail. 1100 final String loginMessage = mActivity.tapLogin(); 1101 1102 assertWithMessage("Wrong login msg").that(loginMessage).isEqualTo( 1103 AUTHENTICATION_MESSAGE); 1104 1105 // Set right password... 1106 mActivity.onPassword((v) -> v.setText("dude")); 1107 1108 // ... and try again 1109 final String expectedMessage = getWelcomeMessage("dude"); 1110 final String actualMessage = mActivity.tapLogin(); 1111 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1112 1113 // Assert the snack bar is shown and tap "Save". 1114 mUiBot.updateForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1115 1116 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1117 1118 // Assert value of expected fields - should not be sanitized. 1119 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 1120 assertTextAndValue(username, "dude"); 1121 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 1122 assertTextAndValue(password, "dude"); 1123 1124 // Make sure extras were passed back on onSave() 1125 assertThat(saveRequest.data).isNotNull(); 1126 final String extraValue = saveRequest.data.getString("numbers"); 1127 assertWithMessage("extras not passed on save").that(extraValue).isEqualTo("4815162342"); 1128 } finally { 1129 try { 1130 // Make sure we can no longer add overlays 1131 disallowOverlays(); 1132 // Make sure the overlay is removed 1133 mActivity.runOnUiThread(() -> { 1134 WindowManager windowManager = mContext.getSystemService(WindowManager.class); 1135 windowManager.removeView(overlay[0]); 1136 }); 1137 } catch (Exception e) { 1138 mSafeCleanerRule.add(e); 1139 } 1140 } 1141 } 1142 1143 @Test 1144 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillMultipleDatasetsPickFirst()1145 public void testAutoFillMultipleDatasetsPickFirst() throws Exception { 1146 multipleDatasetsTest(1); 1147 } 1148 1149 @Test 1150 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillMultipleDatasetsPickSecond()1151 public void testAutoFillMultipleDatasetsPickSecond() throws Exception { 1152 multipleDatasetsTest(2); 1153 } 1154 1155 @Test 1156 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutoFillMultipleDatasetsPickThird()1157 public void testAutoFillMultipleDatasetsPickThird() throws Exception { 1158 multipleDatasetsTest(3); 1159 } 1160 multipleDatasetsTest(int number)1161 private void multipleDatasetsTest(int number) throws Exception { 1162 // Set service. 1163 enableService(); 1164 1165 // Set expectations. 1166 sReplier.addResponse(new CannedFillResponse.Builder() 1167 .addDataset(new CannedDataset.Builder() 1168 .setField(ID_USERNAME, "mr_plow") 1169 .setField(ID_PASSWORD, "D'OH!") 1170 .setPresentation(createPresentation("Mr Plow")) 1171 .build()) 1172 .addDataset(new CannedDataset.Builder() 1173 .setField(ID_USERNAME, "el barto") 1174 .setField(ID_PASSWORD, "aycaramba!") 1175 .setPresentation(createPresentation("El Barto")) 1176 .build()) 1177 .addDataset(new CannedDataset.Builder() 1178 .setField(ID_USERNAME, "mr sparkle") 1179 .setField(ID_PASSWORD, "Aw3someP0wer") 1180 .setPresentation(createPresentation("Mr Sparkle")) 1181 .build()) 1182 .build()); 1183 final String name; 1184 1185 switch (number) { 1186 case 1: 1187 name = "Mr Plow"; 1188 mActivity.expectAutoFill("mr_plow", "D'OH!"); 1189 break; 1190 case 2: 1191 name = "El Barto"; 1192 mActivity.expectAutoFill("el barto", "aycaramba!"); 1193 break; 1194 case 3: 1195 name = "Mr Sparkle"; 1196 mActivity.expectAutoFill("mr sparkle", "Aw3someP0wer"); 1197 break; 1198 default: 1199 throw new IllegalArgumentException("invalid dataset number: " + number); 1200 } 1201 1202 // Trigger auto-fill. 1203 requestFocusOnUsername(); 1204 sReplier.getNextFillRequest(); 1205 1206 // Make sure all datasets are shown. 1207 final UiObject2 picker = mUiBot.assertDatasets("Mr Plow", "El Barto", "Mr Sparkle"); 1208 1209 // Auto-fill it. 1210 mUiBot.selectDataset(picker, name); 1211 1212 // Check the results. 1213 mActivity.assertAutoFilled(); 1214 } 1215 1216 /** 1217 * Tests the scenario where the service uses custom remote views for different fields (username 1218 * and password). 1219 */ 1220 @Presubmit 1221 @Test testAutofillOneDatasetCustomPresentation()1222 public void testAutofillOneDatasetCustomPresentation() throws Exception { 1223 // Set service. 1224 enableService(); 1225 1226 // Set expectations. 1227 sReplier.addResponse(new CannedDataset.Builder() 1228 .setField(ID_USERNAME, "dude", 1229 createPresentation("The Dude")) 1230 .setField(ID_PASSWORD, "sweet", 1231 createPresentation("Dude's password")) 1232 .build()); 1233 mActivity.expectAutoFill("dude", "sweet"); 1234 1235 // Trigger auto-fill. 1236 requestFocusOnUsername(); 1237 sReplier.getNextFillRequest(); 1238 1239 // Check initial field. 1240 mUiBot.assertDatasets("The Dude"); 1241 1242 // Then move around... 1243 requestFocusOnPassword(); 1244 mUiBot.assertDatasets("Dude's password"); 1245 requestFocusOnUsername(); 1246 mUiBot.assertDatasets("The Dude"); 1247 1248 // Auto-fill it. 1249 requestFocusOnPassword(); 1250 mUiBot.selectDataset("Dude's password"); 1251 1252 // Check the results. 1253 mActivity.assertAutoFilled(); 1254 } 1255 1256 /** 1257 * Tests the scenario where the service uses custom remote views for different fields (username 1258 * and password) and the dataset itself, and each dataset has the same number of fields. 1259 */ 1260 @Test 1261 @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough") testAutofillMultipleDatasetsCustomPresentations()1262 public void testAutofillMultipleDatasetsCustomPresentations() throws Exception { 1263 // Set service. 1264 enableService(); 1265 1266 // Set expectations. 1267 sReplier.addResponse(new CannedFillResponse.Builder() 1268 .addDataset(new CannedDataset.Builder(createPresentation("Dataset1")) 1269 .setField(ID_USERNAME, "user1") // no presentation 1270 .setField(ID_PASSWORD, "pass1", createPresentation("Pass1")) 1271 .build()) 1272 .addDataset(new CannedDataset.Builder() 1273 .setField(ID_USERNAME, "user2", createPresentation("User2")) 1274 .setField(ID_PASSWORD, "pass2") // no presentation 1275 .setPresentation(createPresentation("Dataset2")) 1276 .build()) 1277 .build()); 1278 mActivity.expectAutoFill("user1", "pass1"); 1279 1280 // Trigger auto-fill. 1281 requestFocusOnUsername(); 1282 sReplier.getNextFillRequest(); 1283 1284 // Check initial field. 1285 mUiBot.assertDatasets("Dataset1", "User2"); 1286 1287 // Then move around... 1288 requestFocusOnPassword(); 1289 mUiBot.assertDatasets("Pass1", "Dataset2"); 1290 requestFocusOnUsername(); 1291 mUiBot.assertDatasets("Dataset1", "User2"); 1292 1293 // Auto-fill it. 1294 requestFocusOnPassword(); 1295 mUiBot.selectDataset("Pass1"); 1296 1297 // Check the results. 1298 mActivity.assertAutoFilled(); 1299 } 1300 1301 /** 1302 * Tests the scenario where the service uses custom remote views for different fields (username 1303 * and password), and each dataset has the same number of fields. 1304 */ 1305 @Test 1306 @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough") testAutofillMultipleDatasetsCustomPresentationSameFields()1307 public void testAutofillMultipleDatasetsCustomPresentationSameFields() throws Exception { 1308 // Set service. 1309 enableService(); 1310 1311 // Set expectations. 1312 sReplier.addResponse(new CannedFillResponse.Builder() 1313 .addDataset(new CannedDataset.Builder() 1314 .setField(ID_USERNAME, "user1", createPresentation("User1")) 1315 .setField(ID_PASSWORD, "pass1", createPresentation("Pass1")) 1316 .build()) 1317 .addDataset(new CannedDataset.Builder() 1318 .setField(ID_USERNAME, "user2", createPresentation("User2")) 1319 .setField(ID_PASSWORD, "pass2", createPresentation("Pass2")) 1320 .build()) 1321 .build()); 1322 mActivity.expectAutoFill("user1", "pass1"); 1323 1324 // Trigger auto-fill. 1325 requestFocusOnUsername(); 1326 sReplier.getNextFillRequest(); 1327 1328 // Check initial field. 1329 mUiBot.assertDatasets("User1", "User2"); 1330 1331 // Then move around... 1332 requestFocusOnPassword(); 1333 mUiBot.assertDatasets("Pass1", "Pass2"); 1334 requestFocusOnUsername(); 1335 mUiBot.assertDatasets("User1", "User2"); 1336 1337 // Auto-fill it. 1338 requestFocusOnPassword(); 1339 mUiBot.selectDataset("Pass1"); 1340 1341 // Check the results. 1342 mActivity.assertAutoFilled(); 1343 } 1344 1345 /** 1346 * Tests the scenario where the service uses custom remote views for different fields (username 1347 * and password), but each dataset has a different number of fields. 1348 */ 1349 @Test 1350 @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough") testAutofillMultipleDatasetsCustomPresentationFirstDatasetMissingSecondField()1351 public void testAutofillMultipleDatasetsCustomPresentationFirstDatasetMissingSecondField() 1352 throws Exception { 1353 // Set service. 1354 enableService(); 1355 1356 // Set expectations. 1357 sReplier.addResponse(new CannedFillResponse.Builder() 1358 .addDataset(new CannedDataset.Builder() 1359 .setField(ID_USERNAME, "user1", createPresentation("User1")) 1360 .build()) 1361 .addDataset(new CannedDataset.Builder() 1362 .setField(ID_USERNAME, "user2", createPresentation("User2")) 1363 .setField(ID_PASSWORD, "pass2", createPresentation("Pass2")) 1364 .build()) 1365 .build()); 1366 mActivity.expectAutoFill("user2", "pass2"); 1367 1368 // Trigger auto-fill. 1369 requestFocusOnUsername(); 1370 sReplier.getNextFillRequest(); 1371 1372 // Check initial field. 1373 mUiBot.assertDatasets("User1", "User2"); 1374 1375 // Then move around... 1376 requestFocusOnPassword(); 1377 mUiBot.assertDatasets("Pass2"); 1378 requestFocusOnUsername(); 1379 mUiBot.assertDatasets("User1", "User2"); 1380 1381 // Auto-fill it. 1382 mUiBot.selectDataset("User2"); 1383 1384 // Check the results. 1385 mActivity.assertAutoFilled(); 1386 } 1387 1388 /** 1389 * Tests the scenario where the service uses custom remote views for different fields (username 1390 * and password), but each dataset has a different number of fields. 1391 */ 1392 @Test 1393 @AppModeFull(reason = "testAutofillOneDatasetCustomPresentation() is enough") testAutofillMultipleDatasetsCustomPresentationSecondDatasetMissingFirstField()1394 public void testAutofillMultipleDatasetsCustomPresentationSecondDatasetMissingFirstField() 1395 throws Exception { 1396 // Set service. 1397 enableService(); 1398 1399 // Set expectations. 1400 sReplier.addResponse(new CannedFillResponse.Builder() 1401 .addDataset(new CannedDataset.Builder() 1402 .setField(ID_USERNAME, "user1", createPresentation("User1")) 1403 .setField(ID_PASSWORD, "pass1", createPresentation("Pass1")) 1404 .build()) 1405 .addDataset(new CannedDataset.Builder() 1406 .setField(ID_PASSWORD, "pass2", createPresentation("Pass2")) 1407 .build()) 1408 .build()); 1409 mActivity.expectAutoFill("user1", "pass1"); 1410 1411 // Trigger auto-fill. 1412 requestFocusOnUsername(); 1413 sReplier.getNextFillRequest(); 1414 1415 // Check initial field. 1416 mUiBot.assertDatasets("User1"); 1417 1418 // Then move around... 1419 requestFocusOnPassword(); 1420 mUiBot.assertDatasets("Pass1", "Pass2"); 1421 requestFocusOnUsername(); 1422 mUiBot.assertDatasets("User1"); 1423 1424 // Auto-fill it. 1425 mUiBot.selectDataset("User1"); 1426 1427 // Check the results. 1428 mActivity.assertAutoFilled(); 1429 } 1430 1431 @Test 1432 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveOnly()1433 public void testSaveOnly() throws Exception { 1434 saveOnlyTest(false); 1435 } 1436 1437 @Test 1438 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveOnlyTriggeredManually()1439 public void testSaveOnlyTriggeredManually() throws Exception { 1440 saveOnlyTest(false); 1441 } 1442 saveOnlyTest(boolean manually)1443 private void saveOnlyTest(boolean manually) throws Exception { 1444 enableService(); 1445 1446 // Set expectations. 1447 sReplier.addResponse(new CannedFillResponse.Builder() 1448 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1449 .build()); 1450 1451 // Trigger auto-fill. 1452 if (manually) { 1453 mActivity.forceAutofillOnUsername(); 1454 } else { 1455 mActivity.onUsername(View::requestFocus); 1456 } 1457 1458 // Validation check. 1459 mUiBot.assertNoDatasetsEver(); 1460 1461 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1462 // the session started 1463 sReplier.getNextFillRequest(); 1464 1465 // Set credentials... 1466 mActivity.onUsername((v) -> v.setText("malkovich")); 1467 mActivity.onPassword((v) -> v.setText("malkovich")); 1468 1469 // ...and login 1470 final String expectedMessage = getWelcomeMessage("malkovich"); 1471 final String actualMessage = mActivity.tapLogin(); 1472 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1473 1474 // Assert the snack bar is shown and tap "Save". 1475 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1476 1477 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1478 sReplier.assertNoUnhandledSaveRequests(); 1479 assertThat(saveRequest.datasetIds).isNull(); 1480 1481 // Assert value of expected fields - should not be sanitized. 1482 try { 1483 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 1484 assertTextAndValue(username, "malkovich"); 1485 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 1486 assertTextAndValue(password, "malkovich"); 1487 } catch (AssertionError | RuntimeException e) { 1488 dumpStructure("saveOnlyTest() failed", saveRequest.structure); 1489 throw e; 1490 } 1491 } 1492 1493 @Test testSaveGoesAwayWhenTappingHomeButton()1494 public void testSaveGoesAwayWhenTappingHomeButton() throws Exception { 1495 saveGoesAway(DismissType.HOME_BUTTON); 1496 } 1497 1498 @Test testSaveGoesAwayWhenTappingBackButton()1499 public void testSaveGoesAwayWhenTappingBackButton() throws Exception { 1500 saveGoesAway(DismissType.BACK_BUTTON); 1501 } 1502 1503 @Test testSaveGoesAwayWhenTouchingOutside()1504 public void testSaveGoesAwayWhenTouchingOutside() throws Exception { 1505 saveGoesAway(DismissType.TOUCH_OUTSIDE); 1506 } 1507 saveGoesAway(DismissType dismissType)1508 private void saveGoesAway(DismissType dismissType) throws Exception { 1509 enableService(); 1510 1511 // Set expectations. 1512 sReplier.addResponse(new CannedFillResponse.Builder() 1513 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1514 .build()); 1515 1516 // Trigger auto-fill. 1517 mActivity.onUsername(View::requestFocus); 1518 1519 // Validation check. 1520 mUiBot.assertNoDatasetsEver(); 1521 1522 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1523 // the session started 1524 sReplier.getNextFillRequest(); 1525 1526 // Set credentials... 1527 mActivity.onUsername((v) -> v.setText("malkovich")); 1528 mActivity.onPassword((v) -> v.setText("malkovich")); 1529 1530 // ...and login 1531 final String expectedMessage = getWelcomeMessage("malkovich"); 1532 final String actualMessage = mActivity.tapLogin(); 1533 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1534 1535 // Assert the snack bar is shown and tap "Save". 1536 mUiBot.assertSaveShowing(SAVE_DATA_TYPE_PASSWORD); 1537 1538 // Then make sure it goes away when user doesn't want it.. 1539 switch (dismissType) { 1540 case BACK_BUTTON: 1541 mUiBot.pressBack(); 1542 break; 1543 case HOME_BUTTON: 1544 mUiBot.pressHome(); 1545 break; 1546 case TOUCH_OUTSIDE: 1547 mUiBot.touchOutsideSaveDialog(); 1548 break; 1549 default: 1550 throw new IllegalArgumentException("invalid dismiss type: " + dismissType); 1551 } 1552 mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD); 1553 } 1554 1555 @Test 1556 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveOnlyPreFilled()1557 public void testSaveOnlyPreFilled() throws Exception { 1558 saveOnlyTestPreFilled(false); 1559 } 1560 1561 @Test 1562 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveOnlyTriggeredManuallyPreFilled()1563 public void testSaveOnlyTriggeredManuallyPreFilled() throws Exception { 1564 saveOnlyTestPreFilled(true); 1565 } 1566 saveOnlyTestPreFilled(boolean manually)1567 private void saveOnlyTestPreFilled(boolean manually) throws Exception { 1568 enableService(); 1569 1570 // Set expectations. 1571 sReplier.addResponse(new CannedFillResponse.Builder() 1572 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1573 .build()); 1574 1575 // Set activity 1576 mActivity.onUsername((v) -> v.setText("user_before")); 1577 mActivity.onPassword((v) -> v.setText("pass_before")); 1578 1579 // Trigger auto-fill. 1580 if (manually) { 1581 // setText() will trigger a fill request. 1582 // Waits the first fill request triggered by the setText() is received by the service to 1583 // avoid flaky. 1584 sReplier.getNextFillRequest(); 1585 mUiBot.waitForIdle(); 1586 1587 // Set expectations again. 1588 sReplier.addResponse(new CannedFillResponse.Builder() 1589 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1590 .build()); 1591 mActivity.forceAutofillOnUsername(); 1592 } else { 1593 mUiBot.selectByRelativeId(ID_USERNAME); 1594 } 1595 mUiBot.waitForIdle(); 1596 1597 // Validation check. 1598 mUiBot.assertNoDatasetsEver(); 1599 1600 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1601 // the session started 1602 sReplier.getNextFillRequest(); 1603 1604 // Set credentials... 1605 mActivity.onUsername((v) -> v.setText("user_after")); 1606 mActivity.onPassword((v) -> v.setText("pass_after")); 1607 1608 // ...and login 1609 final String expectedMessage = getWelcomeMessage("user_after"); 1610 final String actualMessage = mActivity.tapLogin(); 1611 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1612 mUiBot.waitForIdle(); 1613 1614 // Assert the snack bar is shown and tap "Save". 1615 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1616 1617 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1618 sReplier.assertNoUnhandledSaveRequests(); 1619 1620 // Assert value of expected fields - should not be sanitized. 1621 try { 1622 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 1623 assertTextAndValue(username, "user_after"); 1624 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 1625 assertTextAndValue(password, "pass_after"); 1626 } catch (AssertionError | RuntimeException e) { 1627 dumpStructure("saveOnlyTest() failed", saveRequest.structure); 1628 throw e; 1629 } 1630 } 1631 1632 @Test 1633 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveOnlyTwoRequiredFieldsOnePrefilled()1634 public void testSaveOnlyTwoRequiredFieldsOnePrefilled() throws Exception { 1635 enableService(); 1636 1637 // Set expectations. 1638 sReplier.addResponse(new CannedFillResponse.Builder() 1639 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1640 .build()); 1641 1642 // Set activity 1643 mActivity.onUsername((v) -> v.setText("I_AM_USER")); 1644 1645 // Trigger auto-fill. 1646 mActivity.onPassword(View::requestFocus); 1647 1648 // Wait for onFill() before changing value, otherwise the fields might be changed before 1649 // the session started 1650 sReplier.getNextFillRequest(); 1651 mUiBot.assertNoDatasetsEver(); 1652 1653 // Set credentials... 1654 mActivity.onPassword((v) -> v.setText("thou should pass")); // contains pass 1655 1656 // ...and login 1657 final String expectedMessage = getWelcomeMessage("I_AM_USER"); // contains pass 1658 final String actualMessage = mActivity.tapLogin(); 1659 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1660 1661 // Assert the snack bar is shown and tap "Save". 1662 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1663 1664 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1665 sReplier.assertNoUnhandledSaveRequests(); 1666 1667 // Assert value of expected fields - should not be sanitized. 1668 try { 1669 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 1670 assertTextAndValue(username, "I_AM_USER"); 1671 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 1672 assertTextAndValue(password, "thou should pass"); 1673 } catch (AssertionError | RuntimeException e) { 1674 dumpStructure("saveOnlyTest() failed", saveRequest.structure); 1675 throw e; 1676 } 1677 } 1678 1679 @Test 1680 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveOnlyOptionalField()1681 public void testSaveOnlyOptionalField() throws Exception { 1682 enableService(); 1683 1684 // Set expectations. 1685 sReplier.addResponse(new CannedFillResponse.Builder() 1686 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME) 1687 .setOptionalSavableIds(ID_PASSWORD) 1688 .build()); 1689 1690 // Trigger auto-fill. 1691 mActivity.onUsername(View::requestFocus); 1692 1693 // Validation check. 1694 mUiBot.assertNoDatasetsEver(); 1695 1696 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1697 // the session started 1698 sReplier.getNextFillRequest(); 1699 1700 // Set credentials... 1701 mActivity.onUsername((v) -> v.setText("malkovich")); 1702 mActivity.onPassword(View::requestFocus); 1703 mActivity.onPassword((v) -> v.setText("malkovich")); 1704 1705 // ...and login 1706 final String expectedMessage = getWelcomeMessage("malkovich"); 1707 final String actualMessage = mActivity.tapLogin(); 1708 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1709 1710 // Assert the snack bar is shown and tap "Save". 1711 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1712 1713 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1714 1715 // Assert value of expected fields - should not be sanitized. 1716 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 1717 assertTextAndValue(username, "malkovich"); 1718 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 1719 assertTextAndValue(password, "malkovich"); 1720 } 1721 1722 @Test 1723 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveNoRequiredField_NoneFilled()1724 public void testSaveNoRequiredField_NoneFilled() throws Exception { 1725 optionalOnlyTest(FilledFields.NONE); 1726 } 1727 1728 @Test 1729 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveNoRequiredField_OneFilled()1730 public void testSaveNoRequiredField_OneFilled() throws Exception { 1731 optionalOnlyTest(FilledFields.USERNAME_ONLY); 1732 } 1733 1734 @Test 1735 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testSaveNoRequiredField_BothFilled()1736 public void testSaveNoRequiredField_BothFilled() throws Exception { 1737 optionalOnlyTest(FilledFields.BOTH); 1738 } 1739 1740 enum FilledFields { 1741 NONE, 1742 USERNAME_ONLY, 1743 BOTH 1744 } 1745 optionalOnlyTest(FilledFields filledFields)1746 private void optionalOnlyTest(FilledFields filledFields) throws Exception { 1747 enableService(); 1748 1749 // Set expectations. 1750 sReplier.addResponse(new CannedFillResponse.Builder() 1751 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD) 1752 .setOptionalSavableIds(ID_USERNAME, ID_PASSWORD) 1753 .build()); 1754 1755 // Trigger auto-fill. 1756 mActivity.onUsername(View::requestFocus); 1757 1758 // Validation check. 1759 mUiBot.assertNoDatasetsEver(); 1760 1761 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1762 // the session started 1763 sReplier.getNextFillRequest(); 1764 1765 // Set credentials... 1766 final String expectedUsername; 1767 if (filledFields == FilledFields.USERNAME_ONLY || filledFields == FilledFields.BOTH) { 1768 expectedUsername = BACKDOOR_USERNAME; 1769 mActivity.onUsername((v) -> v.setText(BACKDOOR_USERNAME)); 1770 } else { 1771 expectedUsername = ""; 1772 } 1773 mActivity.onPassword(View::requestFocus); 1774 if (filledFields == FilledFields.BOTH) { 1775 mActivity.onPassword((v) -> v.setText("whatever")); 1776 } 1777 1778 // ...and login 1779 final String expectedMessage = getWelcomeMessage(expectedUsername); 1780 final String actualMessage = mActivity.tapLogin(); 1781 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1782 1783 if (filledFields == FilledFields.NONE) { 1784 mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD); 1785 return; 1786 } 1787 1788 // Assert the snack bar is shown and tap "Save". 1789 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 1790 1791 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 1792 1793 // Assert value of expected fields - should not be sanitized. 1794 final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME); 1795 assertTextAndValue(username, BACKDOOR_USERNAME); 1796 1797 if (filledFields == FilledFields.BOTH) { 1798 final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD); 1799 assertTextAndValue(password, "whatever"); 1800 } 1801 } 1802 1803 @Test 1804 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testGenericSave()1805 public void testGenericSave() throws Exception { 1806 customizedSaveTest(SAVE_DATA_TYPE_GENERIC); 1807 } 1808 1809 @Test 1810 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSavePassword()1811 public void testCustomizedSavePassword() throws Exception { 1812 customizedSaveTest(SAVE_DATA_TYPE_PASSWORD); 1813 } 1814 1815 @Test 1816 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveAddress()1817 public void testCustomizedSaveAddress() throws Exception { 1818 customizedSaveTest(SAVE_DATA_TYPE_ADDRESS); 1819 } 1820 1821 @Test 1822 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveCreditCard()1823 public void testCustomizedSaveCreditCard() throws Exception { 1824 customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD); 1825 } 1826 1827 @Test 1828 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveUsername()1829 public void testCustomizedSaveUsername() throws Exception { 1830 customizedSaveTest(SAVE_DATA_TYPE_USERNAME); 1831 } 1832 1833 @Test 1834 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveEmailAddress()1835 public void testCustomizedSaveEmailAddress() throws Exception { 1836 customizedSaveTest(SAVE_DATA_TYPE_EMAIL_ADDRESS); 1837 } 1838 1839 @Test 1840 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveDebitCard()1841 public void testCustomizedSaveDebitCard() throws Exception { 1842 customizedSaveTest(SAVE_DATA_TYPE_DEBIT_CARD); 1843 } 1844 1845 @Test 1846 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSavePaymentCard()1847 public void testCustomizedSavePaymentCard() throws Exception { 1848 customizedSaveTest(SAVE_DATA_TYPE_PAYMENT_CARD); 1849 } 1850 1851 @Test 1852 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveGenericCard()1853 public void testCustomizedSaveGenericCard() throws Exception { 1854 customizedSaveTest(SAVE_DATA_TYPE_GENERIC_CARD); 1855 } 1856 1857 @Test 1858 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveTwoCardTypes()1859 public void testCustomizedSaveTwoCardTypes() throws Exception { 1860 customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD | SAVE_DATA_TYPE_DEBIT_CARD, 1861 SAVE_DATA_TYPE_GENERIC_CARD); 1862 } 1863 1864 @Test 1865 @AppModeFull(reason = "testAutoFillOneDatasetAndSave() is enough") testCustomizedSaveThreeCardTypes()1866 public void testCustomizedSaveThreeCardTypes() throws Exception { 1867 customizedSaveTest(SAVE_DATA_TYPE_CREDIT_CARD | SAVE_DATA_TYPE_DEBIT_CARD 1868 | SAVE_DATA_TYPE_PAYMENT_CARD, SAVE_DATA_TYPE_GENERIC_CARD); 1869 } 1870 customizedSaveTest(int type)1871 private void customizedSaveTest(int type) throws Exception { 1872 customizedSaveTest(type, type); 1873 } 1874 customizedSaveTest(int type, int expectedType)1875 private void customizedSaveTest(int type, int expectedType) throws Exception { 1876 // Set service. 1877 enableService(); 1878 1879 // Set expectations. 1880 final String saveDescription = "Your data will be saved with love and care..."; 1881 sReplier.addResponse(new CannedFillResponse.Builder() 1882 .setRequiredSavableIds(type, ID_USERNAME, ID_PASSWORD) 1883 .setSaveDescription(saveDescription) 1884 .build()); 1885 1886 // Trigger auto-fill. 1887 mActivity.onUsername(View::requestFocus); 1888 1889 // Validation check. 1890 mUiBot.assertNoDatasetsEver(); 1891 1892 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1893 // the session started. 1894 sReplier.getNextFillRequest(); 1895 1896 // Set credentials... 1897 mActivity.onUsername((v) -> v.setText("malkovich")); 1898 mActivity.onPassword((v) -> v.setText("malkovich")); 1899 1900 // ...and login 1901 final String expectedMessage = getWelcomeMessage("malkovich"); 1902 final String actualMessage = mActivity.tapLogin(); 1903 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1904 1905 // Assert the snack bar is shown and tap "Save". 1906 final UiObject2 saveSnackBar = mUiBot.assertSaveShowing(saveDescription, expectedType); 1907 mUiBot.saveForAutofill(saveSnackBar, true); 1908 1909 // Assert save was called. 1910 sReplier.getNextSaveRequest(); 1911 } 1912 1913 @Presubmit 1914 @Test testDontTriggerSaveOnFinishWhenRequestedByFlag()1915 public void testDontTriggerSaveOnFinishWhenRequestedByFlag() throws Exception { 1916 enableService(); 1917 1918 // Set expectations. 1919 sReplier.addResponse(new CannedFillResponse.Builder() 1920 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 1921 .setSaveInfoFlags(SaveInfo.FLAG_DONT_SAVE_ON_FINISH) 1922 .build()); 1923 1924 // Trigger auto-fill. 1925 mActivity.onUsername(View::requestFocus); 1926 1927 // Validation check. 1928 mUiBot.assertNoDatasetsEver(); 1929 1930 // Wait for onFill() before proceeding, otherwise the fields might be changed before 1931 // the session started 1932 sReplier.getNextFillRequest(); 1933 1934 // Set credentials... 1935 mActivity.onUsername((v) -> v.setText("malkovich")); 1936 mActivity.onPassword((v) -> v.setText("malkovich")); 1937 1938 // ...and login 1939 final String expectedMessage = getWelcomeMessage("malkovich"); 1940 final String actualMessage = mActivity.tapLogin(); 1941 assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage); 1942 1943 // Make sure it didn't trigger save. 1944 mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD); 1945 } 1946 1947 @Presubmit 1948 @Test testAutoFillOneDatasetAndSaveWhenFlagSecure()1949 public void testAutoFillOneDatasetAndSaveWhenFlagSecure() throws Exception { 1950 mActivity.setFlags(FLAG_SECURE); 1951 testAutoFillOneDatasetAndSave(); 1952 } 1953 1954 @Test testAutoFillOneDatasetWhenFlagSecure()1955 public void testAutoFillOneDatasetWhenFlagSecure() throws Exception { 1956 mActivity.setFlags(FLAG_SECURE); 1957 testAutoFillOneDataset(); 1958 } 1959 1960 @Presubmit 1961 @Test 1962 @AppModeFull(reason = "Service-specific test") testDisableSelf()1963 public void testDisableSelf() throws Exception { 1964 enableService(); 1965 1966 // Can disable while connected. 1967 mActivity.runOnUiThread(() -> mContext.getSystemService( 1968 AutofillManager.class).disableAutofillServices()); 1969 1970 // Ensure disabled. 1971 assertServiceDisabled(); 1972 } 1973 1974 @Presubmit 1975 @Test testNeverRejectStyleNegativeSaveButton()1976 public void testNeverRejectStyleNegativeSaveButton() throws Exception { 1977 negativeSaveButtonStyle(SaveInfo.NEGATIVE_BUTTON_STYLE_NEVER); 1978 } 1979 1980 @Presubmit 1981 @Test testRejectStyleNegativeSaveButton()1982 public void testRejectStyleNegativeSaveButton() throws Exception { 1983 negativeSaveButtonStyle(SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT); 1984 } 1985 1986 @Test testCancelStyleNegativeSaveButton()1987 public void testCancelStyleNegativeSaveButton() throws Exception { 1988 negativeSaveButtonStyle(SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL); 1989 } 1990 negativeSaveButtonStyle(int style)1991 private void negativeSaveButtonStyle(int style) throws Exception { 1992 enableService(); 1993 1994 // Set service behavior. 1995 1996 final String intentAction = "android.autofillservice.cts.CUSTOM_ACTION"; 1997 1998 // Configure the save UI. 1999 final IntentSender listener = PendingIntent.getBroadcast(mContext, 0, 2000 new Intent(intentAction), PendingIntent.FLAG_IMMUTABLE).getIntentSender(); 2001 2002 sReplier.addResponse(new CannedFillResponse.Builder() 2003 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 2004 .setNegativeAction(style, listener) 2005 .build()); 2006 2007 // Trigger auto-fill. 2008 mActivity.onUsername(View::requestFocus); 2009 2010 // Wait for onFill() before proceeding. 2011 sReplier.getNextFillRequest(); 2012 2013 // Trigger save. 2014 mActivity.onUsername((v) -> v.setText("foo")); 2015 mActivity.onPassword((v) -> v.setText("foo")); 2016 mActivity.tapLogin(); 2017 2018 // Start watching for the negative intent 2019 final CountDownLatch latch = new CountDownLatch(1); 2020 final IntentFilter intentFilter = new IntentFilter(intentAction); 2021 mContext.registerReceiver(new BroadcastReceiver() { 2022 @Override 2023 public void onReceive(Context context, Intent intent) { 2024 mContext.unregisterReceiver(this); 2025 latch.countDown(); 2026 } 2027 }, intentFilter, Context.RECEIVER_NOT_EXPORTED); 2028 2029 // Trigger the negative button. 2030 mUiBot.saveForAutofill(style, /* yesDoIt= */ false, SAVE_DATA_TYPE_PASSWORD); 2031 2032 // Wait for the custom action. 2033 assertThat(latch.await(5, TimeUnit.SECONDS)).isTrue(); 2034 } 2035 2036 @Presubmit 2037 @Test testContinueStylePositiveSaveButton()2038 public void testContinueStylePositiveSaveButton() throws Exception { 2039 enableService(); 2040 2041 // Set service behavior. 2042 sReplier.addResponse(new CannedFillResponse.Builder() 2043 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 2044 .setPositiveAction(SaveInfo.POSITIVE_BUTTON_STYLE_CONTINUE) 2045 .build()); 2046 2047 // Trigger auto-fill. 2048 mActivity.onUsername(View::requestFocus); 2049 2050 // Wait for onFill() before proceeding. 2051 sReplier.getNextFillRequest(); 2052 2053 // Trigger save. 2054 mActivity.onUsername((v) -> v.setText("foo")); 2055 mActivity.onPassword((v) -> v.setText("foo")); 2056 mActivity.tapLogin(); 2057 2058 // Start watching for the negative intent 2059 // Trigger the negative button. 2060 mUiBot.saveForAutofill(SaveInfo.POSITIVE_BUTTON_STYLE_CONTINUE, SAVE_DATA_TYPE_PASSWORD); 2061 2062 // Assert save was called. 2063 sReplier.getNextSaveRequest(); 2064 } 2065 2066 @Test 2067 @AppModeFull(reason = "Unit test") testGetTextInputType()2068 public void testGetTextInputType() throws Exception { 2069 // Set service. 2070 enableService(); 2071 2072 // Set expectations. 2073 sReplier.addResponse(NO_RESPONSE); 2074 2075 // Trigger auto-fill. 2076 mActivity.onUsername(View::requestFocus); 2077 2078 // Assert input text on fill request: 2079 final FillRequest fillRequest = sReplier.getNextFillRequest(); 2080 2081 final ViewNode label = findNodeByResourceId(fillRequest.structure, ID_PASSWORD_LABEL); 2082 assertThat(label.getInputType()).isEqualTo(TYPE_NULL); 2083 final ViewNode password = findNodeByResourceId(fillRequest.structure, ID_PASSWORD); 2084 assertWithMessage("No TYPE_TEXT_VARIATION_PASSWORD on %s", password.getInputType()) 2085 .that(password.getInputType() & TYPE_TEXT_VARIATION_PASSWORD) 2086 .isEqualTo(TYPE_TEXT_VARIATION_PASSWORD); 2087 } 2088 2089 @Test 2090 @AppModeFull(reason = "Unit test") testNoContainers()2091 public void testNoContainers() throws Exception { 2092 // Set service. 2093 enableService(); 2094 2095 // Set expectations. 2096 sReplier.addResponse(NO_RESPONSE); 2097 2098 // Trigger auto-fill. 2099 mActivity.onUsername(View::requestFocus); 2100 2101 mUiBot.assertNoDatasetsEver(); 2102 2103 final FillRequest fillRequest = sReplier.getNextFillRequest(); 2104 2105 // Assert it only has 1 root view with 10 "leaf" nodes: 2106 // 1.text view for app title 2107 // 2.username text label 2108 // 3.username text field 2109 // 4.password text label 2110 // 5.password text field 2111 // 6.output text field 2112 // 7.clear button 2113 // 8.save button 2114 // 9.login button 2115 // 10.cancel button 2116 // 2117 // But it also has an intermediate container (for username) that should be included because 2118 // it has a resource id. 2119 2120 // get activity title 2121 final CharSequence activityTitle = mActivity.getPackageName() + "/" 2122 + getActivityTitle(InstrumentationRegistry.getInstrumentation(), mActivity); 2123 assertNumberOfChildrenWithWindowTitle(fillRequest.structure, 12, activityTitle); 2124 2125 // Make sure container with a resource id was included: 2126 final ViewNode usernameContainer = findNodeByResourceId(fillRequest.structure, 2127 ID_USERNAME_CONTAINER); 2128 assertThat(usernameContainer).isNotNull(); 2129 assertThat(usernameContainer.getChildCount()).isEqualTo(2); 2130 } 2131 2132 @Presubmit 2133 @Test testAutofillManuallyOneDataset()2134 public void testAutofillManuallyOneDataset() throws Exception { 2135 // Set service. 2136 enableService(); 2137 2138 // And activity. 2139 mActivity.onUsername((v) -> v.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO)); 2140 // Set expectations. 2141 sReplier.addResponse(new CannedDataset.Builder() 2142 .setField(ID_USERNAME, "dude") 2143 .setField(ID_PASSWORD, "sweet") 2144 .setPresentation(createPresentation("The Dude")) 2145 .build()); 2146 mActivity.expectAutoFill("dude", "sweet"); 2147 2148 // Explicitly uses the contextual menu to test that functionality. 2149 mUiBot.getAutofillMenuOption(ID_USERNAME).click(); 2150 2151 final FillRequest fillRequest = sReplier.getNextFillRequest(); 2152 assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST); 2153 2154 // Should have been automatically filled. 2155 mUiBot.selectDataset("The Dude"); 2156 2157 // Check the results. 2158 mActivity.assertAutoFilled(); 2159 } 2160 2161 @Test 2162 @AppModeFull(reason = "testAutoFillOneDataset() is enough") testAutofillManuallyOneDatasetWhenClipboardFull()2163 public void testAutofillManuallyOneDatasetWhenClipboardFull() throws Exception { 2164 // Set service. 2165 enableService(); 2166 2167 // Set clipboard. 2168 ClipboardManager cm = (ClipboardManager) mActivity.getSystemService(CLIPBOARD_SERVICE); 2169 cm.setPrimaryClip(ClipData.newPlainText(null, "test")); 2170 2171 // And activity. 2172 mActivity.onUsername((v) -> v.setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO)); 2173 2174 // Set expectations. 2175 sReplier.addResponse(new CannedDataset.Builder() 2176 .setField(ID_USERNAME, "dude") 2177 .setField(ID_PASSWORD, "sweet") 2178 .setPresentation(createPresentation("The Dude")) 2179 .build()); 2180 mActivity.expectAutoFill("dude", "sweet"); 2181 2182 // Explicitly uses the contextual menu to test that functionality. 2183 mUiBot.getAutofillMenuOption(ID_USERNAME).click(); 2184 2185 final FillRequest fillRequest = sReplier.getNextFillRequest(); 2186 assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST); 2187 2188 // Should have been automatically filled. 2189 mUiBot.selectDataset("The Dude"); 2190 2191 // Check the results. 2192 mActivity.assertAutoFilled(); 2193 2194 // clear clipboard 2195 cm.clearPrimaryClip(); 2196 } 2197 2198 @Test 2199 @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough") testAutofillManuallyTwoDatasetsPickFirst()2200 public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception { 2201 autofillManuallyTwoDatasets(true); 2202 } 2203 2204 @Test 2205 @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough") testAutofillManuallyTwoDatasetsPickSecond()2206 public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception { 2207 autofillManuallyTwoDatasets(false); 2208 } 2209 autofillManuallyTwoDatasets(boolean pickFirst)2210 private void autofillManuallyTwoDatasets(boolean pickFirst) throws Exception { 2211 // Set service. 2212 enableService(); 2213 2214 // Set expectations. 2215 sReplier.addResponse(new CannedFillResponse.Builder() 2216 .addDataset(new CannedDataset.Builder() 2217 .setField(ID_USERNAME, "dude") 2218 .setField(ID_PASSWORD, "sweet") 2219 .setPresentation(createPresentation("The Dude")) 2220 .build()) 2221 .addDataset(new CannedDataset.Builder() 2222 .setField(ID_USERNAME, "jenny") 2223 .setField(ID_PASSWORD, "8675309") 2224 .setPresentation(createPresentation("Jenny")) 2225 .build()) 2226 .build()); 2227 if (pickFirst) { 2228 mActivity.expectAutoFill("dude", "sweet"); 2229 } else { 2230 mActivity.expectAutoFill("jenny", "8675309"); 2231 2232 } 2233 2234 // Force a manual autofill request. 2235 mActivity.forceAutofillOnUsername(); 2236 2237 final FillRequest fillRequest = sReplier.getNextFillRequest(); 2238 assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST); 2239 2240 // Auto-fill it. 2241 final UiObject2 picker = mUiBot.assertDatasets("The Dude", "Jenny"); 2242 mUiBot.selectDataset(picker, pickFirst ? "The Dude" : "Jenny"); 2243 2244 // Check the results. 2245 mActivity.assertAutoFilled(); 2246 } 2247 2248 @Test 2249 @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough") testAutofillManuallyPartialField()2250 public void testAutofillManuallyPartialField() throws Exception { 2251 // Set service. 2252 enableService(); 2253 2254 sReplier.addResponse(NO_RESPONSE); 2255 // And activity. 2256 mActivity.onUsername((v) -> v.setText("dud")); 2257 mActivity.onPassword((v) -> v.setText("IamSecretMan")); 2258 2259 // setText() will trigger a fill request. 2260 // Waits the first fill request triggered by the setText() is received by the service to 2261 // avoid flaky. 2262 sReplier.getNextFillRequest(); 2263 mUiBot.waitForIdle(); 2264 2265 // Set expectations. 2266 sReplier.addResponse(new CannedDataset.Builder() 2267 .setField(ID_USERNAME, "dude") 2268 .setField(ID_PASSWORD, "sweet") 2269 .setPresentation(createPresentation("The Dude")) 2270 .build()); 2271 mActivity.expectAutoFill("dude", "sweet"); 2272 2273 // Force a manual autofill request. 2274 mActivity.forceAutofillOnUsername(); 2275 2276 final FillRequest fillRequest = sReplier.getNextFillRequest(); 2277 assertHasFlags(fillRequest.flags, FLAG_MANUAL_REQUEST); 2278 // Username value should be available because it triggered the manual request... 2279 assertValue(fillRequest.structure, ID_USERNAME, "dud"); 2280 // ... but password didn't 2281 assertTextIsSanitized(fillRequest.structure, ID_PASSWORD); 2282 2283 // Selects the dataset. 2284 mUiBot.selectDataset("The Dude"); 2285 2286 // Check the results. 2287 mActivity.assertAutoFilled(); 2288 } 2289 2290 @Test 2291 @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough") testAutofillManuallyAgainAfterAutomaticallyAutofilledBefore()2292 public void testAutofillManuallyAgainAfterAutomaticallyAutofilledBefore() throws Exception { 2293 // Set service. 2294 enableService(); 2295 2296 /* 2297 * 1st fill (automatic). 2298 */ 2299 // Set expectations. 2300 sReplier.addResponse(new CannedDataset.Builder() 2301 .setField(ID_USERNAME, "dude") 2302 .setField(ID_PASSWORD, "sweet") 2303 .setPresentation(createPresentation("The Dude")) 2304 .build()); 2305 mActivity.expectAutoFill("dude", "sweet"); 2306 2307 // Trigger auto-fill. 2308 requestFocusOnUsername(); 2309 2310 // Assert request. 2311 final FillRequest fillRequest1 = sReplier.getNextFillRequest(); 2312 assertThat(fillRequest1.flags).isEqualTo(0); 2313 assertTextIsSanitized(fillRequest1.structure, ID_USERNAME); 2314 assertTextIsSanitized(fillRequest1.structure, ID_PASSWORD); 2315 2316 // Select it. 2317 mUiBot.selectDataset("The Dude"); 2318 2319 // Check the results. 2320 mActivity.assertAutoFilled(); 2321 2322 /* 2323 * 2nd fill (manual). 2324 */ 2325 // Set expectations. 2326 sReplier.addResponse(new CannedDataset.Builder() 2327 .setField(ID_USERNAME, "DUDE") 2328 .setField(ID_PASSWORD, "SWEET") 2329 .setPresentation(createPresentation("THE DUDE")) 2330 .build()); 2331 mActivity.expectAutoFill("DUDE", "SWEET"); 2332 // Change password to make sure it's not sent to the service. 2333 mActivity.onPassword((v) -> v.setText("IamSecretMan")); 2334 2335 // Trigger auto-fill. 2336 mActivity.forceAutofillOnUsername(); 2337 2338 // Assert request. 2339 final FillRequest fillRequest2 = sReplier.getNextFillRequest(); 2340 assertHasFlags(fillRequest2.flags, FLAG_MANUAL_REQUEST); 2341 assertValue(fillRequest2.structure, ID_USERNAME, "dude"); 2342 assertTextIsSanitized(fillRequest2.structure, ID_PASSWORD); 2343 2344 // Select it. 2345 mUiBot.selectDataset("THE DUDE"); 2346 2347 // Check the results. 2348 mActivity.assertAutoFilled(); 2349 } 2350 2351 @Test 2352 @AppModeFull(reason = "testAutofillManuallyOneDataset() is enough") testAutofillManuallyAgainAfterManuallyAutofilledBefore()2353 public void testAutofillManuallyAgainAfterManuallyAutofilledBefore() throws Exception { 2354 // Set service. 2355 enableService(); 2356 2357 /* 2358 * 1st fill (manual). 2359 */ 2360 // Set expectations. 2361 sReplier.addResponse(new CannedDataset.Builder() 2362 .setField(ID_USERNAME, "dude") 2363 .setField(ID_PASSWORD, "sweet") 2364 .setPresentation(createPresentation("The Dude")) 2365 .build()); 2366 mActivity.expectAutoFill("dude", "sweet"); 2367 2368 // Trigger auto-fill. 2369 mActivity.forceAutofillOnUsername(); 2370 2371 // Assert request. 2372 final FillRequest fillRequest1 = sReplier.getNextFillRequest(); 2373 assertHasFlags(fillRequest1.flags, FLAG_MANUAL_REQUEST); 2374 assertValue(fillRequest1.structure, ID_USERNAME, ""); 2375 assertTextIsSanitized(fillRequest1.structure, ID_PASSWORD); 2376 2377 // Select it. 2378 mUiBot.selectDataset("The Dude"); 2379 2380 // Check the results. 2381 mActivity.assertAutoFilled(); 2382 2383 /* 2384 * 2nd fill (manual). 2385 */ 2386 // Set expectations. 2387 sReplier.addResponse(new CannedDataset.Builder() 2388 .setField(ID_USERNAME, "DUDE") 2389 .setField(ID_PASSWORD, "SWEET") 2390 .setPresentation(createPresentation("THE DUDE")) 2391 .build()); 2392 mActivity.expectAutoFill("DUDE", "SWEET"); 2393 // Change password to make sure it's not sent to the service. 2394 mActivity.onPassword((v) -> v.setText("IamSecretMan")); 2395 2396 // Trigger auto-fill. 2397 mActivity.forceAutofillOnUsername(); 2398 2399 // Assert request. 2400 final FillRequest fillRequest2 = sReplier.getNextFillRequest(); 2401 assertHasFlags(fillRequest2.flags, FLAG_MANUAL_REQUEST); 2402 assertValue(fillRequest2.structure, ID_USERNAME, "dude"); 2403 assertTextIsSanitized(fillRequest2.structure, ID_PASSWORD); 2404 2405 // Select it. 2406 mUiBot.selectDataset("THE DUDE"); 2407 2408 // Check the results. 2409 mActivity.assertAutoFilled(); 2410 } 2411 2412 @FlakyTest(bugId = 162372863) // Re-add @Presubmit after fixing. 2413 @Test testCommitMultipleTimes()2414 public void testCommitMultipleTimes() throws Throwable { 2415 // Set service. 2416 enableService(); 2417 2418 final CannedFillResponse response = new CannedFillResponse.Builder() 2419 .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD) 2420 .build(); 2421 2422 for (int i = 1; i <= 10; i++) { 2423 Log.i(TAG, "testCommitMultipleTimes(): step " + i); 2424 final String username = "user-" + i; 2425 final String password = "pass-" + i; 2426 try { 2427 // Set expectations. 2428 sReplier.addResponse(response); 2429 2430 Timeouts.IDLE_UNBIND_TIMEOUT.run("wait for session created", () -> { 2431 // Trigger auto-fill. 2432 mActivity.onUsername(View::clearFocus); 2433 mActivity.onUsername(View::requestFocus); 2434 2435 return isConnected() ? "not_used" : null; 2436 }); 2437 2438 sReplier.getNextFillRequest(); 2439 2440 // Validation check. 2441 mUiBot.assertNoDatasetsEver(); 2442 2443 // Set credentials... 2444 mActivity.onUsername((v) -> v.setText(username)); 2445 mActivity.onPassword((v) -> v.setText(password)); 2446 2447 // Change focus to prepare for next step - must do it before session is gone 2448 mActivity.onPassword(View::requestFocus); 2449 2450 // ...and save them 2451 mActivity.tapSave(); 2452 2453 // Assert the snack bar is shown and tap "Save". 2454 mUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD); 2455 2456 final SaveRequest saveRequest = sReplier.getNextSaveRequest(); 2457 2458 // Assert value of expected fields - should not be sanitized. 2459 final ViewNode usernameNode = findNodeByResourceId(saveRequest.structure, 2460 ID_USERNAME); 2461 assertTextAndValue(usernameNode, username); 2462 final ViewNode passwordNode = findNodeByResourceId(saveRequest.structure, 2463 ID_PASSWORD); 2464 assertTextAndValue(passwordNode, password); 2465 2466 waitUntilDisconnected(); 2467 2468 // Wait and check if the save window is correctly hidden. 2469 mUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_PASSWORD); 2470 } catch (RetryableException e) { 2471 throw new RetryableException(e, "on step %d", i); 2472 } catch (Throwable t) { 2473 throw new Throwable("Error on step " + i, t); 2474 } 2475 } 2476 } 2477 2478 @Presubmit 2479 @Test testCancelMultipleTimes()2480 public void testCancelMultipleTimes() throws Throwable { 2481 // Set service. 2482 enableService(); 2483 2484 for (int i = 1; i <= 10; i++) { 2485 Log.i(TAG, "testCancelMultipleTimes(): step " + i); 2486 final String username = "user-" + i; 2487 final String password = "pass-" + i; 2488 sReplier.addResponse(new CannedDataset.Builder() 2489 .setField(ID_USERNAME, username) 2490 .setField(ID_PASSWORD, password) 2491 .setPresentation(createPresentation("The Dude")) 2492 .build()); 2493 mActivity.expectAutoFill(username, password); 2494 try { 2495 // Trigger auto-fill. 2496 requestFocusOnUsername(); 2497 2498 waitUntilConnected(); 2499 sReplier.getNextFillRequest(); 2500 2501 // Auto-fill it. 2502 mUiBot.selectDataset("The Dude"); 2503 2504 // Check the results. 2505 mActivity.assertAutoFilled(); 2506 2507 // Change focus to prepare for next step - must do it before session is gone 2508 requestFocusOnPassword(); 2509 2510 // Rinse and repeat... 2511 mActivity.tapClear(); 2512 2513 waitUntilDisconnected(); 2514 } catch (RetryableException e) { 2515 throw e; 2516 } catch (Throwable t) { 2517 throw new Throwable("Error on step " + i, t); 2518 } 2519 } 2520 } 2521 2522 @Presubmit 2523 @Test testClickCustomButton()2524 public void testClickCustomButton() throws Exception { 2525 // Set service. 2526 enableService(); 2527 2528 Intent intent = new Intent(mContext, EmptyActivity.class); 2529 IntentSender sender = PendingIntent.getActivity(mContext, 0, intent, 2530 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT 2531 | PendingIntent.FLAG_IMMUTABLE).getIntentSender(); 2532 2533 RemoteViews presentation = new RemoteViews(mPackageName, R.layout.list_item); 2534 presentation.setTextViewText(R.id.text1, "Poke"); 2535 Intent firstIntent = new Intent(mContext, DummyActivity.class); 2536 presentation.setOnClickPendingIntent(R.id.text1, PendingIntent.getActivity( 2537 mContext, 0, firstIntent, PendingIntent.FLAG_ONE_SHOT 2538 | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE)); 2539 2540 // Set expectations. 2541 sReplier.addResponse(new CannedFillResponse.Builder() 2542 .setAuthentication(sender, ID_USERNAME) 2543 .setPresentation(presentation) 2544 .build()); 2545 2546 // Trigger auto-fill. 2547 requestFocusOnUsername(); 2548 2549 // Wait for onFill() before proceeding. 2550 sReplier.getNextFillRequest(); 2551 2552 // Click on the custom button 2553 mUiBot.selectByText("Poke"); 2554 2555 // Make sure the click worked 2556 mUiBot.selectByText("foo"); 2557 2558 // Go back to the filled app. 2559 mUiBot.pressBack(); 2560 } 2561 2562 @Presubmit 2563 @Test testIsServiceEnabled()2564 public void testIsServiceEnabled() throws Exception { 2565 disableService(); 2566 final AutofillManager afm = mActivity.getAutofillManager(); 2567 assertThat(afm.hasEnabledAutofillServices()).isFalse(); 2568 try { 2569 enableService(); 2570 assertThat(afm.hasEnabledAutofillServices()).isTrue(); 2571 } finally { 2572 disableService(); 2573 } 2574 } 2575 2576 @Presubmit 2577 @Test testGetAutofillServiceComponentName()2578 public void testGetAutofillServiceComponentName() throws Exception { 2579 final AutofillManager afm = mActivity.getAutofillManager(); 2580 2581 enableService(); 2582 final ComponentName componentName = afm.getAutofillServiceComponentName(); 2583 assertThat(componentName.getPackageName()).isEqualTo(SERVICE_PACKAGE); 2584 assertThat(componentName.getClassName()).endsWith(SERVICE_CLASS); 2585 2586 disableService(); 2587 assertThat(afm.getAutofillServiceComponentName()).isNull(); 2588 } 2589 2590 @Presubmit 2591 @Test testSetupComplete()2592 public void testSetupComplete() throws Exception { 2593 enableService(); 2594 2595 // Validation check. 2596 final AutofillManager afm = mActivity.getAutofillManager(); 2597 Helper.assertAutofillEnabled(afm, true); 2598 2599 // Now disable user_complete and try again. 2600 try { 2601 setUserComplete(mContext, false); 2602 Helper.assertAutofillEnabled(afm, false); 2603 } finally { 2604 setUserComplete(mContext, true); 2605 } 2606 } 2607 2608 @Presubmit 2609 @Test testPopupGoesAwayWhenServiceIsChanged()2610 public void testPopupGoesAwayWhenServiceIsChanged() throws Exception { 2611 // Set service. 2612 enableService(); 2613 2614 // Set expectations. 2615 sReplier.addResponse(new CannedDataset.Builder() 2616 .setField(ID_USERNAME, "dude") 2617 .setField(ID_PASSWORD, "sweet") 2618 .setPresentation(createPresentation("The Dude")) 2619 .build()); 2620 mActivity.expectAutoFill("dude", "sweet"); 2621 2622 // Trigger auto-fill. 2623 requestFocusOnUsername(); 2624 sReplier.getNextFillRequest(); 2625 mUiBot.assertDatasets("The Dude"); 2626 2627 // Now disable service by setting another service 2628 Helper.enableAutofillService(mContext, NoOpAutofillService.SERVICE_NAME); 2629 2630 // ...and make sure popup's gone 2631 mUiBot.assertNoDatasets(); 2632 } 2633 2634 // TODO(b/70682223): add a new test to make sure service with BIND_AUTOFILL permission works 2635 @Presubmit 2636 @Test 2637 @AppModeFull(reason = "Service-specific test") testServiceIsDisabledWhenNewServiceInfoIsInvalid()2638 public void testServiceIsDisabledWhenNewServiceInfoIsInvalid() throws Exception { 2639 serviceIsDisabledWhenNewServiceIsInvalid(BadAutofillService.SERVICE_NAME); 2640 } 2641 2642 @Test 2643 @AppModeFull(reason = "Service-specific test") testServiceIsDisabledWhenNewServiceNameIsInvalid()2644 public void testServiceIsDisabledWhenNewServiceNameIsInvalid() throws Exception { 2645 serviceIsDisabledWhenNewServiceIsInvalid("Y_U_NO_VALID"); 2646 } 2647 serviceIsDisabledWhenNewServiceIsInvalid(String serviceName)2648 private void serviceIsDisabledWhenNewServiceIsInvalid(String serviceName) throws Exception { 2649 // Set service. 2650 enableService(); 2651 2652 // Set expectations. 2653 sReplier.addResponse(new CannedDataset.Builder() 2654 .setField(ID_USERNAME, "dude") 2655 .setField(ID_PASSWORD, "sweet") 2656 .setPresentation(createPresentation("The Dude")) 2657 .build()); 2658 mActivity.expectAutoFill("dude", "sweet"); 2659 2660 // Trigger autofill. 2661 requestFocusOnUsername(); 2662 sReplier.getNextFillRequest(); 2663 mUiBot.assertDatasets("The Dude"); 2664 2665 // Now disable service by setting another service... 2666 Helper.enableAutofillService(mContext, serviceName); 2667 2668 // ...and make sure popup's gone 2669 mUiBot.assertNoDatasets(); 2670 2671 // Then try to trigger autofill again... 2672 mActivity.onPassword(View::requestFocus); 2673 //...it should not work! 2674 mUiBot.assertNoDatasetsEver(); 2675 } 2676 2677 @Test testAutofillMovesCursorToTheEnd()2678 public void testAutofillMovesCursorToTheEnd() throws Exception { 2679 // Set service. 2680 enableService(); 2681 2682 // Set expectations. 2683 sReplier.addResponse(new CannedDataset.Builder() 2684 .setField(ID_USERNAME, "dude") 2685 .setField(ID_PASSWORD, "sweet") 2686 .setPresentation(createPresentation("The Dude")) 2687 .build()); 2688 mActivity.expectAutoFill("dude", "sweet"); 2689 2690 // Trigger auto-fill. 2691 requestFocusOnUsername(); 2692 sReplier.getNextFillRequest(); 2693 2694 // Auto-fill it. 2695 mUiBot.selectDataset("The Dude"); 2696 2697 // Check the results. 2698 mActivity.assertAutoFilled(); 2699 2700 // NOTE: need to call getSelectionEnd() inside the UI thread, otherwise it returns 0 2701 final AtomicInteger atomicBombToKillASmallInsect = new AtomicInteger(); 2702 2703 mActivity.onUsername((v) -> atomicBombToKillASmallInsect.set(v.getSelectionEnd())); 2704 assertWithMessage("Wrong position on username").that(atomicBombToKillASmallInsect.get()) 2705 .isEqualTo(4); 2706 2707 mActivity.onPassword((v) -> atomicBombToKillASmallInsect.set(v.getSelectionEnd())); 2708 assertWithMessage("Wrong position on password").that(atomicBombToKillASmallInsect.get()) 2709 .isEqualTo(5); 2710 } 2711 2712 @Test testAutofillLargeNumberOfDatasets()2713 public void testAutofillLargeNumberOfDatasets() throws Exception { 2714 // Set service. 2715 enableService(); 2716 2717 final StringBuilder bigStringBuilder = new StringBuilder(); 2718 for (int i = 0; i < 10_000; i++) { 2719 bigStringBuilder.append("BigAmI"); 2720 } 2721 final String bigString = bigStringBuilder.toString(); 2722 2723 final int size = 100; 2724 Log.d(TAG, "testAutofillLargeNumberOfDatasets(): " + size + " datasets with " 2725 + bigString.length() + "-bytes id"); 2726 2727 final CannedFillResponse.Builder response = new CannedFillResponse.Builder(); 2728 for (int i = 0; i < size; i++) { 2729 final String suffix = "-" + (i + 1); 2730 response.addDataset(new CannedDataset.Builder() 2731 .setField(ID_USERNAME, "user" + suffix) 2732 .setField(ID_PASSWORD, "pass" + suffix) 2733 .setId(bigString) 2734 .setPresentation(createPresentation("DS" + suffix)) 2735 .build()); 2736 } 2737 2738 // Set expectations. 2739 sReplier.addResponse(response.build()); 2740 2741 // Trigger auto-fill. 2742 requestFocusOnUsername(); 2743 sReplier.getNextFillRequest(); 2744 2745 // Make sure all datasets are shown. 2746 // TODO: improve assertDatasets() so it supports scrolling, and assert all of them are 2747 // shown. In fullscreen there are 4 items, otherwise there are 3 items. 2748 mUiBot.assertDatasetsContains("DS-1", "DS-2", "DS-3"); 2749 2750 // TODO: once it supports scrolling, selects the last dataset and asserts it's filled. 2751 } 2752 2753 @Presubmit 2754 @Test testCancellationSignalCalledAfterTimeout()2755 public void testCancellationSignalCalledAfterTimeout() throws Exception { 2756 // Set service. 2757 enableService(); 2758 2759 // Set expectations. 2760 final OneTimeCancellationSignalListener listener = 2761 new OneTimeCancellationSignalListener(Timeouts.FILL_TIMEOUT.ms() + 2000); 2762 sReplier.addResponse(DO_NOT_REPLY_RESPONSE); 2763 2764 // Trigger auto-fill. 2765 mActivity.onUsername(View::requestFocus); 2766 2767 // Attach listener to CancellationSignal. 2768 waitUntilConnected(); 2769 sReplier.getNextFillRequest().cancellationSignal.setOnCancelListener(listener); 2770 2771 // Assert results 2772 listener.assertOnCancelCalled(); 2773 } 2774 2775 @Test 2776 @AppModeFull(reason = "Unit test") testNewTextAttributes()2777 public void testNewTextAttributes() throws Exception { 2778 enableService(); 2779 sReplier.addResponse(NO_RESPONSE); 2780 mActivity.onUsername(View::requestFocus); 2781 2782 final FillRequest request = sReplier.getNextFillRequest(); 2783 final ViewNode username = findNodeByResourceId(request.structure, ID_USERNAME); 2784 assertThat(username.getMinTextEms()).isEqualTo(2); 2785 assertThat(username.getMaxTextEms()).isEqualTo(5); 2786 assertThat(username.getMaxTextLength()).isEqualTo(25); 2787 2788 final ViewNode container = findNodeByResourceId(request.structure, ID_USERNAME_CONTAINER); 2789 assertThat(container.getMinTextEms()).isEqualTo(-1); 2790 assertThat(container.getMaxTextEms()).isEqualTo(-1); 2791 assertThat(container.getMaxTextLength()).isEqualTo(-1); 2792 2793 final ViewNode password = findNodeByResourceId(request.structure, ID_PASSWORD); 2794 assertThat(password.getMinTextEms()).isEqualTo(-1); 2795 assertThat(password.getMaxTextEms()).isEqualTo(-1); 2796 assertThat(password.getMaxTextLength()).isEqualTo(5000); 2797 } 2798 2799 @Test testUiShowOnChangeAfterAutofill()2800 public void testUiShowOnChangeAfterAutofill() throws Exception { 2801 // Set service. 2802 enableService(); 2803 2804 // Set expectations. 2805 sReplier.addResponse(new CannedDataset.Builder() 2806 .setField(ID_USERNAME, "dude", createPresentation("dude")) 2807 .setField(ID_PASSWORD, "sweet", createPresentation("sweet")) 2808 .build()); 2809 mActivity.expectAutoFill("dude", "sweet"); 2810 2811 // Trigger auto-fill. 2812 requestFocusOnUsername(); 2813 mUiBot.assertDatasets("dude"); 2814 sReplier.getNextFillRequest(); 2815 mUiBot.selectDataset("dude"); 2816 2817 // Check the results. 2818 mActivity.assertAutoFilled(); 2819 mUiBot.assertNoDatasets(); 2820 2821 // Delete a character. 2822 sendKeyEvent("KEYCODE_DEL"); 2823 assertThat(mUiBot.getTextByRelativeId(ID_USERNAME)).isEqualTo("dud"); 2824 2825 mActivity.expectAutoFill("dude", "sweet"); 2826 2827 // Check autofill UI show. 2828 final UiObject2 datasetPicker = mUiBot.assertDatasets("dude"); 2829 2830 // Autofill again. 2831 mUiBot.selectDataset(datasetPicker, "dude"); 2832 2833 // Check the results. 2834 mActivity.assertAutoFilled(); 2835 mUiBot.assertNoDatasets(); 2836 } 2837 2838 @Test testUiShowOnChangeAfterAutofillOnePresentation()2839 public void testUiShowOnChangeAfterAutofillOnePresentation() throws Exception { 2840 // Set service. 2841 enableService(); 2842 2843 // Set expectations. 2844 sReplier.addResponse(new CannedDataset.Builder() 2845 .setField(ID_USERNAME, "dude") 2846 .setField(ID_PASSWORD, "sweet") 2847 .setPresentation(createPresentation("The Dude")) 2848 .build()); 2849 mActivity.expectAutoFill("dude", "sweet"); 2850 2851 // Trigger auto-fill. 2852 requestFocusOnUsername(); 2853 mUiBot.assertDatasets("The Dude"); 2854 sReplier.getNextFillRequest(); 2855 mUiBot.selectDataset("The Dude"); 2856 2857 // Check the results. 2858 mActivity.assertAutoFilled(); 2859 mUiBot.assertNoDatasets(); 2860 2861 // Delete username 2862 mUiBot.setTextByRelativeId(ID_USERNAME, ""); 2863 2864 mActivity.expectAutoFill("dude", "sweet"); 2865 2866 // Check autofill UI show. 2867 final UiObject2 datasetPicker = mUiBot.assertDatasets("The Dude"); 2868 2869 // Autofill again. 2870 mUiBot.selectDataset(datasetPicker, "The Dude"); 2871 2872 // Check the results. 2873 mActivity.assertAutoFilled(); 2874 mUiBot.assertNoDatasets(); 2875 } 2876 2877 @Presubmit 2878 @Test testCancelActionButton()2879 public void testCancelActionButton() throws Exception { 2880 // Set service. 2881 enableService(); 2882 2883 // Set expectations. 2884 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 2885 .addDataset(new CannedDataset.Builder() 2886 .setField(ID_USERNAME, "dude") 2887 .setField(ID_PASSWORD, "sweet") 2888 .setPresentation(createPresentationWithCancel("The Dude")) 2889 .build()) 2890 .setPresentationCancelIds(new int[]{R.id.cancel_fill}); 2891 sReplier.addResponse(builder.build()); 2892 2893 // Trigger auto-fill. 2894 mActivity.onUsername(View::requestFocus); 2895 sReplier.getNextFillRequest(); 2896 2897 mUiBot.assertDatasetsContains("The Dude"); 2898 2899 // Tap cancel button on fill UI 2900 mUiBot.selectByRelativeId(ID_CANCEL_FILL); 2901 mUiBot.waitForIdle(); 2902 2903 mUiBot.assertNoDatasets(); 2904 2905 // Test and verify auto-fill does not trigger 2906 mActivity.onPassword(View::requestFocus); 2907 mUiBot.waitForIdle(); 2908 2909 mUiBot.assertNoDatasetsEver(); 2910 2911 // Test and verify auto-fill does not trigger. 2912 mActivity.onUsername(View::requestFocus); 2913 mUiBot.waitForIdle(); 2914 2915 mUiBot.assertNoDatasetsEver(); 2916 2917 // Reset 2918 mActivity.tapClear(); 2919 2920 // Set expectations. 2921 final CannedFillResponse.Builder builder2 = new CannedFillResponse.Builder() 2922 .addDataset(new CannedDataset.Builder() 2923 .setField(ID_USERNAME, "dude") 2924 .setField(ID_PASSWORD, "sweet") 2925 .setPresentation(createPresentationWithCancel("The Dude")) 2926 .build()) 2927 .setPresentationCancelIds(new int[]{R.id.cancel}); 2928 sReplier.addResponse(builder2.build()); 2929 2930 // Trigger auto-fill. 2931 mActivity.onPassword(View::requestFocus); 2932 sReplier.getNextFillRequest(); 2933 2934 // Verify auto-fill has been triggered. 2935 mUiBot.assertDatasetsContains("The Dude"); 2936 } 2937 2938 @Presubmit 2939 @Test 2940 @AppModeFull(reason = "WRITE_SECURE_SETTING permission can't be grant to instant apps") testSwitchInputMethod_noNewFillRequest()2941 public void testSwitchInputMethod_noNewFillRequest() throws Exception { 2942 // TODO(b/187664861): Find better solution for small display device. 2943 mUiBot.assumeMinimumResolution(500); 2944 2945 // Set service 2946 enableService(); 2947 2948 // Set expectations 2949 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 2950 .addDataset(new CannedDataset.Builder() 2951 .setField(ID_USERNAME, "dude") 2952 .setField(ID_PASSWORD, "sweet") 2953 .setPresentation(createPresentation("The Dude")) 2954 .build()); 2955 sReplier.addResponse(builder.build()); 2956 2957 // Trigger auto-fill 2958 mActivity.onUsername(View::requestFocus); 2959 sReplier.getNextFillRequest(); 2960 2961 mUiBot.assertDatasetsContains("The Dude"); 2962 2963 // Trigger IME switch event 2964 Helper.mockSwitchInputMethod(sContext); 2965 mUiBot.waitForIdleSync(); 2966 2967 // Tap password field 2968 mUiBot.selectByRelativeId(ID_PASSWORD); 2969 mUiBot.waitForIdleSync(); 2970 2971 mUiBot.assertDatasetsContains("The Dude"); 2972 2973 // No new fill request 2974 sReplier.assertNoUnhandledFillRequests(); 2975 } 2976 } 2977