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

Commit 370d7864 authored by Nino Jagar's avatar Nino Jagar Committed by Automerger Merge Worker
Browse files

Merge "Add flags and options for content protection" into udc-qpr-dev am: 6b5e167b am: f8b80eb8

parents 91ec5300 f8b80eb8
Loading
Loading
Loading
Loading
+189 −36
Original line number Diff line number Diff line
@@ -75,6 +75,20 @@ public final class ContentCaptureOptions implements Parcelable {
     */
    public final boolean disableFlushForViewTreeAppearing;

    /**
     * Is the content capture receiver enabled.
     *
     * @hide
     */
    public final boolean enableReceiver;

    /**
     * Options for the content protection flow.
     *
     * @hide
     */
    @NonNull public final ContentProtectionOptions contentProtectionOptions;

    /**
     * List of activities explicitly allowlisted for content capture (or {@code null} if allowlisted
     * for all acitivites in the package).
@@ -94,52 +108,99 @@ public final class ContentCaptureOptions implements Parcelable {
     * for contexts belonging to the content capture service app.
     */
    public ContentCaptureOptions(int loggingLevel) {
        this(/* lite= */ true, loggingLevel, /* maxBufferSize= */ 0,
                /* idleFlushingFrequencyMs= */ 0, /* textChangeFlushingFrequencyMs= */ 0,
                /* logHistorySize= */ 0, /* disableFlushForViewTreeAppearing= */ false,
        this(
                /* lite= */ true,
                loggingLevel,
                /* maxBufferSize= */ 0,
                /* idleFlushingFrequencyMs= */ 0,
                /* textChangeFlushingFrequencyMs= */ 0,
                /* logHistorySize= */ 0,
                /* disableFlushForViewTreeAppearing= */ false,
                /* enableReceiver= */ false,
                new ContentProtectionOptions(
                        /* enableReceiver= */ false,
                        /* bufferSize= */ 0),
                /* whitelistedComponents= */ null);
    }

    /**
     * Default constructor.
     */
    public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
            int textChangeFlushingFrequencyMs, int logHistorySize,
            @SuppressLint({"ConcreteCollection", "NullableCollection"})
            @Nullable ArraySet<ComponentName> whitelistedComponents) {
        this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
                textChangeFlushingFrequencyMs, logHistorySize,
    /** Default constructor. */
    public ContentCaptureOptions(
            int loggingLevel,
            int maxBufferSize,
            int idleFlushingFrequencyMs,
            int textChangeFlushingFrequencyMs,
            int logHistorySize,
            @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable
                    ArraySet<ComponentName> whitelistedComponents) {
        this(
                /* lite= */ false,
                loggingLevel,
                maxBufferSize,
                idleFlushingFrequencyMs,
                textChangeFlushingFrequencyMs,
                logHistorySize,
                ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
                ContentCaptureManager.DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER,
                new ContentProtectionOptions(
                        ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
                        ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE),
                whitelistedComponents);
    }

    /** @hide */
    public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
            int textChangeFlushingFrequencyMs, int logHistorySize,
    public ContentCaptureOptions(
            int loggingLevel,
            int maxBufferSize,
            int idleFlushingFrequencyMs,
            int textChangeFlushingFrequencyMs,
            int logHistorySize,
            boolean disableFlushForViewTreeAppearing,
            @SuppressLint({"ConcreteCollection", "NullableCollection"})
            @Nullable ArraySet<ComponentName> whitelistedComponents) {
        this(/* lite= */ false, loggingLevel, maxBufferSize, idleFlushingFrequencyMs,
                textChangeFlushingFrequencyMs, logHistorySize, disableFlushForViewTreeAppearing,
            boolean enableReceiver,
            @NonNull ContentProtectionOptions contentProtectionOptions,
            @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable
                    ArraySet<ComponentName> whitelistedComponents) {
        this(
                /* lite= */ false,
                loggingLevel,
                maxBufferSize,
                idleFlushingFrequencyMs,
                textChangeFlushingFrequencyMs,
                logHistorySize,
                disableFlushForViewTreeAppearing,
                enableReceiver,
                contentProtectionOptions,
                whitelistedComponents);
    }

    /** @hide */
    @VisibleForTesting
    public ContentCaptureOptions(@Nullable ArraySet<ComponentName> whitelistedComponents) {
        this(ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
        this(
                ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
                ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
                ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
                ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
                ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
                ContentCaptureManager.DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING,
                ContentCaptureManager.DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER,
                new ContentProtectionOptions(
                        ContentCaptureManager.DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER,
                        ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE),
                whitelistedComponents);
    }

    private ContentCaptureOptions(boolean lite, int loggingLevel, int maxBufferSize,
            int idleFlushingFrequencyMs, int textChangeFlushingFrequencyMs, int logHistorySize,
    private ContentCaptureOptions(
            boolean lite,
            int loggingLevel,
            int maxBufferSize,
            int idleFlushingFrequencyMs,
            int textChangeFlushingFrequencyMs,
            int logHistorySize,
            boolean disableFlushForViewTreeAppearing,
            @Nullable ArraySet<ComponentName> whitelistedComponents) {
            boolean enableReceiver,
            @NonNull ContentProtectionOptions contentProtectionOptions,
            @SuppressLint({"ConcreteCollection", "NullableCollection"}) @Nullable
                    ArraySet<ComponentName> whitelistedComponents) {
        this.lite = lite;
        this.loggingLevel = loggingLevel;
        this.maxBufferSize = maxBufferSize;
@@ -147,6 +208,8 @@ public final class ContentCaptureOptions implements Parcelable {
        this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs;
        this.logHistorySize = logHistorySize;
        this.disableFlushForViewTreeAppearing = disableFlushForViewTreeAppearing;
        this.enableReceiver = enableReceiver;
        this.contentProtectionOptions = contentProtectionOptions;
        this.whitelistedComponents = whitelistedComponents;
    }

@@ -191,12 +254,22 @@ public final class ContentCaptureOptions implements Parcelable {
            return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
        }
        final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
        string.append("loggingLevel=").append(loggingLevel)
            .append(", maxBufferSize=").append(maxBufferSize)
            .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
            .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
            .append(", logHistorySize=").append(logHistorySize)
            .append(", disableFlushForViewTreeAppearing=").append(disableFlushForViewTreeAppearing);
        string.append("loggingLevel=")
                .append(loggingLevel)
                .append(", maxBufferSize=")
                .append(maxBufferSize)
                .append(", idleFlushingFrequencyMs=")
                .append(idleFlushingFrequencyMs)
                .append(", textChangeFlushingFrequencyMs=")
                .append(textChangeFlushingFrequencyMs)
                .append(", logHistorySize=")
                .append(logHistorySize)
                .append(", disableFlushForViewTreeAppearing=")
                .append(disableFlushForViewTreeAppearing)
                .append(", enableReceiver=")
                .append(enableReceiver)
                .append(", contentProtectionOptions=")
                .append(contentProtectionOptions);
        if (whitelistedComponents != null) {
            string.append(", whitelisted=").append(whitelistedComponents);
        }
@@ -210,11 +283,21 @@ public final class ContentCaptureOptions implements Parcelable {
            pw.print(", lite");
            return;
        }
        pw.print(", bufferSize="); pw.print(maxBufferSize);
        pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
        pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
        pw.print(", logSize="); pw.print(logHistorySize);
        pw.print(", disableFlushForViewTreeAppearing="); pw.print(disableFlushForViewTreeAppearing);
        pw.print(", bufferSize=");
        pw.print(maxBufferSize);
        pw.print(", idle=");
        pw.print(idleFlushingFrequencyMs);
        pw.print(", textIdle=");
        pw.print(textChangeFlushingFrequencyMs);
        pw.print(", logSize=");
        pw.print(logHistorySize);
        pw.print(", disableFlushForViewTreeAppearing=");
        pw.print(disableFlushForViewTreeAppearing);
        pw.print(", enableReceiver=");
        pw.print(enableReceiver);
        pw.print(", contentProtectionOptions=[");
        contentProtectionOptions.dumpShort(pw);
        pw.print("]");
        if (whitelistedComponents != null) {
            pw.print(", whitelisted="); pw.print(whitelistedComponents);
        }
@@ -236,6 +319,8 @@ public final class ContentCaptureOptions implements Parcelable {
        parcel.writeInt(textChangeFlushingFrequencyMs);
        parcel.writeInt(logHistorySize);
        parcel.writeBoolean(disableFlushForViewTreeAppearing);
        parcel.writeBoolean(enableReceiver);
        contentProtectionOptions.writeToParcel(parcel);
        parcel.writeArraySet(whitelistedComponents);
    }

@@ -254,12 +339,22 @@ public final class ContentCaptureOptions implements Parcelable {
                    final int textChangeFlushingFrequencyMs = parcel.readInt();
                    final int logHistorySize = parcel.readInt();
                    final boolean disableFlushForViewTreeAppearing = parcel.readBoolean();
                    final boolean enableReceiver = parcel.readBoolean();
                    final ContentProtectionOptions contentProtectionOptions =
                            ContentProtectionOptions.createFromParcel(parcel);
                    @SuppressWarnings("unchecked")
                    final ArraySet<ComponentName> whitelistedComponents =
                            (ArraySet<ComponentName>) parcel.readArraySet(null);
                    return new ContentCaptureOptions(loggingLevel, maxBufferSize,
                            idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize,
                            disableFlushForViewTreeAppearing, whitelistedComponents);
                    return new ContentCaptureOptions(
                            loggingLevel,
                            maxBufferSize,
                            idleFlushingFrequencyMs,
                            textChangeFlushingFrequencyMs,
                            logHistorySize,
                            disableFlushForViewTreeAppearing,
                            enableReceiver,
                            contentProtectionOptions,
                            whitelistedComponents);
                }

                @Override
@@ -267,4 +362,62 @@ public final class ContentCaptureOptions implements Parcelable {
                    return new ContentCaptureOptions[size];
                }
    };

    /**
     * Content protection options for a given package.
     *
     * <p>Does not implement {@code Parcelable} since it is an inner class without a matching AIDL.
     *
     * @hide
     */
    public static class ContentProtectionOptions {

        /**
         * Is the content protection receiver enabled.
         *
         * @hide
         */
        public final boolean enableReceiver;

        /**
         * Size of the in-memory ring buffer for the content protection flow.
         *
         * @hide
         */
        public final int bufferSize;

        public ContentProtectionOptions(boolean enableReceiver, int bufferSize) {
            this.enableReceiver = enableReceiver;
            this.bufferSize = bufferSize;
        }

        @Override
        public String toString() {
            StringBuilder stringBuilder = new StringBuilder("ContentProtectionOptions [");
            stringBuilder
                    .append("enableReceiver=")
                    .append(enableReceiver)
                    .append(", bufferSize=")
                    .append(bufferSize);
            return stringBuilder.append(']').toString();
        }

        private void dumpShort(@NonNull PrintWriter pw) {
            pw.print("enableReceiver=");
            pw.print(enableReceiver);
            pw.print(", bufferSize=");
            pw.print(bufferSize);
        }

        private void writeToParcel(Parcel parcel) {
            parcel.writeBoolean(enableReceiver);
            parcel.writeInt(bufferSize);
        }

        private static ContentProtectionOptions createFromParcel(Parcel parcel) {
            boolean enableReceiver = parcel.readBoolean();
            int bufferSize = parcel.readInt();
            return new ContentProtectionOptions(enableReceiver, bufferSize);
        }
    }
}
+36 −3
Original line number Diff line number Diff line
@@ -352,6 +352,30 @@ public final class ContentCaptureManager {
    public static final String DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING =
            "disable_flush_for_view_tree_appearing";

    /**
     * Enables the content protection receiver.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER =
            "enable_content_protection_receiver";

    /**
     * Sets the size of the app blocklist for the content protection flow.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE =
            "content_protection_apps_blocklist_size";

    /**
     * Sets the size of the in-memory ring buffer for the content protection flow.
     *
     * @hide
     */
    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE =
            "content_protection_buffer_size";

    /** @hide */
    @TestApi
    public static final int LOGGING_LEVEL_OFF = 0;
@@ -384,6 +408,14 @@ public final class ContentCaptureManager {
    public static final int DEFAULT_LOG_HISTORY_SIZE = 10;
    /** @hide */
    public static final boolean DEFAULT_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING = false;
    /** @hide */
    public static final boolean DEFAULT_ENABLE_CONTENT_CAPTURE_RECEIVER = true;
    /** @hide */
    public static final boolean DEFAULT_ENABLE_CONTENT_PROTECTION_RECEIVER = false;
    /** @hide */
    public static final int DEFAULT_CONTENT_PROTECTION_APPS_BLOCKLIST_SIZE = 1000;
    /** @hide */
    public static final int DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE = 150;

    private final Object mLock = new Object();

@@ -425,11 +457,11 @@ public final class ContentCaptureManager {

    /** @hide */
    static class StrippedContext {
        final String mPackageName;
        final String mContext;
        @NonNull final String mPackageName;
        @NonNull final String mContext;
        final @UserIdInt int mUserId;

        private StrippedContext(Context context) {
        private StrippedContext(@NonNull Context context) {
            mPackageName = context.getPackageName();
            mContext = context.toString();
            mUserId = context.getUserId();
@@ -440,6 +472,7 @@ public final class ContentCaptureManager {
            return mContext;
        }

        @NonNull
        public String getPackageName() {
            return mPackageName;
        }
+85 −9
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static org.mockito.Mockito.when;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.util.ArraySet;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;

@@ -40,16 +41,29 @@ import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ContentCaptureOptionsTest {

    private final ComponentName mContextComponent = new ComponentName("marco", "polo");
    private final ComponentName mComp1 = new ComponentName("comp", "one");
    private final ComponentName mComp2 = new ComponentName("two", "comp");
    private static final ComponentName CONTEXT_COMPONENT = new ComponentName("marco", "polo");
    private static final ComponentName COMPONENT1 = new ComponentName("comp", "one");
    private static final ComponentName COMPONENT2 = new ComponentName("two", "comp");
    private static final ContentCaptureOptions CONTENT_CAPTURE_OPTIONS =
            new ContentCaptureOptions(
                    /* loggingLevel= */ 1000,
                    /* maxBufferSize= */ 1001,
                    /* idleFlushingFrequencyMs= */ 1002,
                    /* textChangeFlushingFrequencyMs= */ 1003,
                    /* logHistorySize= */ 1004,
                    /* disableFlushForViewTreeAppearing= */ true,
                    /* enableReceiver= */ false,
                    new ContentCaptureOptions.ContentProtectionOptions(
                            /* enableReceiver= */ true,
                            /* bufferSize= */ 2001),
                    /* whitelistedComponents= */ toSet(COMPONENT1, COMPONENT2));

    @Mock private Context mContext;
    @Mock private ContentCaptureClient mClient;

    @Before
    public void setExpectation() {
        when(mClient.contentCaptureClientGetComponentName()).thenReturn(mContextComponent);
        when(mClient.contentCaptureClientGetComponentName()).thenReturn(CONTEXT_COMPONENT);
        when(mContext.getContentCaptureClient()).thenReturn(mClient);
    }

@@ -67,26 +81,27 @@ public class ContentCaptureOptionsTest {

    @Test
    public void testIsWhitelisted_notWhitelisted() {
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mComp1, mComp2));
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(COMPONENT1, COMPONENT2));
        assertThat(options.isWhitelisted(mContext)).isFalse();
    }

    @Test
    public void testIsWhitelisted_whitelisted() {
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mComp1, mContextComponent));
        ContentCaptureOptions options =
                new ContentCaptureOptions(toSet(COMPONENT1, CONTEXT_COMPONENT));
        assertThat(options.isWhitelisted(mContext)).isTrue();
    }

    @Test
    public void testIsWhitelisted_invalidContext() {
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mContextComponent));
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(CONTEXT_COMPONENT));
        Context invalidContext = mock(Context.class); // has no client
        assertThat(options.isWhitelisted(invalidContext)).isFalse();
    }

    @Test
    public void testIsWhitelisted_clientWithNullComponentName() {
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(mContextComponent));
        ContentCaptureOptions options = new ContentCaptureOptions(toSet(CONTEXT_COMPONENT));
        ContentCaptureClient client = mock(ContentCaptureClient.class);
        Context context = mock(Context.class);
        when(context.getContentCaptureClient()).thenReturn(client);
@@ -94,8 +109,69 @@ public class ContentCaptureOptionsTest {
        assertThat(options.isWhitelisted(context)).isFalse();
    }

    @Test
    public void testToString() {
        String actual = CONTENT_CAPTURE_OPTIONS.toString();

        String expected =
                new StringBuilder("ContentCaptureOptions [")
                        .append("loggingLevel=")
                        .append(CONTENT_CAPTURE_OPTIONS.loggingLevel)
                        .append(", maxBufferSize=")
                        .append(CONTENT_CAPTURE_OPTIONS.maxBufferSize)
                        .append(", idleFlushingFrequencyMs=")
                        .append(CONTENT_CAPTURE_OPTIONS.idleFlushingFrequencyMs)
                        .append(", textChangeFlushingFrequencyMs=")
                        .append(CONTENT_CAPTURE_OPTIONS.textChangeFlushingFrequencyMs)
                        .append(", logHistorySize=")
                        .append(CONTENT_CAPTURE_OPTIONS.logHistorySize)
                        .append(", disableFlushForViewTreeAppearing=")
                        .append(CONTENT_CAPTURE_OPTIONS.disableFlushForViewTreeAppearing)
                        .append(", enableReceiver=")
                        .append(CONTENT_CAPTURE_OPTIONS.enableReceiver)
                        .append(", contentProtectionOptions=ContentProtectionOptions [")
                        .append("enableReceiver=")
                        .append(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.enableReceiver)
                        .append(", bufferSize=")
                        .append(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.bufferSize)
                        .append("], whitelisted=")
                        .append(CONTENT_CAPTURE_OPTIONS.whitelistedComponents)
                        .append(']')
                        .toString();
        assertThat(actual).isEqualTo(expected);
    }

    @Test
    public void testParcelSerializationDeserialization() {
        Parcel parcel = Parcel.obtain();
        CONTENT_CAPTURE_OPTIONS.writeToParcel(parcel, /* flags= */ 0);
        parcel.setDataPosition(0);

        ContentCaptureOptions actual = ContentCaptureOptions.CREATOR.createFromParcel(parcel);
        parcel.recycle();

        assertThat(actual).isNotNull();
        assertThat(actual.loggingLevel).isEqualTo(CONTENT_CAPTURE_OPTIONS.loggingLevel);
        assertThat(actual.maxBufferSize).isEqualTo(CONTENT_CAPTURE_OPTIONS.maxBufferSize);
        assertThat(actual.idleFlushingFrequencyMs)
                .isEqualTo(CONTENT_CAPTURE_OPTIONS.idleFlushingFrequencyMs);
        assertThat(actual.textChangeFlushingFrequencyMs)
                .isEqualTo(CONTENT_CAPTURE_OPTIONS.textChangeFlushingFrequencyMs);
        assertThat(actual.logHistorySize).isEqualTo(CONTENT_CAPTURE_OPTIONS.logHistorySize);
        assertThat(actual.disableFlushForViewTreeAppearing)
                .isEqualTo(CONTENT_CAPTURE_OPTIONS.disableFlushForViewTreeAppearing);
        assertThat(actual.enableReceiver).isEqualTo(CONTENT_CAPTURE_OPTIONS.enableReceiver);
        assertThat(actual.contentProtectionOptions).isNotNull();
        assertThat(actual.contentProtectionOptions.enableReceiver)
                .isEqualTo(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.enableReceiver);
        assertThat(actual.contentProtectionOptions.bufferSize)
                .isEqualTo(CONTENT_CAPTURE_OPTIONS.contentProtectionOptions.bufferSize);
        assertThat(actual.whitelistedComponents)
                .containsExactlyElementsIn(CONTENT_CAPTURE_OPTIONS.whitelistedComponents);
    }

    @NonNull
    private ArraySet<ComponentName> toSet(@Nullable ComponentName... comps) {
    private static ArraySet<ComponentName> toSet(@Nullable ComponentName... comps) {
        ArraySet<ComponentName> set = new ArraySet<>();
        if (comps != null) {
            for (int i = 0; i < comps.length; i++) {
+154 −55

File changed.

Preview size limit exceeded, changes collapsed.

+114 −0

File added.

Preview size limit exceeded, changes collapsed.