Loading core/java/android/view/contentcapture/MainContentCaptureSessionV2.java +5 −2 Original line number Diff line number Diff line Loading @@ -149,9 +149,12 @@ public final class MainContentCaptureSessionV2 extends ContentCaptureSession { * * Because it is not guaranteed that the events will be enqueued from a single thread, the * implementation must be thread-safe to prevent unexpected behaviour. * * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull private final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue; public final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue; /** * List of events held to be sent to the {@link ContentCaptureService} as a batch. Loading Loading @@ -908,7 +911,7 @@ public final class MainContentCaptureSessionV2 extends ContentCaptureSession { * clear the buffer events then starting sending out current event. */ private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) { if (forceFlush) { if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) { // The buffer events are cleared in the same thread first to prevent new events // being added during the time of context switch. This would disrupt the sequence // of events. Loading core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java +66 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,72 @@ public class MainContentCaptureSessionV2Test { assertThat(session.mEvents).isEmpty(); } @Test public void notifyViewAppearedBelowMaximumBufferSize() throws RemoteException { ContentCaptureOptions options = createOptions( /* enableContentCaptureReceiver= */ true, /* enableContentProtectionReceiver= */ true); MainContentCaptureSessionV2 session = createSession(options); session.mDirectServiceInterface = mMockContentCaptureDirectManager; session.onSessionStarted(0x2, null); for (int i = 0; i < BUFFER_SIZE - 1; i++) { View view = prepareView(session); session.notifyViewAppeared(session.newViewStructure(view)); } mTestableLooper.processAllMessages(); verify(mMockContentCaptureDirectManager, times(0)) .sendEvents(any(), anyInt(), any()); assertThat(session.mEvents).isNull(); assertThat(session.mEventProcessQueue).hasSize(BUFFER_SIZE - 1); } @Test public void notifyViewAppearedExactAsMaximumBufferSize() throws RemoteException { ContentCaptureOptions options = createOptions( /* enableContentCaptureReceiver= */ true, /* enableContentProtectionReceiver= */ true); MainContentCaptureSessionV2 session = createSession(options); session.mDirectServiceInterface = mMockContentCaptureDirectManager; session.onSessionStarted(0x2, null); for (int i = 0; i < BUFFER_SIZE; i++) { View view = prepareView(session); session.notifyViewAppeared(session.newViewStructure(view)); } mTestableLooper.processAllMessages(); verify(mMockContentCaptureDirectManager, times(1)) .sendEvents(any(), anyInt(), any()); assertThat(session.mEvents).isEmpty(); assertThat(session.mEventProcessQueue).isEmpty(); } @Test public void notifyViewAppearedAboveMaximumBufferSize() throws RemoteException { ContentCaptureOptions options = createOptions( /* enableContentCaptureReceiver= */ true, /* enableContentProtectionReceiver= */ true); MainContentCaptureSessionV2 session = createSession(options); session.mDirectServiceInterface = mMockContentCaptureDirectManager; session.onSessionStarted(0x2, null); for (int i = 0; i < BUFFER_SIZE * 2 + 1; i++) { View view = prepareView(session); session.notifyViewAppeared(session.newViewStructure(view)); } mTestableLooper.processAllMessages(); verify(mMockContentCaptureDirectManager, times(2)) .sendEvents(any(), anyInt(), any()); assertThat(session.mEvents).isEmpty(); assertThat(session.mEventProcessQueue).hasSize(1); } /** Simulates the regular content capture events sequence. */ private void notifyContentCaptureEvents(final MainContentCaptureSessionV2 session) { final ArrayList<Object> events = new ArrayList<>( Loading Loading
core/java/android/view/contentcapture/MainContentCaptureSessionV2.java +5 −2 Original line number Diff line number Diff line Loading @@ -149,9 +149,12 @@ public final class MainContentCaptureSessionV2 extends ContentCaptureSession { * * Because it is not guaranteed that the events will be enqueued from a single thread, the * implementation must be thread-safe to prevent unexpected behaviour. * * @hide */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @NonNull private final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue; public final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue; /** * List of events held to be sent to the {@link ContentCaptureService} as a batch. Loading Loading @@ -908,7 +911,7 @@ public final class MainContentCaptureSessionV2 extends ContentCaptureSession { * clear the buffer events then starting sending out current event. */ private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) { if (forceFlush) { if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) { // The buffer events are cleared in the same thread first to prevent new events // being added during the time of context switch. This would disrupt the sequence // of events. Loading
core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionV2Test.java +66 −0 Original line number Diff line number Diff line Loading @@ -433,6 +433,72 @@ public class MainContentCaptureSessionV2Test { assertThat(session.mEvents).isEmpty(); } @Test public void notifyViewAppearedBelowMaximumBufferSize() throws RemoteException { ContentCaptureOptions options = createOptions( /* enableContentCaptureReceiver= */ true, /* enableContentProtectionReceiver= */ true); MainContentCaptureSessionV2 session = createSession(options); session.mDirectServiceInterface = mMockContentCaptureDirectManager; session.onSessionStarted(0x2, null); for (int i = 0; i < BUFFER_SIZE - 1; i++) { View view = prepareView(session); session.notifyViewAppeared(session.newViewStructure(view)); } mTestableLooper.processAllMessages(); verify(mMockContentCaptureDirectManager, times(0)) .sendEvents(any(), anyInt(), any()); assertThat(session.mEvents).isNull(); assertThat(session.mEventProcessQueue).hasSize(BUFFER_SIZE - 1); } @Test public void notifyViewAppearedExactAsMaximumBufferSize() throws RemoteException { ContentCaptureOptions options = createOptions( /* enableContentCaptureReceiver= */ true, /* enableContentProtectionReceiver= */ true); MainContentCaptureSessionV2 session = createSession(options); session.mDirectServiceInterface = mMockContentCaptureDirectManager; session.onSessionStarted(0x2, null); for (int i = 0; i < BUFFER_SIZE; i++) { View view = prepareView(session); session.notifyViewAppeared(session.newViewStructure(view)); } mTestableLooper.processAllMessages(); verify(mMockContentCaptureDirectManager, times(1)) .sendEvents(any(), anyInt(), any()); assertThat(session.mEvents).isEmpty(); assertThat(session.mEventProcessQueue).isEmpty(); } @Test public void notifyViewAppearedAboveMaximumBufferSize() throws RemoteException { ContentCaptureOptions options = createOptions( /* enableContentCaptureReceiver= */ true, /* enableContentProtectionReceiver= */ true); MainContentCaptureSessionV2 session = createSession(options); session.mDirectServiceInterface = mMockContentCaptureDirectManager; session.onSessionStarted(0x2, null); for (int i = 0; i < BUFFER_SIZE * 2 + 1; i++) { View view = prepareView(session); session.notifyViewAppeared(session.newViewStructure(view)); } mTestableLooper.processAllMessages(); verify(mMockContentCaptureDirectManager, times(2)) .sendEvents(any(), anyInt(), any()); assertThat(session.mEvents).isEmpty(); assertThat(session.mEventProcessQueue).hasSize(1); } /** Simulates the regular content capture events sequence. */ private void notifyContentCaptureEvents(final MainContentCaptureSessionV2 session) { final ArrayList<Object> events = new ArrayList<>( Loading