1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.contentcaptureservice.cts; 17 18 import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.CREATION; 19 import static android.contentcaptureservice.cts.Assertions.LifecycleOrder.DESTRUCTION; 20 import static android.contentcaptureservice.cts.Assertions.assertChildSessionContext; 21 import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared; 22 import static android.contentcaptureservice.cts.Assertions.assertLifecycleOrder; 23 import static android.contentcaptureservice.cts.Assertions.assertMainSessionContext; 24 import static android.contentcaptureservice.cts.Assertions.assertNoViewLevelEvents; 25 import static android.contentcaptureservice.cts.Assertions.assertRightActivity; 26 import static android.contentcaptureservice.cts.Assertions.assertSessionPaused; 27 import static android.contentcaptureservice.cts.Assertions.assertSessionResumed; 28 import static android.contentcaptureservice.cts.Assertions.assertViewAppeared; 29 import static android.contentcaptureservice.cts.Assertions.assertViewDisappeared; 30 import static android.contentcaptureservice.cts.Assertions.assertViewTreeFinished; 31 import static android.contentcaptureservice.cts.Assertions.assertViewTreeStarted; 32 import static android.contentcaptureservice.cts.Assertions.assertViewsDisappeared; 33 import static android.contentcaptureservice.cts.Helper.newImportantView; 34 import static android.contentcaptureservice.cts.Helper.sContext; 35 36 import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED; 37 import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED; 38 39 import static com.google.common.truth.Truth.assertThat; 40 41 import static org.testng.Assert.assertThrows; 42 43 import android.content.ComponentName; 44 import android.content.LocusId; 45 import android.contentcaptureservice.cts.CtsContentCaptureService.DisconnectListener; 46 import android.contentcaptureservice.cts.CtsContentCaptureService.ServiceWatcher; 47 import android.contentcaptureservice.cts.CtsContentCaptureService.Session; 48 import android.os.SystemClock; 49 import android.platform.test.annotations.AppModeFull; 50 import android.util.Log; 51 import android.view.View; 52 import android.view.autofill.AutofillId; 53 import android.view.contentcapture.ContentCaptureContext; 54 import android.view.contentcapture.ContentCaptureEvent; 55 import android.view.contentcapture.ContentCaptureManager; 56 import android.view.contentcapture.ContentCaptureSession; 57 import android.view.contentcapture.ContentCaptureSessionId; 58 import android.widget.LinearLayout; 59 import android.widget.TextView; 60 61 import androidx.annotation.NonNull; 62 import androidx.annotation.Nullable; 63 import androidx.test.rule.ActivityTestRule; 64 65 import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher; 66 import com.android.compatibility.common.util.ActivityLauncher; 67 68 import org.junit.After; 69 import org.junit.Before; 70 import org.junit.Test; 71 72 import java.util.Arrays; 73 import java.util.List; 74 import java.util.concurrent.atomic.AtomicReference; 75 76 @AppModeFull(reason = "BlankWithTitleActivityTest is enough") 77 public class ChildlessActivityTest 78 extends AbstractContentCaptureIntegrationAutoActivityLaunchTest<ChildlessActivity> { 79 80 private static final String TAG = ChildlessActivityTest.class.getSimpleName(); 81 82 private static final ActivityTestRule<ChildlessActivity> sActivityRule = new ActivityTestRule<>( 83 ChildlessActivity.class, false, false); 84 ChildlessActivityTest()85 public ChildlessActivityTest() { 86 super(ChildlessActivity.class); 87 } 88 89 @Override getActivityTestRule()90 protected ActivityTestRule<ChildlessActivity> getActivityTestRule() { 91 return sActivityRule; 92 } 93 94 @Before 95 @After resetActivityStaticState()96 public void resetActivityStaticState() { 97 ChildlessActivity.onRootView(null); 98 } 99 100 @Test testDefaultLifecycle()101 public void testDefaultLifecycle() throws Exception { 102 final CtsContentCaptureService service = enableService(); 103 final ActivityWatcher watcher = startWatcher(); 104 105 final ChildlessActivity activity = launchActivity(); 106 watcher.waitFor(RESUMED); 107 108 activity.finish(); 109 watcher.waitFor(DESTROYED); 110 111 final Session session = service.getOnlyFinishedSession(); 112 Log.v(TAG, "session id: " + session.id); 113 114 activity.assertDefaultEvents(session); 115 } 116 117 @Test testGetContentCapture_disabledWhenNoService()118 public void testGetContentCapture_disabledWhenNoService() throws Exception { 119 final ActivityWatcher watcher = startWatcher(); 120 121 final ChildlessActivity activity = launchActivity(); 122 watcher.waitFor(RESUMED); 123 124 assertThat(activity.getContentCaptureManager().isContentCaptureEnabled()).isFalse(); 125 126 activity.finish(); 127 watcher.waitFor(DESTROYED); 128 } 129 130 @Test testGetContentCapture_enabledWhenNoService()131 public void testGetContentCapture_enabledWhenNoService() throws Exception { 132 enableService(); 133 final ActivityWatcher watcher = startWatcher(); 134 135 final ChildlessActivity activity = launchActivity(); 136 watcher.waitFor(RESUMED); 137 138 assertThat(activity.getContentCaptureManager().isContentCaptureEnabled()).isTrue(); 139 140 activity.finish(); 141 watcher.waitFor(DESTROYED); 142 143 } 144 145 @Test testLaunchAnotherActivity()146 public void testLaunchAnotherActivity() throws Exception { 147 final CtsContentCaptureService service = enableService(); 148 final ActivityWatcher watcher1 = startWatcher(); 149 150 // Launch and finish 1st activity 151 final ChildlessActivity activity1 = launchActivity(); 152 watcher1.waitFor(RESUMED); 153 activity1.finish(); 154 watcher1.waitFor(DESTROYED); 155 156 // Launch and finish 2nd activity 157 final ActivityLauncher<LoginActivity> anotherActivityLauncher = new ActivityLauncher<>( 158 sContext, mActivitiesWatcher, LoginActivity.class); 159 final ActivityWatcher watcher2 = anotherActivityLauncher.getWatcher(); 160 final LoginActivity activity2 = anotherActivityLauncher.launchActivity(); 161 watcher2.waitFor(RESUMED); 162 activity2.finish(); 163 watcher2.waitFor(DESTROYED); 164 165 // Assert the sessions 166 final List<ContentCaptureSessionId> sessionIds = service.getAllSessionIds(); 167 assertThat(sessionIds).hasSize(2); 168 final ContentCaptureSessionId sessionId1 = sessionIds.get(0); 169 Log.v(TAG, "session id1: " + sessionId1); 170 final ContentCaptureSessionId sessionId2 = sessionIds.get(1); 171 Log.v(TAG, "session id2: " + sessionId2); 172 173 final Session session1 = service.getFinishedSession(sessionId1); 174 activity1.assertDefaultEvents(session1); 175 176 final Session session2 = service.getFinishedSession(sessionId2); 177 activity2.assertDefaultEvents(session2); 178 } 179 180 181 @Test testLaunchAnotherActivity_onTopOfIt()182 public void testLaunchAnotherActivity_onTopOfIt() throws Exception { 183 final CtsContentCaptureService service = enableService(); 184 final ActivityWatcher watcher1 = startWatcher(); 185 186 // Launch 1st activity 187 final ChildlessActivity activity1 = launchActivity(); 188 watcher1.waitFor(RESUMED); 189 190 // Launch and finish 2nd activity 191 final ActivityLauncher<LoginActivity> anotherActivityLauncher = new ActivityLauncher<>( 192 sContext, mActivitiesWatcher, LoginActivity.class); 193 final ActivityWatcher watcher2 = anotherActivityLauncher.getWatcher(); 194 final LoginActivity activity2 = anotherActivityLauncher.launchActivity(); 195 196 watcher2.waitFor(RESUMED); 197 activity2.finish(); 198 watcher2.waitFor(DESTROYED); 199 200 // Finish 1st activity 201 activity1.finish(); 202 watcher1.waitFor(DESTROYED); 203 204 // Assert the activity lifecycle events 205 final ComponentName name1 = activity1.getComponentName(); 206 final ComponentName name2 = activity2.getComponentName(); 207 service.assertThat() 208 .activityResumed(name1) 209 .activityPaused(name1) 210 .activityResumed(name2) 211 .activityStopped(name1) 212 .activityPaused(name2) 213 .activityResumed(name1) 214 .activityDestroyed(name2) 215 .activityPaused(name1); 216 217 // Assert the sessions 218 final List<ContentCaptureSessionId> sessionIds = service.getAllSessionIds(); 219 assertThat(sessionIds).hasSize(2); 220 final ContentCaptureSessionId sessionId1 = sessionIds.get(0); 221 Log.v(TAG, "session id1: " + sessionId1); 222 final ContentCaptureSessionId sessionId2 = sessionIds.get(1); 223 Log.v(TAG, "session id2: " + sessionId2); 224 225 final Session session1 = service.getFinishedSession(sessionId1); 226 final List<ContentCaptureEvent> events1 = session1.getEvents(); 227 Log.v(TAG, "events on " + activity1 + ": " + events1); 228 assertThat(events1).hasSize(4); 229 assertSessionResumed(events1, 0); 230 assertSessionPaused(events1, 1); 231 assertSessionResumed(events1, 2); 232 assertSessionPaused(events1, 3); 233 234 final Session session2 = service.getFinishedSession(sessionId2); 235 activity2.assertDefaultEvents(session2); 236 237 } 238 239 @Test testAddAndRemoveNoImportantChild()240 public void testAddAndRemoveNoImportantChild() throws Exception { 241 final CtsContentCaptureService service = enableService(); 242 final ActivityWatcher watcher = startWatcher(); 243 244 // Child must be created inside the lambda because it needs to use the Activity context. 245 final AtomicReference<TextView> childRef = new AtomicReference<>(); 246 247 ChildlessActivity.onRootView((activity, rootView) -> { 248 final TextView child = new TextView(activity); 249 child.setText("VIEW, Y U NO IMPORTANT?"); 250 child.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO); 251 252 rootView.addView(child); 253 }); 254 255 final ChildlessActivity activity = launchActivity(); 256 watcher.waitFor(RESUMED); 257 258 // Remove view 259 final TextView child = childRef.get(); 260 activity.syncRunOnUiThread(() -> activity.getRootView().removeView(child)); 261 262 activity.finish(); 263 watcher.waitFor(DESTROYED); 264 265 final Session session = service.getOnlyFinishedSession(); 266 final ContentCaptureSessionId sessionId = session.id; 267 Log.v(TAG, "session id: " + sessionId); 268 269 assertRightActivity(session, sessionId, activity); 270 271 // Should be empty because the root view is not important for content capture without a 272 // child that is important. 273 assertNoViewLevelEvents(session, activity); 274 } 275 276 @Test testAddAndRemoveImportantChild()277 public void testAddAndRemoveImportantChild() throws Exception { 278 final CtsContentCaptureService service = enableService(); 279 final ActivityWatcher watcher = startWatcher(); 280 281 // TODO(b/120494182): Child must be created inside the lambda because it needs to use the 282 // Activity context. 283 final AtomicReference<TextView> childRef = new AtomicReference<>(); 284 285 ChildlessActivity.onRootView((activity, rootView) -> { 286 final TextView text = newImportantView(activity, "Important I am"); 287 rootView.addView(text); 288 childRef.set(text); 289 }); 290 291 final ChildlessActivity activity = launchActivity(); 292 watcher.waitFor(RESUMED); 293 294 // Remove view 295 final LinearLayout rootView = activity.getRootView(); 296 final TextView child = childRef.get(); 297 activity.syncRunOnUiThread(() -> rootView.removeView(child)); 298 299 activity.finish(); 300 watcher.waitFor(DESTROYED); 301 302 final Session session = service.getOnlyFinishedSession(); 303 final ContentCaptureSessionId sessionId = session.id; 304 Log.v(TAG, "session id: " + sessionId); 305 306 assertRightActivity(session, sessionId, activity); 307 308 final List<ContentCaptureEvent> events = session.getEvents(); 309 Log.v(TAG, "events(" + events.size() + "): " + events); 310 311 final AutofillId rootId = rootView.getAutofillId(); 312 313 final View grandpa1 = activity.getGrandParent(); 314 final View grandpa2 = activity.getGrandGrandParent(); 315 final View decorView = activity.getDecorView(); 316 317 // Assert just the relevant events 318 assertThat(events.size()).isAtLeast(12); 319 assertSessionResumed(events, 0); 320 assertViewTreeStarted(events, 1); 321 assertDecorViewAppeared(events, 2, decorView); 322 assertViewAppeared(events, 3, grandpa2, decorView.getAutofillId()); 323 assertViewAppeared(events, 4, grandpa1, grandpa2.getAutofillId()); 324 assertViewAppeared(events, 5, sessionId, rootView, grandpa1.getAutofillId()); 325 assertViewAppeared(events, 6, sessionId, child, rootId); 326 assertViewTreeFinished(events, 7); 327 assertViewTreeStarted(events, 8); 328 assertViewDisappeared(events, 9, child.getAutofillId()); 329 assertViewTreeFinished(events, 10); 330 assertSessionPaused(events, 11); 331 332 // TODO(b/122315042): assert parents disappeared 333 } 334 335 @Test testAddImportantChildAfterSessionStarted()336 public void testAddImportantChildAfterSessionStarted() throws Exception { 337 final CtsContentCaptureService service = enableService(); 338 final ActivityWatcher watcher = startWatcher(); 339 340 final ChildlessActivity activity = launchActivity(); 341 watcher.waitFor(RESUMED); 342 343 // Add View 344 final LinearLayout rootView = activity.getRootView(); 345 final TextView child = newImportantView(activity, "Important I am"); 346 activity.runOnUiThread(() -> rootView.addView(child)); 347 348 activity.finish(); 349 watcher.waitFor(DESTROYED); 350 351 final Session session = service.getOnlyFinishedSession(); 352 final ContentCaptureSessionId sessionId = session.id; 353 Log.v(TAG, "session id: " + sessionId); 354 355 assertRightActivity(session, sessionId, activity); 356 357 final List<ContentCaptureEvent> events = session.getEvents(); 358 Log.v(TAG, "events(" + events.size() + "): " + events); 359 360 final View grandpa = activity.getGrandParent(); 361 362 // Assert just the relevant events 363 364 assertThat(events.size()).isAtLeast(6); 365 // TODO(b/122959591): figure out the child is coming first 366 assertSessionResumed(events, 0); 367 assertViewTreeStarted(events, 1); 368 assertViewAppeared(events, 2, sessionId, child, rootView.getAutofillId()); 369 assertViewAppeared(events, 3, sessionId, rootView, grandpa.getAutofillId()); 370 assertViewTreeFinished(events, 4); 371 assertSessionPaused(events, 5); 372 } 373 374 @Test testAddAndRemoveImportantChildOnDifferentSession()375 public void testAddAndRemoveImportantChildOnDifferentSession() throws Exception { 376 final CtsContentCaptureService service = enableService(); 377 final ActivityWatcher watcher = startWatcher(); 378 379 final ChildlessActivity activity = launchActivity(); 380 watcher.waitFor(RESUMED); 381 382 final LinearLayout rootView = activity.getRootView(); 383 final View grandpa = activity.getGrandParent(); 384 385 final ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 386 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 387 Log.v(TAG, "main session id: " + mainSessionId); 388 389 final ContentCaptureSession childSession = mainSession 390 .createContentCaptureSession(newContentCaptureContextBuilder("child") 391 .build()); 392 final ContentCaptureSessionId childSessionId = childSession.getContentCaptureSessionId(); 393 Log.v(TAG, "child session id: " + childSessionId); 394 395 final TextView child = newImportantView(activity, "Important I am"); 396 final AutofillId childId = child.getAutofillId(); 397 Log.v(TAG, "childId: " + childId); 398 child.setContentCaptureSession(childSession); 399 activity.runOnUiThread(() -> rootView.addView(child)); 400 401 activity.finish(); 402 watcher.waitFor(DESTROYED); 403 404 final List<ContentCaptureSessionId> sessionIds = service.getAllSessionIds(); 405 assertThat(sessionIds).containsExactly(mainSessionId, childSessionId).inOrder(); 406 407 // Assert sessions 408 final Session mainTestSession = service.getFinishedSession(mainSessionId); 409 assertMainSessionContext(mainTestSession, activity); 410 final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents(); 411 Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents); 412 413 assertThat(mainEvents.size()).isAtLeast(5); 414 assertSessionResumed(mainEvents, 0); 415 assertViewTreeStarted(mainEvents, 1); 416 assertViewAppeared(mainEvents, 2, mainSessionId, rootView, grandpa.getAutofillId()); 417 assertViewTreeFinished(mainEvents, 3); 418 assertSessionPaused(mainEvents, 4); 419 420 final Session childTestSession = service.getFinishedSession(childSessionId); 421 assertChildSessionContext(childTestSession, "child"); 422 final List<ContentCaptureEvent> childEvents = childTestSession.getEvents(); 423 Log.v(TAG, "childEvents(" + childEvents.size() + "): " + childEvents); 424 final int minEvents = 3; 425 assertThat(childEvents.size()).isAtLeast(minEvents); 426 assertViewTreeStarted(childEvents, 0); 427 assertViewAppeared(childEvents, 1, childSessionId, child, rootView.getAutofillId()); 428 assertViewTreeFinished(childEvents, 2); 429 // TODO(b/122315042): assert parents disappeared 430 } 431 432 /** 433 * Tests scenario where new sessions are added from the main session, but they're not nested 434 * neither have views attached to them. 435 */ 436 @Test testDinamicallyManageChildlessSiblingSessions()437 public void testDinamicallyManageChildlessSiblingSessions() throws Exception { 438 final CtsContentCaptureService service = enableService(); 439 final ActivityWatcher watcher = startWatcher(); 440 441 final ChildlessActivity activity = launchActivity(); 442 watcher.waitFor(RESUMED); 443 444 final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession(); 445 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 446 Log.v(TAG, "main session id: " + mainSessionId); 447 448 // Create 1st session 449 final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1") 450 .build(); 451 final ContentCaptureSession childSession1 = mainSession 452 .createContentCaptureSession(context1); 453 final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId(); 454 Log.v(TAG, "child session id 1: " + childSessionId1); 455 456 // Create 2nd session 457 final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2") 458 .build(); 459 final ContentCaptureSession childSession2 = mainSession 460 .createContentCaptureSession(context2); 461 final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId(); 462 Log.v(TAG, "child session id 2: " + childSessionId2); 463 464 // Close 1st session before opening 3rd 465 childSession1.close(); 466 467 // Create 3nd session... 468 final ContentCaptureContext context3 = newContentCaptureContextBuilder("session3") 469 .build(); 470 final ContentCaptureSession childSession3 = mainSession 471 .createContentCaptureSession(context3); 472 final ContentCaptureSessionId childSessionId3 = childSession3.getContentCaptureSessionId(); 473 Log.v(TAG, "child session id 3: " + childSessionId3); 474 475 // ...and close it right away 476 childSession3.close(); 477 478 // Create 4nd session 479 final ContentCaptureContext context4 = newContentCaptureContextBuilder("session4") 480 .build(); 481 final ContentCaptureSession childSession4 = mainSession 482 .createContentCaptureSession(context4); 483 final ContentCaptureSessionId childSessionId4 = childSession4.getContentCaptureSessionId(); 484 Log.v(TAG, "child session id 4: " + childSessionId4); 485 486 activity.finish(); 487 watcher.waitFor(DESTROYED); 488 489 final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds(); 490 assertThat(receivedIds).containsExactly( 491 mainSessionId, 492 childSessionId1, 493 childSessionId2, 494 childSessionId3, 495 childSessionId4) 496 .inOrder(); 497 498 // Assert main sessions info 499 final Session mainTestSession = service.getFinishedSession(mainSessionId); 500 assertMainSessionContext(mainTestSession, activity); 501 502 final Session childTestSession1 = service.getFinishedSession(childSessionId1); 503 assertChildSessionContext(childTestSession1, "session1"); 504 505 final Session childTestSession2 = service.getFinishedSession(childSessionId2); 506 assertChildSessionContext(childTestSession2, "session2"); 507 508 final Session childTestSession3 = service.getFinishedSession(childSessionId3); 509 assertChildSessionContext(childTestSession3, "session3"); 510 511 final Session childTestSession4 = service.getFinishedSession(childSessionId4); 512 assertChildSessionContext(childTestSession4, "session4"); 513 514 // Gets all events first so they're all logged before the assertions 515 final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents(); 516 final List<ContentCaptureEvent> events1 = childTestSession1.getEvents(); 517 final List<ContentCaptureEvent> events2 = childTestSession2.getEvents(); 518 final List<ContentCaptureEvent> events3 = childTestSession3.getEvents(); 519 final List<ContentCaptureEvent> events4 = childTestSession4.getEvents(); 520 Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents); 521 Log.v(TAG, "events1(" + events1.size() + "): " + events1); 522 Log.v(TAG, "events2(" + events2.size() + "): " + events2); 523 Log.v(TAG, "events3(" + events3.size() + "): " + events3); 524 Log.v(TAG, "events4(" + events4.size() + "): " + events4); 525 526 assertNoViewLevelEvents(mainTestSession, activity); 527 assertThat(events1).isEmpty(); 528 assertThat(events2).isEmpty(); 529 assertThat(events3).isEmpty(); 530 assertThat(events4).isEmpty(); 531 532 // Assert lifecycle methods were called in the right order 533 assertLifecycleOrder(1, mainTestSession, CREATION); 534 assertLifecycleOrder(2, childTestSession1, CREATION); 535 assertLifecycleOrder(3, childTestSession2, CREATION); 536 assertLifecycleOrder(4, childTestSession1, DESTRUCTION); 537 assertLifecycleOrder(5, childTestSession3, CREATION); 538 assertLifecycleOrder(6, childTestSession3, DESTRUCTION); 539 assertLifecycleOrder(7, childTestSession4, CREATION); 540 assertLifecycleOrder(8, childTestSession2, DESTRUCTION); 541 assertLifecycleOrder(9, childTestSession4, DESTRUCTION); 542 assertLifecycleOrder(10, mainTestSession, DESTRUCTION); 543 } 544 545 @Test testDinamicallyAddOneChildOnAnotherSession_manuallyCloseSession()546 public void testDinamicallyAddOneChildOnAnotherSession_manuallyCloseSession() throws Exception { 547 dinamicallyAddOneChildOnAnotherSessionTest(/* manuallyCloseSession= */ true); 548 } 549 550 @Test testDinamicallyAddOneChildOnAnotherSession_autoCloseSession()551 public void testDinamicallyAddOneChildOnAnotherSession_autoCloseSession() throws Exception { 552 dinamicallyAddOneChildOnAnotherSessionTest(/* manuallyCloseSession= */ false); 553 } 554 555 /** 556 * Tests scenario where just 1 session with 1 dinamically added view is created. 557 */ dinamicallyAddOneChildOnAnotherSessionTest(boolean manuallyCloseSession)558 private void dinamicallyAddOneChildOnAnotherSessionTest(boolean manuallyCloseSession) 559 throws Exception { 560 final CtsContentCaptureService service = enableService(); 561 final ActivityWatcher watcher = startWatcher(); 562 563 final ChildlessActivity activity = launchActivity(); 564 watcher.waitFor(RESUMED); 565 final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession(); 566 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 567 Log.v(TAG, "main session id: " + mainSessionId); 568 569 // Create session 570 final ContentCaptureSession childSession = mainSession 571 .createContentCaptureSession( 572 newContentCaptureContextBuilder("child_session").build()); 573 final ContentCaptureSessionId childSessionId = childSession.getContentCaptureSessionId(); 574 Log.v(TAG, "child session: " + childSessionId); 575 576 final TextView child = addChild(activity, childSession, "Sweet O'Mine"); 577 if (manuallyCloseSession) { 578 waitAndClose(childSession); 579 } 580 581 activity.finish(); 582 watcher.waitFor(DESTROYED); 583 584 final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds(); 585 assertThat(receivedIds).containsExactly(mainSessionId, childSessionId).inOrder(); 586 587 // Assert main session 588 final Session mainTestSession = service.getFinishedSession(mainSessionId); 589 assertMainSessionContext(mainTestSession, activity); 590 // TODO(b/123540067): ideally it should be empty, but has intermediate parents stuff... 591 // assertThat(mainTestSession.getEvents()).isEmpty(); 592 593 // Assert child session 594 final Session childTestSession = service.getFinishedSession(childSessionId); 595 assertChildSessionContext(childTestSession, "child_session"); 596 final List<ContentCaptureEvent> childEvents = childTestSession.getEvents(); 597 assertThat(childEvents.size()).isAtLeast(3); 598 final AutofillId rootId = activity.getRootView().getAutofillId(); 599 assertViewTreeStarted(childEvents, 0); 600 assertViewAppeared(childEvents, 1, child, rootId); 601 assertViewTreeFinished(childEvents, 2); 602 603 // Assert lifecycle methods were called in the right order 604 assertLifecycleOrder(1, mainTestSession, CREATION); 605 assertLifecycleOrder(2, childTestSession, CREATION); 606 assertLifecycleOrder(3, childTestSession, DESTRUCTION); 607 assertLifecycleOrder(4, mainTestSession, DESTRUCTION); 608 } 609 610 /** 611 * Tests scenario where new sessions with children are added from the main session. 612 */ 613 @Test testDinamicallyManageSiblingSessions()614 public void testDinamicallyManageSiblingSessions() throws Exception { 615 final CtsContentCaptureService service = enableService(); 616 final ActivityWatcher watcher = startWatcher(); 617 618 final ChildlessActivity activity = launchActivity(); 619 watcher.waitFor(RESUMED); 620 final LinearLayout rootView = activity.getRootView(); 621 final ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 622 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 623 Log.v(TAG, "main session id: " + mainSessionId); 624 625 // Create 1st session 626 final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1") 627 .build(); 628 final ContentCaptureSession childSession1 = mainSession 629 .createContentCaptureSession(context1); 630 final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId(); 631 Log.v(TAG, "child session id 1: " + childSessionId1); 632 633 // Session 1, child 1 634 final TextView s1c1 = addChild(activity, childSession1, "s1c1"); 635 636 // Create 2nd session 637 final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2") 638 .build(); 639 final ContentCaptureSession childSession2 = mainSession 640 .createContentCaptureSession(context2); 641 final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId(); 642 Log.v(TAG, "child session id 2: " + childSessionId2); 643 644 final TextView s2c1 = newImportantView(activity, childSession2, "s2c1"); 645 final TextView s2c2 = newImportantView(activity, childSession2, "s2c1"); 646 647 // Add 2 children together so they're wrapped a view_tree batch 648 activity.runOnUiThread(() -> { 649 rootView.addView(s2c1); 650 rootView.addView(s2c2); 651 }); 652 653 // Close 1st session before opening 3rd 654 waitAndClose(childSession1); 655 656 // Create 3nd session... 657 final ContentCaptureContext context3 = newContentCaptureContextBuilder("session3") 658 .build(); 659 final ContentCaptureSession childSession3 = mainSession 660 .createContentCaptureSession(context3); 661 final ContentCaptureSessionId childSessionId3 = childSession3.getContentCaptureSessionId(); 662 Log.v(TAG, "child session id 3: " + childSessionId3); 663 664 final TextView s3c1 = newImportantView(activity, childSession3, "s3c1"); 665 final TextView s3c2 = newImportantView(activity, childSession3, "s3c1"); 666 final TextView s3c3 = newImportantView(activity, childSession3, "s3c3"); 667 668 // Add 2 children together so they're wrapped a view_tree batch 669 activity.runOnUiThread(() -> { 670 rootView.addView(s3c1); 671 rootView.addView(s3c2); 672 }); 673 674 // TODO(b/123024698): need to wait until the 4 events are flushed - ideally we should block 675 // waiting until the service received them 676 sleep(); 677 678 // Add 2 children so they're wrapped a view_tree batch 679 activity.runOnUiThread(() -> { 680 rootView.removeView(s3c1); 681 rootView.addView(s3c3); 682 }); 683 684 // ...and close it right away 685 waitAndClose(childSession3); 686 687 // Create 4nd session 688 final ContentCaptureContext context4 = newContentCaptureContextBuilder("session4") 689 .build(); 690 final ContentCaptureSession childSession4 = mainSession 691 .createContentCaptureSession(context4); 692 final ContentCaptureSessionId childSessionId4 = childSession4.getContentCaptureSessionId(); 693 Log.v(TAG, "child session id 4: " + childSessionId4); 694 695 activity.finish(); 696 watcher.waitFor(DESTROYED); 697 698 final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds(); 699 assertThat(receivedIds).containsExactly( 700 mainSessionId, 701 childSessionId1, 702 childSessionId2, 703 childSessionId3, 704 childSessionId4) 705 .inOrder(); 706 707 // Assert main sessions info 708 final Session mainTestSession = service.getFinishedSession(mainSessionId); 709 assertMainSessionContext(mainTestSession, activity); 710 final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents(); 711 Log.v(TAG, "main session events(" + mainEvents.size() + "): " + mainEvents); 712 713 // Gets all events first so they're all logged before the assertions 714 final Session childTestSession1 = service.getFinishedSession(childSessionId1); 715 assertChildSessionContext(childTestSession1, "session1"); 716 final List<ContentCaptureEvent> events1 = childTestSession1.getEvents(); 717 Log.v(TAG, "events1(" + events1.size() + "): " + events1); 718 719 final Session childTestSession2 = service.getFinishedSession(childSessionId2); 720 final List<ContentCaptureEvent> events2 = childTestSession2.getEvents(); 721 assertChildSessionContext(childTestSession2, "session2"); 722 Log.v(TAG, "events2(" + events2.size() + "): " + events2); 723 final Session childTestSession3 = service.getFinishedSession(childSessionId3); 724 assertChildSessionContext(childTestSession3, "session3"); 725 List<ContentCaptureEvent> events3 = childTestSession3.getEvents(); 726 Log.v(TAG, "events3(" + events3.size() + "): " + events3); 727 728 final AutofillId rootId = rootView.getAutofillId(); 729 final View grandpa = activity.getGrandParent(); 730 731 assertThat(mainEvents).hasSize(8); 732 assertSessionResumed(mainEvents, 0); 733 assertViewTreeStarted(mainEvents, 1); 734 assertViewAppeared(mainEvents, 2, rootView, grandpa.getAutofillId()); 735 assertViewTreeFinished(mainEvents, 3); 736 assertSessionPaused(mainEvents, 4); // TODO(b/122959591): investigate why 737 assertViewTreeStarted(mainEvents, 5); 738 assertViewDisappeared(mainEvents, 6, rootId); 739 assertViewTreeFinished(mainEvents, 7); 740 741 assertThat(events1).hasSize(3); 742 assertViewTreeStarted(events1, 0); 743 assertViewAppeared(events1, 1, s1c1, rootId); 744 assertViewTreeFinished(events1, 2); 745 746 assertThat(events2.size()).isAtLeast(4); 747 assertViewTreeStarted(events2, 0); 748 assertViewAppeared(events2, 1, s2c1, rootId); 749 assertViewAppeared(events2, 2, s2c2, rootId); 750 assertViewTreeFinished(events2, 3); 751 // TODO(b/122315042): assert parents disappeared 752 753 assertThat(events3).hasSize(8); 754 assertViewTreeStarted(events3, 0); 755 assertViewAppeared(events3, 1, s3c1, rootId); 756 assertViewAppeared(events3, 2, s3c2, rootId); 757 assertViewTreeFinished(events3, 3); 758 assertViewTreeStarted(events3, 4); 759 assertViewDisappeared(events3, 5, s3c1.getAutofillId()); 760 assertViewAppeared(events3, 6, s3c3, rootId); 761 assertViewTreeFinished(events3, 7); 762 763 final Session childTestSession4 = service.getFinishedSession(childSessionId4); 764 assertChildSessionContext(childTestSession4, "session4"); 765 assertThat(childTestSession4.getEvents()).isEmpty(); 766 767 // Assert lifecycle methods were called in the right order 768 assertLifecycleOrder(1, mainTestSession, CREATION); 769 assertLifecycleOrder(2, childTestSession1, CREATION); 770 assertLifecycleOrder(3, childTestSession2, CREATION); 771 assertLifecycleOrder(4, childTestSession1, DESTRUCTION); 772 assertLifecycleOrder(5, childTestSession3, CREATION); 773 assertLifecycleOrder(6, childTestSession3, DESTRUCTION); 774 assertLifecycleOrder(7, childTestSession4, CREATION); 775 assertLifecycleOrder(8, childTestSession2, DESTRUCTION); 776 assertLifecycleOrder(9, childTestSession4, DESTRUCTION); 777 assertLifecycleOrder(10, mainTestSession, DESTRUCTION); 778 } 779 780 @Test testNestedSessions_simplestScenario()781 public void testNestedSessions_simplestScenario() throws Exception { 782 final CtsContentCaptureService service = enableService(); 783 final ActivityWatcher watcher = startWatcher(); 784 785 final ChildlessActivity activity = launchActivity(); 786 watcher.waitFor(RESUMED); 787 788 final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession(); 789 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 790 Log.v(TAG, "main session id: " + mainSessionId); 791 792 // Create child session 793 final ContentCaptureContext childContext = newContentCaptureContextBuilder("child") 794 .build(); 795 final ContentCaptureSession childSession = mainSession 796 .createContentCaptureSession(childContext); 797 final ContentCaptureSessionId childSessionId = childSession.getContentCaptureSessionId(); 798 Log.v(TAG, "child session id: " + childSessionId); 799 800 // Create grand child session 801 final ContentCaptureContext grandChild = newContentCaptureContextBuilder("grandChild") 802 .build(); 803 final ContentCaptureSession grandChildSession = childSession 804 .createContentCaptureSession(grandChild); 805 final ContentCaptureSessionId grandChildSessionId = grandChildSession 806 .getContentCaptureSessionId(); 807 Log.v(TAG, "child session id: " + grandChildSessionId); 808 809 activity.finish(); 810 watcher.waitFor(DESTROYED); 811 812 final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds(); 813 assertThat(receivedIds).containsExactly( 814 mainSessionId, 815 childSessionId, 816 grandChildSessionId) 817 .inOrder(); 818 819 // Assert sessions 820 final Session mainTestSession = service.getFinishedSession(mainSessionId); 821 assertMainSessionContext(mainTestSession, activity); 822 assertNoViewLevelEvents(mainTestSession, activity); 823 824 final Session childTestSession = service.getFinishedSession(childSessionId); 825 assertChildSessionContext(childTestSession, "child"); 826 assertThat(childTestSession.getEvents()).isEmpty(); 827 828 final Session grandChildTestSession = service.getFinishedSession(grandChildSessionId); 829 assertChildSessionContext(grandChildTestSession, "grandChild"); 830 assertThat(grandChildTestSession.getEvents()).isEmpty(); 831 832 // Assert lifecycle methods were called in the right order 833 assertLifecycleOrder(1, mainTestSession, CREATION); 834 assertLifecycleOrder(2, childTestSession, CREATION); 835 assertLifecycleOrder(3, grandChildTestSession, CREATION); 836 assertLifecycleOrder(4, grandChildTestSession, DESTRUCTION); 837 assertLifecycleOrder(5, childTestSession, DESTRUCTION); 838 assertLifecycleOrder(6, mainTestSession, DESTRUCTION); 839 } 840 841 /** 842 * Tests scenario where new sessions are added from each other session, but they're not nested 843 * neither have views attached to them. 844 * 845 * <p>This test actions are exactly the same as 846 * {@link #testDinamicallyManageChildlessSiblingSessions()}, except for session nesting (and 847 * order of lifecycle events). 848 */ 849 @Test testDinamicallyManageChildlessNestedSessions()850 public void testDinamicallyManageChildlessNestedSessions() throws Exception { 851 final CtsContentCaptureService service = enableService(); 852 final ActivityWatcher watcher = startWatcher(); 853 854 final ChildlessActivity activity = launchActivity(); 855 watcher.waitFor(RESUMED); 856 857 final ContentCaptureSession mainSession = activity.getRootView().getContentCaptureSession(); 858 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 859 Log.v(TAG, "main session id: " + mainSessionId); 860 861 // Create 1st session 862 final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1") 863 .build(); 864 final ContentCaptureSession childSession1 = mainSession 865 .createContentCaptureSession(context1); 866 final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId(); 867 Log.v(TAG, "child session id 1: " + childSessionId1); 868 869 // Create 2nd session 870 final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2") 871 .build(); 872 final ContentCaptureSession childSession2 = childSession1 873 .createContentCaptureSession(context2); 874 final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId(); 875 Log.v(TAG, "child session id 2: " + childSessionId2); 876 877 // Close 1st session before opening 3rd 878 childSession1.close(); 879 880 // Create 3nd session... 881 final ContentCaptureContext context3 = newContentCaptureContextBuilder("session3") 882 .build(); 883 final ContentCaptureSession childSession3 = mainSession 884 .createContentCaptureSession(context3); 885 final ContentCaptureSessionId childSessionId3 = childSession3.getContentCaptureSessionId(); 886 Log.v(TAG, "child session id 3: " + childSessionId3); 887 888 // ...and close it right away 889 childSession3.close(); 890 891 // Create 4nd session 892 final ContentCaptureContext context4 = newContentCaptureContextBuilder("session4") 893 .build(); 894 final ContentCaptureSession childSession4 = mainSession 895 .createContentCaptureSession(context4); 896 final ContentCaptureSessionId childSessionId4 = childSession4.getContentCaptureSessionId(); 897 Log.v(TAG, "child session id 4: " + childSessionId4); 898 899 activity.finish(); 900 watcher.waitFor(DESTROYED); 901 902 final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds(); 903 assertThat(receivedIds).containsExactly( 904 mainSessionId, 905 childSessionId1, 906 childSessionId2, 907 childSessionId3, 908 childSessionId4) 909 .inOrder(); 910 911 // Assert main sessions info 912 final Session mainTestSession = service.getFinishedSession(mainSessionId); 913 assertMainSessionContext(mainTestSession, activity); 914 assertNoViewLevelEvents(mainTestSession, activity); 915 916 final Session childTestSession1 = service.getFinishedSession(childSessionId1); 917 assertChildSessionContext(childTestSession1, "session1"); 918 assertThat(childTestSession1.getEvents()).isEmpty(); 919 920 final Session childTestSession2 = service.getFinishedSession(childSessionId2); 921 assertChildSessionContext(childTestSession2, "session2"); 922 assertThat(childTestSession2.getEvents()).isEmpty(); 923 924 final Session childTestSession3 = service.getFinishedSession(childSessionId3); 925 assertChildSessionContext(childTestSession3, "session3"); 926 assertThat(childTestSession3.getEvents()).isEmpty(); 927 928 final Session childTestSession4 = service.getFinishedSession(childSessionId4); 929 assertChildSessionContext(childTestSession4, "session4"); 930 assertThat(childTestSession4.getEvents()).isEmpty(); 931 932 // Assert lifecycle methods were called in the right order 933 assertLifecycleOrder(1, mainTestSession, CREATION); 934 assertLifecycleOrder(2, childTestSession1, CREATION); 935 assertLifecycleOrder(3, childTestSession2, CREATION); 936 assertLifecycleOrder(4, childTestSession2, DESTRUCTION); 937 assertLifecycleOrder(5, childTestSession1, DESTRUCTION); 938 assertLifecycleOrder(6, childTestSession3, CREATION); 939 assertLifecycleOrder(7, childTestSession3, DESTRUCTION); 940 assertLifecycleOrder(8, childTestSession4, CREATION); 941 assertLifecycleOrder(9, childTestSession4, DESTRUCTION); 942 assertLifecycleOrder(10, mainTestSession, DESTRUCTION); 943 } 944 945 /** 946 * Tests scenario where views from different session are removed in sequence - they should not 947 * have been batched. 948 */ 949 @Test testRemoveChildrenFromDifferentSessions()950 public void testRemoveChildrenFromDifferentSessions() throws Exception { 951 final CtsContentCaptureService service = enableService(); 952 final ActivityWatcher watcher = startWatcher(); 953 954 final ChildlessActivity activity = launchActivity(); 955 watcher.waitFor(RESUMED); 956 final LinearLayout rootView = activity.getRootView(); 957 final ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 958 final ContentCaptureSessionId mainSessionId = mainSession.getContentCaptureSessionId(); 959 Log.v(TAG, "main session id: " + mainSessionId); 960 961 // Create 1st session 962 final ContentCaptureContext context1 = newContentCaptureContextBuilder("session1") 963 .build(); 964 final ContentCaptureSession childSession1 = mainSession 965 .createContentCaptureSession(context1); 966 final ContentCaptureSessionId childSessionId1 = childSession1.getContentCaptureSessionId(); 967 Log.v(TAG, "child session id 1: " + childSessionId1); 968 969 // Session 1, child 1 970 final TextView s1c1 = addChild(activity, childSession1, "s1c1"); 971 final AutofillId s1c1Id = s1c1.getAutofillId(); 972 Log.v(TAG, "childrens from session1: " + s1c1Id); 973 974 // Create 2nd session 975 final ContentCaptureContext context2 = newContentCaptureContextBuilder("session2") 976 .build(); 977 final ContentCaptureSession childSession2 = mainSession 978 .createContentCaptureSession(context2); 979 final ContentCaptureSessionId childSessionId2 = childSession2.getContentCaptureSessionId(); 980 Log.v(TAG, "child session id 2: " + childSessionId2); 981 982 final TextView s2c1 = newImportantView(activity, childSession2, "s2c1"); 983 final AutofillId s2c1Id = s2c1.getAutofillId(); 984 final TextView s2c2 = newImportantView(activity, childSession2, "s2c2"); 985 final AutofillId s2c2Id = s2c2.getAutofillId(); 986 Log.v(TAG, "childrens from session2: " + s2c1Id + ", " + s2c2Id); 987 988 // Add 2 children together so they're wrapped a view_tree batch 989 activity.syncRunOnUiThread(() -> { 990 rootView.addView(s2c1); 991 rootView.addView(s2c2); 992 }); 993 994 // Remove views - should generate one batch event for s2 and one single event for s1 995 waitAndRemoveViews(activity, s2c1, s2c2, s1c1); 996 997 activity.finish(); 998 watcher.waitFor(DESTROYED); 999 1000 final List<ContentCaptureSessionId> receivedIds = service.getAllSessionIds(); 1001 assertThat(receivedIds).containsExactly( 1002 mainSessionId, 1003 childSessionId1, 1004 childSessionId2) 1005 .inOrder(); 1006 1007 // Assert main sessions info 1008 final Session mainTestSession = service.getFinishedSession(mainSessionId); 1009 assertMainSessionContext(mainTestSession, activity); 1010 final List<ContentCaptureEvent> mainEvents = mainTestSession.getEvents(); 1011 Log.v(TAG, "mainEvents(" + mainEvents.size() + "): " + mainEvents); 1012 1013 // Logs events before asserting 1014 final Session childTestSession1 = service.getFinishedSession(childSessionId1); 1015 assertChildSessionContext(childTestSession1, "session1"); 1016 final List<ContentCaptureEvent> events1 = childTestSession1.getEvents(); 1017 Log.v(TAG, "events1(" + events1.size() + "): " + events1); 1018 final Session childTestSession2 = service.getFinishedSession(childSessionId2); 1019 final List<ContentCaptureEvent> events2 = childTestSession2.getEvents(); 1020 assertChildSessionContext(childTestSession2, "session2"); 1021 Log.v(TAG, "events2(" + events2.size() + "): " + events2); 1022 1023 // Assert children 1024 assertThat(events1.size()).isAtLeast(6); 1025 final AutofillId rootId = rootView.getAutofillId(); 1026 assertViewTreeStarted(events1, 0); 1027 assertViewAppeared(events1, 1, s1c1, rootId); 1028 assertViewTreeFinished(events1, 2); 1029 assertViewTreeStarted(events1, 3); 1030 assertViewDisappeared(events1, 4, s1c1Id); 1031 assertViewTreeFinished(events1, 5); 1032 1033 assertThat(events2.size()).isAtLeast(7); 1034 assertViewTreeStarted(events2, 0); 1035 assertViewAppeared(events2, 1, s2c1, rootId); 1036 assertViewAppeared(events2, 2, s2c2, rootId); 1037 assertViewTreeFinished(events2, 3); 1038 assertViewTreeStarted(events2, 4); 1039 assertViewsDisappeared(events2, 5, s2c1Id, s2c2Id); 1040 assertViewTreeFinished(events2, 6); 1041 } 1042 1043 /* TODO(b/119638528): add more scenarios for nested sessions, such as: 1044 * - add views to the children sessions 1045 * - s1 -> s2 -> s3 and main -> s4; close(s1) then generate events on view from s3 1046 * - s1 -> s2 -> s3 and main -> s4; close(s2) then generate events on view from s3 1047 * - s1 -> s2 and s3->s4 -> s4 1048 * - etc 1049 */ 1050 1051 private enum DisabledReason { 1052 BY_API, 1053 BY_SETTINGS, 1054 BY_DEVICE_CONFIG 1055 } 1056 setFeatureEnabled(@onNull CtsContentCaptureService service, @NonNull DisabledReason reason, boolean enabled)1057 private void setFeatureEnabled(@NonNull CtsContentCaptureService service, 1058 @NonNull DisabledReason reason, 1059 boolean enabled) { 1060 switch (reason) { 1061 case BY_API: 1062 if (enabled) { 1063 // The service cannot re-enable itself, so we use settings instead. 1064 setFeatureEnabledBySettings(true); 1065 } else { 1066 service.disableSelf(); 1067 } 1068 break; 1069 case BY_SETTINGS: 1070 setFeatureEnabledBySettings(enabled); 1071 break; 1072 case BY_DEVICE_CONFIG: 1073 setFeatureEnabledByDeviceConfig(Boolean.toString(enabled)); 1074 break; 1075 default: 1076 throw new IllegalArgumentException("invalid reason: " + reason); 1077 } 1078 } 1079 1080 @Test testIsContentCaptureFeatureEnabled_notService()1081 public void testIsContentCaptureFeatureEnabled_notService() throws Exception { 1082 final ContentCaptureManager mgr = getContentCaptureManagerHack(); 1083 assertThrows(SecurityException.class, () -> mgr.isContentCaptureFeatureEnabled()); 1084 } 1085 1086 @Test testSetContentCaptureFeatureEnabled_disabledBySettings()1087 public void testSetContentCaptureFeatureEnabled_disabledBySettings() throws Exception { 1088 setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_SETTINGS); 1089 } 1090 setContentCaptureFeatureEnabledTest_disabled(@onNull DisabledReason reason)1091 private void setContentCaptureFeatureEnabledTest_disabled(@NonNull DisabledReason reason) 1092 throws Exception { 1093 final ContentCaptureManager mgr = getContentCaptureManagerHack(); 1094 1095 final CtsContentCaptureService service = enableService(); 1096 assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue(); 1097 final DisconnectListener disconnectedListener = service.setOnDisconnectListener(); 1098 1099 setFeatureEnabled(service, reason, /* enabled= */ false); 1100 1101 disconnectedListener.waitForOnDisconnected(); 1102 assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse(); 1103 assertThat(mgr.isContentCaptureEnabled()).isFalse(); 1104 1105 final ActivityWatcher watcher = startWatcher(); 1106 final ChildlessActivity activity = launchActivity(); 1107 1108 watcher.waitFor(RESUMED); 1109 activity.finish(); 1110 watcher.waitFor(DESTROYED); 1111 1112 assertThat(service.getAllSessionIds()).isEmpty(); 1113 } 1114 1115 @Test testSetContentCaptureFeatureEnabled_disabledThenReEnabledBySettings()1116 public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledBySettings() 1117 throws Exception { 1118 setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_SETTINGS); 1119 } 1120 setContentCaptureFeatureEnabledTest_disabledThenReEnabled( @onNull DisabledReason reason)1121 private void setContentCaptureFeatureEnabledTest_disabledThenReEnabled( 1122 @NonNull DisabledReason reason) throws Exception { 1123 final ContentCaptureManager mgr = getContentCaptureManagerHack(); 1124 1125 final CtsContentCaptureService service1 = enableService(); 1126 assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue(); 1127 final DisconnectListener disconnectedListener = service1.setOnDisconnectListener(); 1128 1129 setFeatureEnabled(service1, reason, /* enabled= */ false); 1130 disconnectedListener.waitForOnDisconnected(); 1131 1132 assertThat(mgr.isContentCaptureFeatureEnabled()).isFalse(); 1133 assertThat(mgr.isContentCaptureEnabled()).isFalse(); 1134 1135 // Launch and finish 1st activity while it's disabled 1136 final ActivityWatcher watcher1 = startWatcher(); 1137 final ChildlessActivity activity1 = launchActivity(); 1138 watcher1.waitFor(RESUMED); 1139 activity1.finish(); 1140 watcher1.waitFor(DESTROYED); 1141 1142 // Re-enable feature 1143 final ServiceWatcher reconnectionWatcher = CtsContentCaptureService.setServiceWatcher(); 1144 reconnectionWatcher.whitelistSelf(); 1145 setFeatureEnabled(service1, reason, /* enabled= */ true); 1146 final CtsContentCaptureService service2 = reconnectionWatcher.waitOnCreate(); 1147 assertThat(mgr.isContentCaptureFeatureEnabled()).isTrue(); 1148 1149 // Launch and finish 2nd activity while it's enabled 1150 final ActivityLauncher<CustomViewActivity> launcher2 = new ActivityLauncher<>( 1151 sContext, mActivitiesWatcher, CustomViewActivity.class); 1152 final ActivityWatcher watcher2 = launcher2.getWatcher(); 1153 final CustomViewActivity activity2 = launcher2.launchActivity(); 1154 watcher2.waitFor(RESUMED); 1155 activity2.finish(); 1156 watcher2.waitFor(DESTROYED); 1157 1158 assertThat(service1.getAllSessionIds()).isEmpty(); 1159 final Session session = service2.getOnlyFinishedSession(); 1160 activity2.assertDefaultEvents(session); 1161 } 1162 1163 @Test testSetContentCaptureFeatureEnabled_disabledByApi()1164 public void testSetContentCaptureFeatureEnabled_disabledByApi() throws Exception { 1165 setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_API); 1166 } 1167 1168 @Test testSetContentCaptureFeatureEnabled_disabledThenReEnabledByApi()1169 public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByApi() 1170 throws Exception { 1171 setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_API); 1172 } 1173 1174 @Test testSetContentCaptureFeatureEnabled_disabledByDeviceConfig()1175 public void testSetContentCaptureFeatureEnabled_disabledByDeviceConfig() throws Exception { 1176 setContentCaptureFeatureEnabledTest_disabled(DisabledReason.BY_DEVICE_CONFIG); 1177 // Reset service, otherwise it will reconnect when the deviceConfig value is reset 1178 // on cleanup, which will cause the test to fail 1179 Helper.resetService(); 1180 } 1181 1182 @Test testSetContentCaptureFeatureEnabled_disabledThenReEnabledByDeviceConfig()1183 public void testSetContentCaptureFeatureEnabled_disabledThenReEnabledByDeviceConfig() 1184 throws Exception { 1185 setContentCaptureFeatureEnabledTest_disabledThenReEnabled(DisabledReason.BY_DEVICE_CONFIG); 1186 // Reset service, otherwise it will reconnect when the deviceConfig value is reset 1187 // on cleanup, which will cause the test to fail 1188 Helper.resetService(); 1189 } 1190 1191 // TODO(b/123406031): add tests that mix feature_enabled with user_restriction_enabled (and 1192 // make sure mgr.isContentCaptureFeatureEnabled() returns only the state of the 1st) 1193 addChild(@onNull ChildlessActivity activity, @NonNull ContentCaptureSession session, @NonNull String text)1194 private TextView addChild(@NonNull ChildlessActivity activity, 1195 @NonNull ContentCaptureSession session, @NonNull String text) { 1196 final TextView child = newImportantView(activity, text); 1197 child.setContentCaptureSession(session); 1198 Log.i(TAG, "adding " + child.getAutofillId() + " on session " 1199 + session.getContentCaptureSessionId()); 1200 activity.runOnUiThread(() -> activity.getRootView().addView(child)); 1201 return child; 1202 } 1203 1204 // TODO(b/123024698): these method are used in cases where we cannot close a session because we 1205 // would miss intermediate events, so we need to sleep. This is a hack (it's slow and flaky): 1206 // ideally we should block and wait until the service receives the event, but right now 1207 // we don't get the service events until after the activity is finished, so we cannot do that... waitAndClose(@onNull ContentCaptureSession session)1208 private void waitAndClose(@NonNull ContentCaptureSession session) { 1209 Log.d(TAG, "sleeping before closing " + session.getContentCaptureSessionId()); 1210 sleep(); 1211 session.close(); 1212 } 1213 waitAndRemoveViews(@onNull ChildlessActivity activity, @NonNull View... views)1214 private void waitAndRemoveViews(@NonNull ChildlessActivity activity, @NonNull View... views) { 1215 Log.d(TAG, "sleeping before removing " + Arrays.toString(views)); 1216 sleep(); 1217 activity.syncRunOnUiThread(() -> { 1218 for (View view : views) { 1219 activity.getRootView().removeView(view); 1220 } 1221 }); 1222 } 1223 sleep()1224 private void sleep() { 1225 Log.d(TAG, "sleeping for 1s "); 1226 SystemClock.sleep(1_000); 1227 } 1228 1229 // TODO(b/120494182): temporary hack to get the manager, which currently is only available on 1230 // Activity contexts (and would be null from sContext) 1231 @NonNull getContentCaptureManagerHack()1232 private ContentCaptureManager getContentCaptureManagerHack() throws InterruptedException { 1233 final AtomicReference<ContentCaptureManager> ref = new AtomicReference<>(); 1234 LoginActivity.onRootView( 1235 (activity, rootView) -> ref.set(activity.getContentCaptureManager())); 1236 1237 final ActivityLauncher<LoginActivity> launcher = new ActivityLauncher<>( 1238 sContext, mActivitiesWatcher, LoginActivity.class); 1239 final ActivityWatcher watcher = launcher.getWatcher(); 1240 final LoginActivity activity = launcher.launchActivity(); 1241 watcher.waitFor(RESUMED); 1242 activity.finish(); 1243 watcher.waitFor(DESTROYED); 1244 1245 final ContentCaptureManager mgr = ref.get(); 1246 assertThat(mgr).isNotNull(); 1247 1248 return mgr; 1249 } 1250 setFeatureEnabledByDeviceConfig(@ullable String value)1251 private void setFeatureEnabledByDeviceConfig(@Nullable String value) { 1252 Log.d(TAG, "setFeatureEnabledByDeviceConfig(): " + value); 1253 1254 sKillSwitchManager.set(value); 1255 } 1256 1257 @NonNull newContentCaptureContextBuilder(@onNull String id)1258 private ContentCaptureContext.Builder newContentCaptureContextBuilder(@NonNull String id) { 1259 return new ContentCaptureContext.Builder(new LocusId(id)); 1260 } 1261 } 1262