| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package android.contentcaptureservice.cts; |
| |
| import static android.contentcaptureservice.cts.Assertions.assertRightActivity; |
| import static android.contentcaptureservice.cts.Helper.MY_PACKAGE; |
| import static android.contentcaptureservice.cts.Helper.NO_ACTIVITIES; |
| import static android.contentcaptureservice.cts.Helper.OTHER_PACKAGE; |
| import static android.contentcaptureservice.cts.Helper.await; |
| import static android.contentcaptureservice.cts.Helper.eventually; |
| import static android.contentcaptureservice.cts.Helper.toSet; |
| import static android.view.contentcapture.ContentCaptureCondition.FLAG_IS_REGEX; |
| |
| import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED; |
| import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| |
| import android.content.LocusId; |
| import android.contentcaptureservice.cts.CtsContentCaptureService.Session; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.platform.test.annotations.AppModeFull; |
| import android.util.ArraySet; |
| import android.util.Log; |
| import android.view.View; |
| import android.view.ViewStructure; |
| import android.view.WindowManager; |
| import android.view.autofill.AutofillId; |
| import android.view.contentcapture.ContentCaptureCondition; |
| import android.view.contentcapture.ContentCaptureContext; |
| import android.view.contentcapture.ContentCaptureEvent; |
| import android.view.contentcapture.ContentCaptureManager; |
| import android.view.contentcapture.ContentCaptureSession; |
| import android.view.contentcapture.ContentCaptureSessionId; |
| |
| import androidx.annotation.NonNull; |
| import androidx.test.rule.ActivityTestRule; |
| |
| import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher; |
| import com.android.compatibility.common.util.DoubleVisitor; |
| |
| import org.junit.Test; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.atomic.AtomicReference; |
| |
| @AppModeFull(reason = "BlankWithTitleActivityTest is enough") |
| public class CustomViewActivityTest extends |
| AbstractContentCaptureIntegrationAutoActivityLaunchTest<CustomViewActivity> { |
| |
| private static final String TAG = CustomViewActivityTest.class.getSimpleName(); |
| |
| private static final ActivityTestRule<CustomViewActivity> sActivityRule = |
| new ActivityTestRule<>(CustomViewActivity.class, false, false); |
| |
| public CustomViewActivityTest() { |
| super(CustomViewActivity.class); |
| } |
| |
| @Override |
| protected ActivityTestRule<CustomViewActivity> getActivityTestRule() { |
| return sActivityRule; |
| } |
| |
| /** |
| * Baseline / initial check test for the other tests. |
| */ |
| @Test |
| public void testLifecycle() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| activity.assertDefaultEvents(session); |
| } |
| |
| /** |
| * Test for session lifecycle events. |
| */ |
| @Test |
| public void testSessionLifecycleEvents() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| final AtomicReference<CustomView> customViewRef = new AtomicReference<>(); |
| |
| CustomViewActivity.setCustomViewDelegate((customView, structure) -> { |
| customViewRef.set(customView); |
| final ContentCaptureSession session = customView.getContentCaptureSession(); |
| session.notifySessionResumed(); |
| session.notifySessionPaused(); |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| assertRightActivity(session, session.id, activity); |
| |
| final View grandpa1 = (View) activity.mCustomView.getParent(); |
| final View grandpa2 = (View) grandpa1.getParent(); |
| final View decorView = activity.getDecorView(); |
| final AutofillId customViewId = activity.mCustomView.getAutofillId(); |
| Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId() |
| + ", grandpa2=" + grandpa2.getAutofillId() + ", decor=" |
| + decorView.getAutofillId() + "customView=" + customViewId); |
| |
| final List<ContentCaptureEvent> events = session.getEvents(); |
| Log.v(TAG, "events(" + events.size() + "): " + events); |
| final int additionalEvents = 2; |
| |
| new EventsAssertor(events) |
| .isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents) |
| .assertSessionResumed() |
| .assertViewTreeStarted() |
| .assertDecorViewAppeared(decorView) |
| .assertViewAppeared(grandpa2, decorView.getAutofillId()) |
| .assertViewAppeared(grandpa1, grandpa2.getAutofillId()) |
| // Assert for session lifecycle events. |
| .assertSessionResumed() |
| .assertSessionPaused() |
| .assertViewAppeared(session.id, customViewRef.get()) |
| .assertViewTreeFinished() |
| .assertSessionPaused(); |
| } |
| |
| /** |
| * Tests when the view has virtual children but it doesn't return right away and calls |
| * the session notification methods instead - this is wrong because the main view will be |
| * notified last, but we cannot prevent the apps from doing so... |
| */ |
| @Test |
| public void testVirtualView_wrongWay() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| CustomViewActivity.setCustomViewDelegate((customView, structure) -> { |
| Log.d(TAG, "delegate running on " + Thread.currentThread()); |
| final AutofillId customViewId = customView.getAutofillId(); |
| Log.d(TAG, "customViewId: " + customViewId); |
| final ContentCaptureSession session = customView.getContentCaptureSession(); |
| |
| final ViewStructure child = session.newVirtualViewStructure(customViewId, 1); |
| child.setText("child"); |
| final AutofillId childId = child.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 1)).isEqualTo(childId); |
| Log.d(TAG, "nofifying child appeared: " + childId); |
| session.notifyViewAppeared(child); |
| |
| Log.d(TAG, "nofifying child disappeared: " + childId); |
| session.notifyViewDisappeared(childId); |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| assertRightActivity(session, session.id, activity); |
| |
| final View grandpa1 = (View) activity.mCustomView.getParent(); |
| final View grandpa2 = (View) grandpa1.getParent(); |
| final View decorView = activity.getDecorView(); |
| final AutofillId customViewId = activity.mCustomView.getAutofillId(); |
| Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId() |
| + ", grandpa2=" + grandpa2.getAutofillId() + ", decor=" |
| + decorView.getAutofillId() + "customView=" + customViewId); |
| |
| final List<ContentCaptureEvent> events = session.getEvents(); |
| Log.v(TAG, "events(" + events.size() + "): " + events); |
| final int additionalEvents = 2; |
| final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession(); |
| |
| new EventsAssertor(events) |
| .isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents) |
| .assertSessionResumed() |
| .assertViewTreeStarted() |
| .assertDecorViewAppeared(decorView) |
| .assertViewAppeared(grandpa2, decorView.getAutofillId()) |
| .assertViewAppeared(grandpa1, grandpa2.getAutofillId()) |
| .assertVirtualViewAppeared(mainSession, customViewId, 1, "child") |
| .assertVirtualViewDisappeared(customViewId, mainSession, 1) |
| .assertViewAppeared(session.id, activity.mCustomView) |
| .assertViewTreeFinished() |
| .assertSessionPaused(); |
| } |
| |
| /** |
| * Tests when the view has virtual children, but those children are leaf nodes. |
| */ |
| @Test |
| public void testVirtualView_oneLevel() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final AtomicReference<AutofillId> child2IdRef = new AtomicReference<>(); |
| final CountDownLatch asyncLatch = setAsyncDelegate((customView, structure) -> { |
| Log.d(TAG, "delegate running on " + Thread.currentThread()); |
| final AutofillId customViewId = customView.getAutofillId(); |
| Log.d(TAG, "customViewId: " + customViewId); |
| final ContentCaptureSession session = customView.getContentCaptureSession(); |
| |
| final ViewStructure child1 = session.newVirtualViewStructure(customViewId, 1); |
| child1.setText("child1"); |
| final AutofillId child1Id = child1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 1)).isEqualTo(child1Id); |
| Log.d(TAG, "nofifying child1 appeared: " + child1Id); |
| session.notifyViewAppeared(child1); |
| final ViewStructure child2 = session.newVirtualViewStructure(customViewId, 2); |
| child2.setText("child2"); |
| final AutofillId child2Id = child2.getAutofillId(); |
| child2IdRef.set(child2Id); |
| assertThat(session.newAutofillId(customViewId, 2)).isEqualTo(child2Id); |
| Log.d(TAG, "nofifying child2 appeared: " + child2Id); |
| session.notifyViewAppeared(child2); |
| |
| Log.d(TAG, "nofifying child2 text changed"); |
| session.notifyViewTextChanged(child2Id, "The Times They Are a-Changin'"); |
| |
| Log.d(TAG, "nofifying child2 disappeared: " + child2Id); |
| session.notifyViewDisappeared(child2Id); |
| Log.d(TAG, "nofifying child1 disappeared: " + child1Id); |
| session.notifyViewDisappeared(child1Id); |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| await(asyncLatch, "async onProvide"); |
| |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| assertRightActivity(session, session.id, activity); |
| |
| final int additionalEvents = 3; |
| final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session, |
| additionalEvents); |
| |
| final AutofillId customViewId = activity.mCustomView.getAutofillId(); |
| final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession(); |
| |
| new EventsAssertor(events) |
| .assertVirtualViewAppeared(mainSession, customViewId, 1, "child1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 2, "child2") |
| .assertViewTextChanged(child2IdRef.get(), "The Times They Are a-Changin'") |
| .assertVirtualViewsDisappeared(customViewId, mainSession, 2, 1); |
| // TODO(b/122315042): assert views disappeared |
| } |
| |
| /** |
| * Tests when the view has virtual children, and some of those children have children too. |
| */ |
| @Test |
| public void testVirtualView_multipleLevels() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final CountDownLatch asyncLatch = setAsyncDelegate((customView, structure) -> { |
| Log.d(TAG, "delegate running on " + Thread.currentThread()); |
| final AutofillId customViewId = customView.getAutofillId(); |
| Log.d(TAG, "customViewId: " + customViewId); |
| final ContentCaptureSession session = customView.getContentCaptureSession(); |
| |
| // Child 1 |
| final ViewStructure c1 = session.newVirtualViewStructure(customViewId, 1); |
| c1.setText("c1"); |
| final AutofillId c1Id = c1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 1)).isEqualTo(c1Id); |
| Log.d(TAG, "nofifying c1 appeared: " + c1Id); |
| session.notifyViewAppeared(c1); |
| |
| // Child 1, grandchildren 1 |
| final ViewStructure c1g1 = session.newVirtualViewStructure(c1Id, 11); |
| c1g1.setText("c1g1"); |
| final AutofillId c1g1Id = c1g1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 11)).isEqualTo(c1g1Id); |
| Log.d(TAG, "nofifying c1g1 appeared: " + c1g1Id); |
| session.notifyViewAppeared(c1g1); |
| |
| // Child 1, grandchildren 2 |
| final ViewStructure c1g2 = session.newVirtualViewStructure(c1Id, 12); |
| c1g2.setText("c1g2"); |
| final AutofillId c1g2Id = c1g2.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 12)).isEqualTo(c1g2Id); |
| Log.d(TAG, "nofifying c1g2 appeared: " + c1g2Id); |
| session.notifyViewAppeared(c1g2); |
| |
| final ViewStructure c2 = session.newVirtualViewStructure(customViewId, 2); |
| c2.setText("c2"); |
| final AutofillId c2Id = c2.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 2)).isEqualTo(c2Id); |
| Log.d(TAG, "nofifying c2 appeared: " + c2Id); |
| session.notifyViewAppeared(c2); |
| |
| // Child 2, grandchildren 1 - not removed |
| final ViewStructure c2g1 = session.newVirtualViewStructure(c2Id, 21); |
| c2g1.setText("c2g1"); |
| final AutofillId c2g1Id = c2g1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 21)).isEqualTo(c2g1Id); |
| Log.d(TAG, "nofifying c2g1 appeared: " + c2g1Id); |
| session.notifyViewAppeared(c2g1); |
| |
| // Child 2, grandchildren 1, grandgrandchild1 (on purpose) |
| final ViewStructure c2g1gg1 = session.newVirtualViewStructure(c2g1Id, |
| 211); |
| c2g1gg1.setText("c2g1gg1"); |
| final AutofillId c2g1ggt1Id = c2g1gg1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 211)).isEqualTo(c2g1ggt1Id); |
| Log.d(TAG, "nofifying c2g1gg1 appeared: " + c2g1ggt1Id); |
| session.notifyViewAppeared(c2g1gg1); |
| |
| // Child 3 - not removed (on purpose) |
| final ViewStructure c3 = session.newVirtualViewStructure(customViewId, 3); |
| c3.setText("c3"); |
| final AutofillId c3Id = c3.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 3)).isEqualTo(c3Id); |
| Log.d(TAG, "nofifying c3 appeared: " + c3Id); |
| session.notifyViewAppeared(c3); |
| |
| // Remove children (although not all of them, on purpose) |
| Log.d(TAG, "nofifying c2g1 disappeared: " + c2g1Id); |
| session.notifyViewDisappeared(c2g1Id); |
| Log.d(TAG, "nofifying c2 disappeared: " + c2Id); |
| session.notifyViewDisappeared(c2Id); |
| // Remove child1 grandchildren before and after |
| Log.d(TAG, "nofifying c1g1 disappeared: " + c1g1Id); |
| session.notifyViewDisappeared(c1g1Id); |
| Log.d(TAG, "nofifying c1 disappeared: " + c1Id); |
| session.notifyViewDisappeared(c1Id); |
| Log.d(TAG, "nofifying c1g2 disappeared: " + c1g2Id); |
| session.notifyViewDisappeared(c1g2Id); |
| |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| await(asyncLatch, "async onProvide"); |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| assertRightActivity(session, session.id, activity); |
| |
| final int additionalEvents = 7; |
| final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session, |
| additionalEvents); |
| |
| final AutofillId customViewId = activity.mCustomView.getAutofillId(); |
| final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession(); |
| |
| new EventsAssertor(events) |
| .assertVirtualViewAppeared(mainSession, customViewId, 1, "c1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 11, "c1g1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 12, "c1g2") |
| .assertVirtualViewAppeared(mainSession, customViewId, 2, "c2") |
| .assertVirtualViewAppeared(mainSession, customViewId, 21, "c2g1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 211, "c2g1gg1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 3, "c3") |
| .assertVirtualViewsDisappeared(customViewId, mainSession, 21, 2, 11, 1, 12); |
| // TODO(b/122315042): assert other views disappeared |
| } |
| |
| // TODO(b/123540602): add tests for multiple sessions |
| |
| @Test |
| public void testVirtualView_batchDisappear() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final CountDownLatch asyncLatch = setAsyncDelegate((customView, structure) -> { |
| Log.d(TAG, "delegate running on " + Thread.currentThread()); |
| final AutofillId customViewId = customView.getAutofillId(); |
| Log.d(TAG, "customViewId: " + customViewId); |
| final ContentCaptureSession session = customView.getContentCaptureSession(); |
| |
| final ViewStructure child1 = session.newVirtualViewStructure(customViewId, 1); |
| child1.setText("child1"); |
| final AutofillId child1Id = child1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 1)).isEqualTo(child1Id); |
| Log.d(TAG, "nofifying child1 appeared: " + child1Id); |
| session.notifyViewAppeared(child1); |
| |
| final ViewStructure child2 = session.newVirtualViewStructure(customViewId, 2); |
| child2.setText("child2"); |
| final AutofillId child2Id = child2.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 2)).isEqualTo(child2Id); |
| Log.d(TAG, "nofifying child2 appeared: " + child2Id); |
| session.notifyViewAppeared(child2); |
| |
| final long[] childrenIds = {2, 1}; |
| Log.d(TAG, "nofifying both children disappeared: " + Arrays.toString(childrenIds)); |
| session.notifyViewsDisappeared(customViewId, childrenIds); |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| await(asyncLatch, "async onProvide"); |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| assertRightActivity(session, session.id, activity); |
| |
| |
| final int additionalEvents = 5; |
| final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session, |
| additionalEvents); |
| |
| final AutofillId customViewId = activity.mCustomView.getAutofillId(); |
| final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession(); |
| |
| new EventsAssertor(events) |
| .assertVirtualViewAppeared(mainSession, customViewId, 1, "child1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 2, "child2") |
| .assertViewTreeStarted() |
| .assertVirtualViewsDisappeared(customViewId, mainSession, 2, 1) |
| .assertViewTreeFinished(); |
| // TODO(b/122315042): assert other views disappeared |
| } |
| |
| @Test |
| public void testVirtualView_batchAppear() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final CountDownLatch asyncLatch = setAsyncDelegate((customView, structure) -> { |
| Log.d(TAG, "delegate running on " + Thread.currentThread()); |
| final AutofillId customViewId = customView.getAutofillId(); |
| Log.d(TAG, "customViewId: " + customViewId); |
| final ContentCaptureSession session = customView.getContentCaptureSession(); |
| |
| final ViewStructure child1 = session.newVirtualViewStructure(customViewId, 1); |
| child1.setText("child1"); |
| final AutofillId child1Id = child1.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 1)).isEqualTo(child1Id); |
| |
| final ViewStructure child2 = session.newVirtualViewStructure(customViewId, 2); |
| child2.setText("child2"); |
| final AutofillId child2Id = child2.getAutofillId(); |
| assertThat(session.newAutofillId(customViewId, 2)).isEqualTo(child2Id); |
| Log.d(TAG, "nofifying children appeared"); |
| final List<ViewStructure> appearedNodes = new ArrayList<>(); |
| appearedNodes.add(child1); |
| appearedNodes.add(child2); |
| session.notifyViewsAppeared(appearedNodes); |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| await(asyncLatch, "async onProvide"); |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| Log.v(TAG, "session id: " + session.id); |
| |
| assertRightActivity(session, session.id, activity); |
| |
| final int additionalEvents = 4; |
| final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session, |
| additionalEvents); |
| |
| final AutofillId customViewId = activity.mCustomView.getAutofillId(); |
| final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession(); |
| |
| new EventsAssertor(events) |
| .assertViewTreeStarted() |
| .assertVirtualViewAppeared(mainSession, customViewId, 1, "child1") |
| .assertVirtualViewAppeared(mainSession, customViewId, 2, "child2") |
| .assertViewTreeFinished(); |
| } |
| |
| @Test |
| public void testContentCaptureConditions() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final Set<ContentCaptureCondition> conditions = new ArraySet<>(1); |
| final LocusId locusId = new LocusId("Locus At me!"); |
| conditions.add(new ContentCaptureCondition(locusId, FLAG_IS_REGEX)); |
| service.setContentCaptureConditions(MY_PACKAGE, conditions); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| final ContentCaptureManager mgr = activity.getContentCaptureManager(); |
| final Set<ContentCaptureCondition> actualConditions = mgr.getContentCaptureConditions(); |
| assertThat(actualConditions).isNotNull(); |
| assertThat(actualConditions).hasSize(1); |
| |
| final ContentCaptureCondition actualCondition = actualConditions.iterator().next(); |
| assertThat(actualCondition).isNotNull(); |
| assertThat(actualCondition.getLocusId()).isEqualTo(locusId); |
| assertThat(actualCondition.getFlags()).isEqualTo(FLAG_IS_REGEX); |
| } |
| |
| @Test |
| public void testContentCaptureConditions_otherPackage() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final Set<ContentCaptureCondition> conditions = new ArraySet<>(1); |
| final LocusId locusId = new LocusId("Locus At me!"); |
| conditions.add(new ContentCaptureCondition(locusId, FLAG_IS_REGEX)); |
| service.setContentCaptureConditions(OTHER_PACKAGE, conditions); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| final ContentCaptureManager mgr = activity.getContentCaptureManager(); |
| final Set<ContentCaptureCondition> actualConditions = mgr.getContentCaptureConditions(); |
| assertThat(actualConditions).isNull(); |
| } |
| |
| @Test |
| public void testContentCaptureEnabled_dynamicFlagSecure() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| final ContentCaptureManager mgr = activity.getContentCaptureManager(); |
| assertThat(mgr.isContentCaptureEnabled()).isTrue(); |
| |
| activity.syncRunOnUiThread(() -> { |
| activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); |
| }); |
| |
| eventually("Waiting for flag secure to be disabled", |
| () -> mgr.isContentCaptureEnabled() ? null : "not_used"); |
| |
| activity.syncRunOnUiThread(() -> { |
| activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); |
| }); |
| |
| eventually("Waiting for flag secure to be re-enabled", |
| () -> mgr.isContentCaptureEnabled() ? "not_used" : null); |
| } |
| |
| @Test |
| public void testDisabledByFlagSecure() throws Exception { |
| final CtsContentCaptureService service = enableService(); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| CustomViewActivity.onRootView((activity) -> { |
| activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); |
| }); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| final ContentCaptureManager mgr = activity.getContentCaptureManager(); |
| assertThat(mgr.isContentCaptureEnabled()).isFalse(); |
| |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| |
| final Session session = service.getOnlyFinishedSession(); |
| assertThat((session.context.getFlags() |
| & ContentCaptureContext.FLAG_DISABLED_BY_FLAG_SECURE) != 0).isTrue(); |
| |
| final ContentCaptureSessionId sessionId = session.id; |
| assertRightActivity(session, sessionId, activity); |
| |
| final List<ContentCaptureEvent> events = session.getEvents(); |
| assertThat(events).isEmpty(); |
| } |
| |
| @Test |
| public void testDisabledAfterLaunched() throws Exception { |
| // Explicitly enable package so it doesn't havea a "lite" ContentCaptureOptions |
| final CtsContentCaptureService service = enableService(toSet(MY_PACKAGE), NO_ACTIVITIES); |
| final ActivityWatcher watcher = startWatcher(); |
| |
| final CustomViewActivity activity = launchActivity(); |
| watcher.waitFor(RESUMED); |
| |
| final ContentCaptureManager mgr = activity.getContentCaptureManager(); |
| eventually("isContentCaptureEnabled() is not true yet", |
| () -> mgr.isContentCaptureEnabled() ? "not_used" : null); |
| |
| service.setContentCaptureWhitelist(/* packages= */ null, /* activities= */ null); |
| |
| eventually("isContentCaptureEnabled() is still true", |
| () -> mgr.isContentCaptureEnabled() ? null : "not_used"); |
| |
| activity.finish(); |
| watcher.waitFor(DESTROYED); |
| } |
| |
| /** |
| * Sets a delegate that will generate the events asynchronously, |
| * after {@code onProvideContentCaptureStructure()} returns. |
| */ |
| private CountDownLatch setAsyncDelegate( |
| @NonNull DoubleVisitor<CustomView, ViewStructure> delegate) { |
| final CountDownLatch asyncLatch = new CountDownLatch(1); |
| CustomViewActivity.setCustomViewDelegate( |
| (customView, structure) -> new Handler(Looper.getMainLooper()) |
| .post(() -> { |
| delegate.visit(customView, structure); |
| asyncLatch.countDown(); |
| })); |
| return asyncLatch; |
| } |
| } |