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