Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc8c1f91 authored by Nino Jagar's avatar Nino Jagar
Browse files

Add content protection buffer to ContentCaptureManager

BYPASS_INCLUSIVE_LANGUAGE_REASON=All issues are in the existing code
which is already in production. New code has no issues.

Bug: 275732576
Test: Added new tests
Change-Id: I676ae25d5245892e995d87e3793da73aff4a5f0e
parent 90ca501c
Loading
Loading
Loading
Loading
+26 −2
Original line number Original line Diff line number Diff line
@@ -52,6 +52,7 @@ import android.view.contentcapture.ContentCaptureSession.FlushReason;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.RingBuffer;
import com.android.internal.util.SyncResultReceiver;
import com.android.internal.util.SyncResultReceiver;


import java.io.PrintWriter;
import java.io.PrintWriter;
@@ -446,6 +447,9 @@ public final class ContentCaptureManager {
    @Nullable // set on-demand by addDumpable()
    @Nullable // set on-demand by addDumpable()
    private Dumper mDumpable;
    private Dumper mDumpable;


    // Created here in order to live across activity and session changes
    @Nullable private final RingBuffer<ContentCaptureEvent> mContentProtectionEventBuffer;

    /** @hide */
    /** @hide */
    public interface ContentCaptureClient {
    public interface ContentCaptureClient {
        /**
        /**
@@ -456,12 +460,15 @@ public final class ContentCaptureManager {
    }
    }


    /** @hide */
    /** @hide */
    static class StrippedContext {
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public static class StrippedContext {
        @NonNull final String mPackageName;
        @NonNull final String mPackageName;
        @NonNull final String mContext;
        @NonNull final String mContext;
        final @UserIdInt int mUserId;
        final @UserIdInt int mUserId;


        private StrippedContext(@NonNull Context context) {
        /** @hide */
        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
        public StrippedContext(@NonNull Context context) {
            mPackageName = context.getPackageName();
            mPackageName = context.getPackageName();
            mContext = context.toString();
            mContext = context.toString();
            mUserId = context.getUserId();
            mUserId = context.getUserId();
@@ -502,6 +509,16 @@ public final class ContentCaptureManager {
        mHandler = Handler.createAsync(Looper.getMainLooper());
        mHandler = Handler.createAsync(Looper.getMainLooper());


        mDataShareAdapterResourceManager = new LocalDataShareAdapterResourceManager();
        mDataShareAdapterResourceManager = new LocalDataShareAdapterResourceManager();

        if (mOptions.contentProtectionOptions.enableReceiver
                && mOptions.contentProtectionOptions.bufferSize > 0) {
            mContentProtectionEventBuffer =
                    new RingBuffer(
                            ContentCaptureEvent.class,
                            mOptions.contentProtectionOptions.bufferSize);
        } else {
            mContentProtectionEventBuffer = null;
        }
    }
    }


    /**
    /**
@@ -870,6 +887,13 @@ public final class ContentCaptureManager {
        activity.addDumpable(mDumpable);
        activity.addDumpable(mDumpable);
    }
    }


    /** @hide */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    @Nullable
    public RingBuffer<ContentCaptureEvent> getContentProtectionEventBuffer() {
        return mContentProtectionEventBuffer;
    }

    // NOTE: ContentCaptureManager cannot implement it directly as it would be exposed as public API
    // NOTE: ContentCaptureManager cannot implement it directly as it would be exposed as public API
    private final class Dumper implements Dumpable {
    private final class Dumper implements Dumpable {
        @Override
        @Override
+82 −7
Original line number Original line Diff line number Diff line
@@ -15,14 +15,17 @@
 */
 */
package android.view.contentcapture;
package android.view.contentcapture;


import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;


import static org.mockito.Mockito.mock;
import static org.testng.Assert.assertThrows;
import static org.testng.Assert.assertThrows;


import android.content.ContentCaptureOptions;
import android.content.ContentCaptureOptions;
import android.content.Context;
import android.content.Context;


import com.android.internal.util.RingBuffer;

import org.junit.Test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mock;
@@ -37,9 +40,15 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
@RunWith(MockitoJUnitRunner.class)
public class ContentCaptureManagerTest {
public class ContentCaptureManagerTest {


    private static final int BUFFER_SIZE = 100;

    private static final ContentCaptureOptions EMPTY_OPTIONS = new ContentCaptureOptions(null);

    @Mock
    @Mock
    private Context mMockContext;
    private Context mMockContext;


    @Mock private IContentCaptureManager mMockContentCaptureManager;

    @Test
    @Test
    public void testConstructor_invalidParametersThrowsException() {
    public void testConstructor_invalidParametersThrowsException() {
        assertThrows(NullPointerException.class,
        assertThrows(NullPointerException.class,
@@ -47,12 +56,66 @@ public class ContentCaptureManagerTest {
                        null));
                        null));
    }
    }


    @Test
    public void testConstructor_contentProtection_default_bufferNotCreated() {
        ContentCaptureManager manager =
                new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS);

        assertThat(manager.getContentProtectionEventBuffer()).isNull();
    }

    @Test
    public void testConstructor_contentProtection_disabled_bufferNotCreated() {
        ContentCaptureOptions options =
                createOptions(
                        new ContentCaptureOptions.ContentProtectionOptions(
                                /* enableReceiver= */ false, BUFFER_SIZE));

        ContentCaptureManager manager =
                new ContentCaptureManager(mMockContext, mMockContentCaptureManager, options);

        assertThat(manager.getContentProtectionEventBuffer()).isNull();
    }

    @Test
    public void testConstructor_contentProtection_invalidBufferSize_bufferNotCreated() {
        ContentCaptureOptions options =
                createOptions(
                        new ContentCaptureOptions.ContentProtectionOptions(
                                /* enableReceiver= */ true, /* bufferSize= */ 0));

        ContentCaptureManager manager =
                new ContentCaptureManager(mMockContext, mMockContentCaptureManager, options);

        assertThat(manager.getContentProtectionEventBuffer()).isNull();
    }

    @Test
    public void testConstructor_contentProtection_enabled_bufferCreated() {
        ContentCaptureOptions options =
                createOptions(
                        new ContentCaptureOptions.ContentProtectionOptions(
                                /* enableReceiver= */ true, BUFFER_SIZE));

        ContentCaptureManager manager =
                new ContentCaptureManager(mMockContext, mMockContentCaptureManager, options);
        RingBuffer<ContentCaptureEvent> buffer = manager.getContentProtectionEventBuffer();

        assertThat(buffer).isNotNull();
        ContentCaptureEvent[] expected = new ContentCaptureEvent[BUFFER_SIZE];
        int offset = 3;
        for (int i = 0; i < BUFFER_SIZE + offset; i++) {
            ContentCaptureEvent event = new ContentCaptureEvent(i, TYPE_SESSION_STARTED);
            buffer.append(event);
            expected[(i + BUFFER_SIZE - offset) % BUFFER_SIZE] = event;
        }
        assertThat(buffer.toArray()).isEqualTo(expected);
    }

    @Test
    @Test
    public void testRemoveData_invalidParametersThrowsException() {
    public void testRemoveData_invalidParametersThrowsException() {
        final IContentCaptureManager mockService = mock(IContentCaptureManager.class);
        final ContentCaptureOptions options = new ContentCaptureOptions(null);
        final ContentCaptureManager manager =
        final ContentCaptureManager manager =
                new ContentCaptureManager(mMockContext, mockService, options);
                new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS);


        assertThrows(NullPointerException.class, () -> manager.removeData(null));
        assertThrows(NullPointerException.class, () -> manager.removeData(null));
    }
    }
@@ -60,10 +123,8 @@ public class ContentCaptureManagerTest {
    @Test
    @Test
    @SuppressWarnings("GuardedBy")
    @SuppressWarnings("GuardedBy")
    public void testFlushViewTreeAppearingEventDisabled_setAndGet() {
    public void testFlushViewTreeAppearingEventDisabled_setAndGet() {
        final IContentCaptureManager mockService = mock(IContentCaptureManager.class);
        final ContentCaptureOptions options = new ContentCaptureOptions(null);
        final ContentCaptureManager manager =
        final ContentCaptureManager manager =
                new ContentCaptureManager(mMockContext, mockService, options);
                new ContentCaptureManager(mMockContext, mMockContentCaptureManager, EMPTY_OPTIONS);


        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse();
        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse();
        manager.setFlushViewTreeAppearingEventDisabled(true);
        manager.setFlushViewTreeAppearingEventDisabled(true);
@@ -71,4 +132,18 @@ public class ContentCaptureManagerTest {
        manager.setFlushViewTreeAppearingEventDisabled(false);
        manager.setFlushViewTreeAppearingEventDisabled(false);
        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse();
        assertThat(manager.getFlushViewTreeAppearingEventDisabled()).isFalse();
    }
    }

    private ContentCaptureOptions createOptions(
            ContentCaptureOptions.ContentProtectionOptions contentProtectionOptions) {
        return new ContentCaptureOptions(
                /* loggingLevel= */ 0,
                /* maxBufferSize= */ 0,
                /* idleFlushingFrequencyMs= */ 0,
                /* textChangeFlushingFrequencyMs= */ 0,
                /* logHistorySize= */ 0,
                /* disableFlushForViewTreeAppearing= */ false,
                /* enableReceiver= */ true,
                contentProtectionOptions,
                /* whitelistedComponents= */ null);
    }
}
}