1 /* 2 * Copyright (C) 2020 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.inline; 18 19 import static android.autofillservice.cts.testcore.CannedFillResponse.NO_RESPONSE; 20 import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD; 21 import static android.autofillservice.cts.testcore.Helper.ID_USERNAME; 22 import static android.autofillservice.cts.testcore.Helper.assertTextIsSanitized; 23 import static android.autofillservice.cts.testcore.Helper.disablePccDetectionFeature; 24 import static android.autofillservice.cts.testcore.Helper.enablePccDetectionFeature; 25 import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId; 26 import static android.autofillservice.cts.testcore.Helper.findNodeByResourceId; 27 import static android.autofillservice.cts.testcore.Helper.getContext; 28 import static android.autofillservice.cts.testcore.Helper.isPccFieldClassificationSet; 29 import static android.autofillservice.cts.testcore.InstrumentedAutoFillServiceInlineEnabled.SERVICE_NAME; 30 import static android.autofillservice.cts.testcore.Timeouts.MOCK_IME_TIMEOUT_MS; 31 import static android.view.View.AUTOFILL_HINT_USERNAME; 32 33 import static com.android.cts.mockime.ImeEventStreamTestUtils.expectEvent; 34 35 import static com.google.common.truth.Truth.assertThat; 36 import static com.google.common.truth.Truth.assertWithMessage; 37 38 import static org.junit.Assume.assumeTrue; 39 40 import android.accessibilityservice.AccessibilityServiceInfo; 41 import android.app.PendingIntent; 42 import android.app.UiAutomation; 43 import android.autofillservice.cts.activities.DummyActivity; 44 import android.autofillservice.cts.activities.NonAutofillableActivity; 45 import android.autofillservice.cts.activities.UsernameOnlyActivity; 46 import android.autofillservice.cts.commontests.LoginActivityCommonTestCase; 47 import android.autofillservice.cts.testcore.CannedFillResponse; 48 import android.autofillservice.cts.testcore.Helper; 49 import android.autofillservice.cts.testcore.IdMode; 50 import android.autofillservice.cts.testcore.InlineUiBot; 51 import android.autofillservice.cts.testcore.InstrumentedAutoFillService; 52 import android.content.Intent; 53 import android.os.Binder; 54 import android.os.Bundle; 55 import android.os.SystemClock; 56 import android.platform.test.annotations.AppModeFull; 57 import android.platform.test.annotations.Presubmit; 58 import android.service.autofill.FillContext; 59 import android.util.Log; 60 import android.view.accessibility.AccessibilityManager; 61 62 import androidx.test.platform.app.InstrumentationRegistry; 63 import androidx.test.uiautomator.Direction; 64 65 import com.android.cts.mockime.ImeEventStream; 66 import com.android.cts.mockime.MockImeSession; 67 68 import org.junit.After; 69 import org.junit.Ignore; 70 import org.junit.Test; 71 import org.junit.rules.TestRule; 72 73 import java.util.concurrent.CountDownLatch; 74 import java.util.concurrent.TimeUnit; 75 76 @Presubmit 77 public class InlineLoginActivityTest extends LoginActivityCommonTestCase { 78 79 private static final String TAG = "InlineLoginActivityTest"; 80 81 @Override enableService()82 protected void enableService() { 83 Helper.enableAutofillService(SERVICE_NAME); 84 } 85 InlineLoginActivityTest()86 public InlineLoginActivityTest() { 87 super(getInlineUiBot()); 88 } 89 90 @Override isInlineMode()91 protected boolean isInlineMode() { 92 return true; 93 } 94 95 @Override getMainTestRule()96 public TestRule getMainTestRule() { 97 return InlineUiBot.annotateRule(super.getMainTestRule()); 98 } 99 100 @After disablePcc()101 public void disablePcc() { 102 Log.d(TAG, "@After: disablePcc()"); 103 disablePccDetectionFeature(sContext); 104 } 105 106 @Test testAutofill_disjointDatasets()107 public void testAutofill_disjointDatasets() throws Exception { 108 // Set service. 109 enableService(); 110 111 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 112 .addDataset(new CannedFillResponse.CannedDataset.Builder() 113 .setField(ID_USERNAME, "dude") 114 .setPresentation(createPresentation("The Username")) 115 .setInlinePresentation(createInlinePresentation("The Username")) 116 .build()) 117 .addDataset(new CannedFillResponse.CannedDataset.Builder() 118 .setField(ID_PASSWORD, "sweet") 119 .setPresentation(createPresentation("The Password")) 120 .setInlinePresentation(createInlinePresentation("The Password")) 121 .build()) 122 .addDataset(new CannedFillResponse.CannedDataset.Builder() 123 .setField(ID_PASSWORD, "lollipop") 124 .setPresentation(createPresentation("The Password2")) 125 .setInlinePresentation(createInlinePresentation("The Password2")) 126 .build()); 127 128 sReplier.addResponse(builder.build()); 129 mActivity.expectAutoFill("dude"); 130 131 // Trigger auto-fill. 132 mUiBot.selectByRelativeId(ID_USERNAME); 133 mUiBot.waitForIdleSync(); 134 135 mUiBot.assertDatasets("The Username"); 136 137 // Switch focus to password 138 mUiBot.selectByRelativeId(ID_PASSWORD); 139 mUiBot.waitForIdleSync(); 140 141 mUiBot.assertDatasets("The Password", "The Password2"); 142 143 // Switch focus back to username 144 mUiBot.selectByRelativeId(ID_USERNAME); 145 mUiBot.waitForIdleSync(); 146 147 mUiBot.assertDatasets("The Username"); 148 mUiBot.selectDataset("The Username"); 149 mUiBot.waitForIdleSync(); 150 151 // Check the results. 152 mActivity.assertAutoFilled(); 153 154 // Make sure input was sanitized. 155 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 156 assertWithMessage("CancelationSignal is null").that(request.cancellationSignal).isNotNull(); 157 assertTextIsSanitized(request.structure, ID_PASSWORD); 158 final FillContext fillContext = request.contexts.get(request.contexts.size() - 1); 159 assertThat(fillContext.getFocusedId()) 160 .isEqualTo(findAutofillIdByResourceId(fillContext, ID_USERNAME)); 161 162 // Make sure initial focus was properly set. 163 assertWithMessage("Username node is not focused").that( 164 findNodeByResourceId(request.structure, ID_USERNAME).isFocused()).isTrue(); 165 assertWithMessage("Password node is focused").that( 166 findNodeByResourceId(request.structure, ID_PASSWORD).isFocused()).isFalse(); 167 } 168 169 @Test testAutofill_SwitchToAutofillableActivity()170 public void testAutofill_SwitchToAutofillableActivity() throws Exception { 171 assertAutofill_SwitchActivity(UsernameOnlyActivity.class, /* autofillable */ true); 172 } 173 174 @Test testAutofill_SwitchToNonAutofillableActivity()175 public void testAutofill_SwitchToNonAutofillableActivity() throws Exception { 176 assertAutofill_SwitchActivity(NonAutofillableActivity.class, /* autofillable */ false); 177 } 178 assertAutofill_SwitchActivity(Class<?> clazz, boolean autofillable)179 private void assertAutofill_SwitchActivity(Class<?> clazz, boolean autofillable) 180 throws Exception { 181 // Set service. 182 enableService(); 183 184 // Set expectations. 185 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 186 .addDataset(new CannedFillResponse.CannedDataset.Builder() 187 .setField(ID_USERNAME, "dude") 188 .setField(ID_PASSWORD, "password") 189 .setPresentation(createPresentation("The Username")) 190 .setInlinePresentation(createInlinePresentation("The Username")) 191 .build()); 192 sReplier.addResponse(builder.build()); 193 194 // Trigger auto-fill. 195 mUiBot.selectByRelativeId(ID_USERNAME); 196 mUiBot.waitForIdleSync(); 197 sReplier.getNextFillRequest(); 198 // Make sure the suggestion is shown. 199 mUiBot.assertDatasets("The Username"); 200 201 mUiBot.pressHome(); 202 mUiBot.waitForIdle(); 203 204 // Switch to another Activity 205 startActivity(clazz); 206 mUiBot.waitForIdle(); 207 208 // Trigger input method show. 209 mUiBot.selectByRelativeId(ID_USERNAME); 210 mUiBot.waitForIdleSync(); 211 if (autofillable) { 212 sReplier.addResponse(NO_RESPONSE); 213 sReplier.getNextFillRequest(); 214 } 215 // Make sure suggestion is not shown. 216 mUiBot.assertNoDatasets(); 217 } 218 startActivity(Class<?> clazz)219 protected final void startActivity(Class<?> clazz) { 220 final Intent intent = new Intent(mContext, clazz); 221 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 222 mContext.startActivity(intent); 223 } 224 225 @Test testAutofill_selectDatasetThenHideInlineSuggestion()226 public void testAutofill_selectDatasetThenHideInlineSuggestion() throws Exception { 227 // Set service. 228 enableService(); 229 230 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 231 .addDataset(new CannedFillResponse.CannedDataset.Builder() 232 .setField(ID_USERNAME, "dude") 233 .setPresentation(createPresentation("The Username")) 234 .setInlinePresentation(createInlinePresentation("The Username")) 235 .build()); 236 237 sReplier.addResponse(builder.build()); 238 mActivity.expectAutoFill("dude"); 239 240 // Trigger auto-fill. 241 mUiBot.selectByRelativeId(ID_USERNAME); 242 mUiBot.waitForIdleSync(); 243 244 mUiBot.assertDatasets("The Username"); 245 246 mUiBot.selectDataset("The Username"); 247 mUiBot.waitForIdleSync(); 248 249 mUiBot.assertNoDatasets(); 250 251 // Make sure input was sanitized. 252 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 253 assertWithMessage("CancelationSignal is null").that(request.cancellationSignal).isNotNull(); 254 assertTextIsSanitized(request.structure, ID_PASSWORD); 255 final FillContext fillContext = request.contexts.get(request.contexts.size() - 1); 256 assertThat(fillContext.getFocusedId()) 257 .isEqualTo(findAutofillIdByResourceId(fillContext, ID_USERNAME)); 258 259 // Make sure initial focus was properly set. 260 assertWithMessage("Username node is not focused").that( 261 findNodeByResourceId(request.structure, ID_USERNAME).isFocused()).isTrue(); 262 assertWithMessage("Password node is focused").that( 263 findNodeByResourceId(request.structure, ID_PASSWORD).isFocused()).isFalse(); 264 } 265 266 @Test testLongClickAttribution()267 public void testLongClickAttribution() throws Exception { 268 // Set service. 269 enableService(); 270 271 Intent intent = new Intent(mContext, DummyActivity.class); 272 PendingIntent pendingIntent = 273 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); 274 275 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 276 .addDataset(new CannedFillResponse.CannedDataset.Builder() 277 .setField(ID_USERNAME, "dude") 278 .setPresentation(createPresentation("The Username")) 279 .setInlinePresentation( 280 createInlinePresentation("The Username", pendingIntent)) 281 .build()); 282 283 sReplier.addResponse(builder.build()); 284 mActivity.expectAutoFill("dude"); 285 286 // Trigger auto-fill. 287 mUiBot.selectByRelativeId(ID_USERNAME); 288 mUiBot.waitForIdleSync(); 289 290 mUiBot.assertDatasets("The Username"); 291 292 // Long click on suggestion 293 mUiBot.longPressSuggestion("The Username"); 294 mUiBot.waitForIdleSync(); 295 296 // Make sure the attribution showed worked 297 mUiBot.selectByText("foo"); 298 299 // Go back to the filled app. 300 mUiBot.pressBack(); 301 302 sReplier.getNextFillRequest(); 303 mUiBot.waitForIdleSync(); 304 } 305 306 @Test 307 @AppModeFull(reason = "BROADCAST_STICKY permission cannot be granted to instant apps") testAutofill_noInvalid()308 public void testAutofill_noInvalid() throws Exception { 309 final String keyInvalid = "invalid"; 310 final String keyValid = "valid"; 311 final String message = "Passes valid message to the remote service"; 312 final Bundle bundle = new Bundle(); 313 bundle.putBinder(keyInvalid, new Binder()); 314 bundle.putString(keyValid, message); 315 316 // Set service. 317 enableService(); 318 final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession(); 319 assumeTrue("MockIME not available", mockImeSession != null); 320 321 mockImeSession.callSetInlineSuggestionsExtras(bundle); 322 323 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 324 .addDataset(new CannedFillResponse.CannedDataset.Builder() 325 .setField(ID_USERNAME, "dude") 326 .setPresentation(createPresentation("The Username")) 327 .setInlinePresentation(createInlinePresentation("The Username")) 328 .build()); 329 330 sReplier.addResponse(builder.build()); 331 332 // Trigger auto-fill. 333 mUiBot.selectByRelativeId(ID_USERNAME); 334 mUiBot.waitForIdleSync(); 335 336 mUiBot.assertDatasets("The Username"); 337 338 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 339 final Bundle extras = request.inlineRequest.getExtras(); 340 assertThat(extras.get(keyInvalid)).isNull(); 341 assertThat(extras.getString(keyValid)).isEqualTo(message); 342 343 final Bundle style = request.inlineRequest.getInlinePresentationSpecs().get(0).getStyle(); 344 assertThat(style.get(keyInvalid)).isNull(); 345 assertThat(style.getString(keyValid)).isEqualTo(message); 346 347 final Bundle style2 = request.inlineRequest.getInlinePresentationSpecs().get(1).getStyle(); 348 assertThat(style2.get(keyInvalid)).isNull(); 349 assertThat(style2.getString(keyValid)).isEqualTo(message); 350 } 351 352 @Test 353 @AppModeFull(reason = "WRITE_SECURE_SETTING permission can't be grant to instant apps") testSwitchInputMethod()354 public void testSwitchInputMethod() throws Exception { 355 // Set service 356 enableService(); 357 358 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 359 .addDataset(new CannedFillResponse.CannedDataset.Builder() 360 .setField(ID_USERNAME, "dude") 361 .setPresentation(createPresentation("The Username")) 362 .setInlinePresentation(createInlinePresentation("The Username")) 363 .build()); 364 365 sReplier.addResponse(builder.build()); 366 367 // Trigger auto-fill 368 mUiBot.selectByRelativeId(ID_USERNAME); 369 mUiBot.waitForIdleSync(); 370 371 mUiBot.assertDatasets("The Username"); 372 373 sReplier.getNextFillRequest(); 374 375 // Trigger IME switch event 376 Helper.mockSwitchInputMethod(sContext); 377 mUiBot.waitForIdleSync(); 378 379 final CannedFillResponse.Builder builder2 = new CannedFillResponse.Builder() 380 .addDataset(new CannedFillResponse.CannedDataset.Builder() 381 .setField(ID_USERNAME, "dude2") 382 .setPresentation(createPresentation("The Username 2")) 383 .setInlinePresentation(createInlinePresentation("The Username 2")) 384 .build()); 385 386 sReplier.addResponse(builder2.build()); 387 388 // Trigger auto-fill 389 mUiBot.selectByRelativeId(ID_USERNAME); 390 mUiBot.waitForIdleSync(); 391 392 // Confirm new suggestion 393 mUiBot.assertDatasets("The Username 2"); 394 395 // Confirm new fill request 396 sReplier.getNextFillRequest(); 397 } 398 399 @Test 400 @AppModeFull(reason = "BROADCAST_STICKY permission cannot be granted to instant apps") testImeDisableInlineSuggestions_fallbackDropdownUi()401 public void testImeDisableInlineSuggestions_fallbackDropdownUi() throws Exception { 402 // Set service. 403 enableService(); 404 405 final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession(); 406 assumeTrue("MockIME not available", mockImeSession != null); 407 408 // Disable inline suggestions for the default service. 409 final Bundle bundle = new Bundle(); 410 bundle.putBoolean("InlineSuggestions", false); 411 mockImeSession.callSetInlineSuggestionsExtras(bundle); 412 413 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 414 .addDataset(new CannedFillResponse.CannedDataset.Builder() 415 .setField(ID_USERNAME, "dude") 416 .setPresentation(createPresentation("The Username")) 417 .setInlinePresentation(createInlinePresentation("The Username")) 418 .build()); 419 sReplier.addResponse(builder.build()); 420 421 // Trigger auto-fill. 422 mUiBot.selectByRelativeId(ID_USERNAME); 423 mUiBot.waitForIdleSync(); 424 425 // Check that no inline requests are sent to the service. 426 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 427 assertThat(request.inlineRequest).isNull(); 428 429 // Check dropdown UI shown. 430 getDropdownUiBot().assertDatasets("The Username"); 431 } 432 433 @Test testTouchExplorationEnabledImeSupportInline_inlineShown()434 public void testTouchExplorationEnabledImeSupportInline_inlineShown() throws Exception { 435 enableTouchExploration(); 436 437 enableService(); 438 439 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 440 .addDataset(new CannedFillResponse.CannedDataset.Builder() 441 .setField(ID_USERNAME, "dude") 442 .setPresentation(createPresentation("The Username")) 443 .setInlinePresentation(createInlinePresentation("The Username")) 444 .build()); 445 sReplier.addResponse(builder.build()); 446 447 try { 448 // Trigger auto-fill. 449 mUiBot.selectByRelativeId(ID_USERNAME); 450 mUiBot.waitForIdleSync(); 451 452 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 453 assertThat(request.inlineRequest).isNotNull(); 454 455 // Check datasets shown. 456 mUiBot.assertDatasets("The Username"); 457 } catch (Exception e) { 458 throw e; 459 } finally { 460 resetTouchExploration(); 461 } 462 } 463 464 @Test testScrollSuggestionView()465 public void testScrollSuggestionView() throws Exception { 466 // Set service. 467 enableService(); 468 469 final int firstDataset = 1; 470 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder(); 471 for (int i = firstDataset; i <= 20; i++) { 472 builder.addDataset(new CannedFillResponse.CannedDataset.Builder() 473 .setField(ID_USERNAME, "dude" + i) 474 .setPresentation(createPresentation("Username" + i)) 475 .setInlinePresentation(createInlinePresentation("Username" + i)) 476 .build()); 477 } 478 479 sReplier.addResponse(builder.build()); 480 481 // Trigger auto-fill. 482 mUiBot.selectByRelativeId(ID_USERNAME); 483 mUiBot.waitForIdleSync(); 484 485 mUiBot.assertSuggestion("Username" + firstDataset); 486 487 // Scroll the suggestion view 488 mUiBot.scrollSuggestionView(Direction.RIGHT, /* speed */ 3000); 489 mUiBot.waitForIdleSync(); 490 491 mUiBot.assertNoSuggestion("Username" + firstDataset); 492 493 sReplier.getNextFillRequest(); 494 mUiBot.waitForIdleSync(); 495 } 496 497 @Test testClickEventPassToIme()498 public void testClickEventPassToIme() throws Exception { 499 testTouchEventPassToIme(/* longPress */ false); 500 } 501 502 @Test testLongClickEventPassToIme()503 public void testLongClickEventPassToIme() throws Exception { 504 testTouchEventPassToIme(/* longPress */ true); 505 } 506 testTouchEventPassToIme(boolean longPress)507 private void testTouchEventPassToIme(boolean longPress) throws Exception { 508 final MockImeSession mockImeSession = sMockImeSessionRule.getMockImeSession(); 509 assumeTrue("MockIME not available", mockImeSession != null); 510 511 // Set service. 512 enableService(); 513 514 Intent intent = new Intent(mContext, DummyActivity.class); 515 PendingIntent pendingIntent = 516 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); 517 518 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 519 .addDataset(new CannedFillResponse.CannedDataset.Builder() 520 .setField(ID_USERNAME, "dude") 521 .setPresentation(createPresentation("The Username")) 522 .setInlinePresentation(longPress 523 ? createInlinePresentation("The Username", pendingIntent) 524 : createInlinePresentation("The Username")) 525 .build()); 526 527 sReplier.addResponse(builder.build()); 528 529 final ImeEventStream stream = mockImeSession.openEventStream(); 530 531 // Trigger auto-fill. 532 mUiBot.selectByRelativeId(ID_USERNAME); 533 mUiBot.waitForIdleSync(); 534 sReplier.getNextFillRequest(); 535 536 mUiBot.assertDatasets("The Username"); 537 538 if (longPress) { 539 // Long click on suggestion 540 mUiBot.longPressSuggestion("The Username"); 541 542 expectEvent(stream, 543 event -> "onInlineSuggestionLongClickedEvent".equals(event.getEventName()), 544 MOCK_IME_TIMEOUT_MS); 545 } else { 546 // Click on suggestion 547 mUiBot.selectDataset("The Username"); 548 549 expectEvent(stream, 550 event -> "onInlineSuggestionClickedEvent".equals(event.getEventName()), 551 MOCK_IME_TIMEOUT_MS); 552 } 553 } 554 555 @Test testInlineSuggestionViewReleased()556 public void testInlineSuggestionViewReleased() throws Exception { 557 // Set service 558 enableService(); 559 560 // Prepare the autofill response 561 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 562 .addDataset(new CannedFillResponse.CannedDataset.Builder() 563 .setField(ID_USERNAME, "dude") 564 .setPresentation(createPresentation("The Username")) 565 .setInlinePresentation(createInlinePresentation("The Username")) 566 .build()) 567 .addDataset(new CannedFillResponse.CannedDataset.Builder() 568 .setField(ID_PASSWORD, "sweet") 569 .setPresentation(createPresentation("The Password")) 570 .setInlinePresentation(createInlinePresentation("The Password")) 571 .build()) 572 .addDataset(new CannedFillResponse.CannedDataset.Builder() 573 .setField(ID_PASSWORD, "lollipop") 574 .setPresentation(createPresentation("The Password2")) 575 .setInlinePresentation(createInlinePresentation("The Password2")) 576 .build()); 577 sReplier.addResponse(builder.build()); 578 579 // Trigger auto-fill on username field 580 mUiBot.selectByRelativeId(ID_USERNAME); 581 mUiBot.waitForIdleSync(); 582 mUiBot.assertDatasets("The Username"); 583 Helper.assertActiveViewCountFromInlineSuggestionRenderService(1); 584 585 // Switch focus to password 586 mUiBot.selectByRelativeId(ID_PASSWORD); 587 mUiBot.waitForIdleSync(); 588 mUiBot.assertDatasets("The Password", "The Password2"); 589 Helper.assertActiveViewCountFromInlineSuggestionRenderService(2); 590 591 // Switch focus back to username 592 mUiBot.selectByRelativeId(ID_USERNAME); 593 mUiBot.waitForIdleSync(); 594 mUiBot.assertDatasets("The Username"); 595 Helper.assertActiveViewCountFromInlineSuggestionRenderService(1); 596 597 // Select the autofill suggestion on username, then check the results 598 mActivity.expectAutoFill("dude"); 599 mUiBot.selectDataset("The Username"); 600 mUiBot.waitForIdleSync(); 601 mActivity.assertAutoFilled(); 602 sReplier.getNextFillRequest(); 603 604 // Sleep for a while for the wait in {@link com.android.server.autofill.ui 605 // .RemoteInlineSuggestionUi} to timeout. 606 SystemClock.sleep(500); 607 Helper.assertActiveViewCountFromInlineSuggestionRenderService(0); 608 } 609 610 @Test 611 @Ignore("b/281726966") testAutofill_pccDatasets()612 public void testAutofill_pccDatasets() throws Exception { 613 // Set service. 614 enableService(); 615 enablePccDetectionFeature(sContext, "username"); 616 sReplier.setIdMode(IdMode.PCC_ID); 617 618 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 619 .addDataset(new CannedFillResponse.CannedDataset.Builder() 620 .setField(ID_USERNAME, "dude") 621 .setField(ID_PASSWORD, "sweet") 622 .setPresentation(createPresentation("The Dude")) 623 .build()) 624 .addDataset(new CannedFillResponse.CannedDataset.Builder() 625 .setField(ID_USERNAME, "user1") 626 .setField(ID_PASSWORD, "pass1") 627 .setPresentation(createPresentation("generic user")) 628 .build()); 629 sReplier.addResponse(builder.build()); 630 631 // Trigger auto-fill. 632 mUiBot.selectByRelativeId(ID_USERNAME); 633 mUiBot.waitForIdleSync(); 634 635 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 636 if (isPccFieldClassificationSet(sContext)) { 637 assertThat(request.hints.size()).isEqualTo(1); 638 assertThat(request.hints.get(0)).isEqualTo("username"); 639 } 640 disablePccDetectionFeature(sContext); 641 sReplier.setIdMode(IdMode.RESOURCE_ID); 642 } 643 644 @Test 645 @Ignore("b/281726966") autofillPccDatasetTest_setForAllHints()646 public void autofillPccDatasetTest_setForAllHints() throws Exception { 647 // Set service. 648 enableService(); 649 enablePccDetectionFeature(sContext, "username", "password", "new_password"); 650 sReplier.setIdMode(IdMode.PCC_ID); 651 652 final CannedFillResponse.Builder builder = new CannedFillResponse.Builder() 653 .addDataset(new CannedFillResponse.CannedDataset.Builder() 654 .setField(AUTOFILL_HINT_USERNAME, "dude") 655 .setField("allField1") 656 .setPresentation(createPresentation("The Dude")) 657 .build()) 658 .addDataset(new CannedFillResponse.CannedDataset.Builder() 659 .setField("allField2") 660 .setPresentation(createPresentation("generic user")) 661 .build()); 662 sReplier.addResponse(builder.build()); 663 664 // Trigger auto-fill. 665 mUiBot.selectByRelativeId(ID_USERNAME); 666 mUiBot.waitForIdleSync(); 667 668 final InstrumentedAutoFillService.FillRequest request = sReplier.getNextFillRequest(); 669 if (isPccFieldClassificationSet(sContext)) { 670 assertThat(request.hints.size()).isEqualTo(3); 671 } 672 673 disablePccDetectionFeature(sContext); 674 sReplier.setIdMode(IdMode.RESOURCE_ID); 675 } 676 enableTouchExploration()677 private void enableTouchExploration() throws InterruptedException { 678 toggleTouchExploration(/*enable=*/ true); 679 } 680 resetTouchExploration()681 private void resetTouchExploration() throws InterruptedException { 682 toggleTouchExploration(/*enable=*/ false); 683 } 684 toggleTouchExploration(boolean enable)685 private void toggleTouchExploration(boolean enable) 686 throws InterruptedException { 687 final AccessibilityManager manager = 688 getContext().getSystemService(AccessibilityManager.class); 689 if (isTouchExplorationEnabled(manager) == enable) { 690 return; 691 } 692 693 final CountDownLatch latch = new CountDownLatch(1); 694 AccessibilityManager.TouchExplorationStateChangeListener serviceListener = 695 (boolean newState) -> { 696 if (newState == enable) { 697 latch.countDown(); 698 } 699 }; 700 manager.addTouchExplorationStateChangeListener(serviceListener); 701 702 final UiAutomation uiAutomation = 703 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 704 final AccessibilityServiceInfo info = uiAutomation.getServiceInfo(); 705 assert info != null; 706 if (enable) { 707 info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; 708 } else { 709 info.flags &= ~AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE; 710 } 711 uiAutomation.setServiceInfo(info); 712 713 // Wait for touch exploration state to be toggled 714 assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); 715 716 if (enable) { 717 assertThat(isTouchExplorationEnabled(manager)).isTrue(); 718 } else { 719 assertThat(isTouchExplorationEnabled(manager)).isFalse(); 720 } 721 manager.removeTouchExplorationStateChangeListener(serviceListener); 722 } 723 isTouchExplorationEnabled(AccessibilityManager manager)724 private static boolean isTouchExplorationEnabled(AccessibilityManager manager) { 725 return manager.isEnabled() && manager.isTouchExplorationEnabled(); 726 } 727 } 728