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

Commit bbbb9431 authored by Mary Xia's avatar Mary Xia
Browse files

Declare new display category and enforce equality match with activity attribute in GWPC

Bug:233910285
Test: atest RestrictActivityTest
Change-Id: I0452fe45d5d5ba360bbfbe4a15586fcea68d2216
parent 135f6013
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2958,6 +2958,7 @@ package android.companion.virtual {
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
    method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
    method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull java.util.List<java.lang.String>, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+61 −3
Original line number Diff line number Diff line
@@ -350,14 +350,72 @@ public final class VirtualDeviceManager {
                @VirtualDisplayFlag int flags,
                @Nullable @CallbackExecutor Executor executor,
                @Nullable VirtualDisplay.Callback callback) {
            // TODO(b/205343547): Handle display groups properly instead of creating a new display
            //  group for every new virtual display created using this API.
            // belongs to the same display group.
            VirtualDisplayConfig config = new VirtualDisplayConfig.Builder(
                    getVirtualDisplayName(), width, height, densityDpi)
                    .setSurface(surface)
                    .setFlags(getVirtualDisplayFlags(flags))
                    .build();
            return createVirtualDisplayInternal(config, executor, callback);
        }

        /**
         * Creates a virtual display for this virtual device. All displays created on the same
         * device belongs to the same display group.
         *
         * @param width The width of the virtual display in pixels, must be greater than 0.
         * @param height The height of the virtual display in pixels, must be greater than 0.
         * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
         * @param displayCategories The categories of the virtual display, indicating the type of
         * activities allowed to run on the display. Activities can declare their type using
         * {@link android.content.pm.ActivityInfo#targetDisplayCategory}.
         * @param surface The surface to which the content of the virtual display should
         * be rendered, or null if there is none initially. The surface can also be set later using
         * {@link VirtualDisplay#setSurface(Surface)}.
         * @param flags A combination of virtual display flags accepted by
         * {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are
         * automatically set for all virtual devices:
         * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and
         * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
         * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
         * @param executor The executor on which {@code callback} will be invoked. This is ignored
         * if {@code callback} is {@code null}. If {@code callback} is specified, this executor must
         * not be null.
         * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
         * @return The newly created virtual display, or {@code null} if the application could
         * not create the virtual display.
         *
         * @see DisplayManager#createVirtualDisplay
         */
        @Nullable
        public VirtualDisplay createVirtualDisplay(
                @IntRange(from = 1) int width,
                @IntRange(from = 1) int height,
                @IntRange(from = 1) int densityDpi,
                @NonNull List<String> displayCategories,
                @Nullable Surface surface,
                @VirtualDisplayFlag int flags,
                @Nullable @CallbackExecutor Executor executor,
                @Nullable VirtualDisplay.Callback callback) {
            VirtualDisplayConfig config = new VirtualDisplayConfig.Builder(
                    getVirtualDisplayName(), width, height, densityDpi)
                    .setDisplayCategories(displayCategories)
                    .setSurface(surface)
                    .setFlags(getVirtualDisplayFlags(flags))
                    .build();
            return createVirtualDisplayInternal(config, executor, callback);
        }

        /**
         * @hide
         */
        @Nullable
        private VirtualDisplay createVirtualDisplayInternal(
                @NonNull VirtualDisplayConfig config,
                @Nullable @CallbackExecutor Executor executor,
                @Nullable VirtualDisplay.Callback callback) {
            // TODO(b/205343547): Handle display groups properly instead of creating a new display
            //  group for every new virtual display created using this API.
            // belongs to the same display group.
            IVirtualDisplayCallback callbackWrapper =
                    new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor);
            final int displayId;
+60 −6
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ import android.view.Surface;

import com.android.internal.util.DataClass;

import java.util.ArrayList;
import java.util.List;

/**
 * Holds configuration used to create {@link VirtualDisplay} instances. See
 * {@link MediaProjection#createVirtualDisplay(VirtualDisplayConfig, VirtualDisplay.Callback, Handler)}.
@@ -99,6 +102,13 @@ public final class VirtualDisplayConfig implements Parcelable {
     */
    private boolean mWindowManagerMirroring = false;

    /**
     * The display categories. If set, only corresponding activities from the same category can be
     * shown on the display.
     */
    @DataClass.PluralOf("displayCategory")
    @NonNull private List<String> mDisplayCategories = new ArrayList<>();



    // Code below generated by codegen v1.0.23.
@@ -124,7 +134,8 @@ public final class VirtualDisplayConfig implements Parcelable {
            @Nullable Surface surface,
            @Nullable String uniqueId,
            int displayIdToMirror,
            boolean windowManagerMirroring) {
            boolean windowManagerMirroring,
            @NonNull List<String> displayCategories) {
        this.mName = name;
        com.android.internal.util.AnnotationValidations.validate(
                NonNull.class, null, mName);
@@ -147,6 +158,9 @@ public final class VirtualDisplayConfig implements Parcelable {
        this.mUniqueId = uniqueId;
        this.mDisplayIdToMirror = displayIdToMirror;
        this.mWindowManagerMirroring = windowManagerMirroring;
        this.mDisplayCategories = displayCategories;
        com.android.internal.util.AnnotationValidations.validate(
                NonNull.class, null, mDisplayCategories);

        // onConstructed(); // You can define this method to get a callback
    }
@@ -233,6 +247,15 @@ public final class VirtualDisplayConfig implements Parcelable {
        return mWindowManagerMirroring;
    }

    /**
     * The display categories. If set, only corresponding activities from the same category can be
     * shown on the display.
     */
    @DataClass.Generated.Member
    public @NonNull List<String> getDisplayCategories() {
        return mDisplayCategories;
    }

    @Override
    @DataClass.Generated.Member
    public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -252,6 +275,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        if (mSurface != null) dest.writeTypedObject(mSurface, flags);
        if (mUniqueId != null) dest.writeString(mUniqueId);
        dest.writeInt(mDisplayIdToMirror);
        dest.writeStringList(mDisplayCategories);
    }

    @Override
@@ -275,6 +299,8 @@ public final class VirtualDisplayConfig implements Parcelable {
        Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR);
        String uniqueId = (flg & 0x40) == 0 ? null : in.readString();
        int displayIdToMirror = in.readInt();
        List<String> displayCategories = new ArrayList<>();
        in.readStringList(displayCategories);

        this.mName = name;
        com.android.internal.util.AnnotationValidations.validate(
@@ -298,6 +324,9 @@ public final class VirtualDisplayConfig implements Parcelable {
        this.mUniqueId = uniqueId;
        this.mDisplayIdToMirror = displayIdToMirror;
        this.mWindowManagerMirroring = windowManagerMirroring;
        this.mDisplayCategories = displayCategories;
        com.android.internal.util.AnnotationValidations.validate(
                NonNull.class, null, mDisplayCategories);

        // onConstructed(); // You can define this method to get a callback
    }
@@ -332,6 +361,7 @@ public final class VirtualDisplayConfig implements Parcelable {
        private @Nullable String mUniqueId;
        private int mDisplayIdToMirror;
        private boolean mWindowManagerMirroring;
        private @NonNull List<String> mDisplayCategories;

        private long mBuilderFieldsSet = 0L;

@@ -478,10 +508,30 @@ public final class VirtualDisplayConfig implements Parcelable {
            return this;
        }

        /**
         * The display categories. If set, only corresponding activities from the same category can be
         * shown on the display.
         */
        @DataClass.Generated.Member
        public @NonNull Builder setDisplayCategories(@NonNull List<String> value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x200;
            mDisplayCategories = value;
            return this;
        }

        /** @see #setDisplayCategories */
        @DataClass.Generated.Member
        public @NonNull Builder addDisplayCategory(@NonNull String value) {
            if (mDisplayCategories == null) setDisplayCategories(new ArrayList<>());
            mDisplayCategories.add(value);
            return this;
        }

        /** Builds the instance. This builder should not be touched after calling this! */
        public @NonNull VirtualDisplayConfig build() {
            checkNotUsed();
            mBuilderFieldsSet |= 0x200; // Mark builder used
            mBuilderFieldsSet |= 0x400; // Mark builder used

            if ((mBuilderFieldsSet & 0x10) == 0) {
                mFlags = 0;
@@ -498,6 +548,9 @@ public final class VirtualDisplayConfig implements Parcelable {
            if ((mBuilderFieldsSet & 0x100) == 0) {
                mWindowManagerMirroring = false;
            }
            if ((mBuilderFieldsSet & 0x200) == 0) {
                mDisplayCategories = new ArrayList<>();
            }
            VirtualDisplayConfig o = new VirtualDisplayConfig(
                    mName,
                    mWidth,
@@ -507,12 +560,13 @@ public final class VirtualDisplayConfig implements Parcelable {
                    mSurface,
                    mUniqueId,
                    mDisplayIdToMirror,
                    mWindowManagerMirroring);
                    mWindowManagerMirroring,
                    mDisplayCategories);
            return o;
        }

        private void checkNotUsed() {
            if ((mBuilderFieldsSet & 0x200) != 0) {
            if ((mBuilderFieldsSet & 0x400) != 0) {
                throw new IllegalStateException(
                        "This Builder should not be reused. Use a new Builder instance instead");
            }
@@ -520,10 +574,10 @@ public final class VirtualDisplayConfig implements Parcelable {
    }

    @DataClass.Generated(
            time = 1646227247934L,
            time = 1668534501320L,
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nprivate  boolean mWindowManagerMirroring\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nprivate  boolean mWindowManagerMirroring\nprivate @com.android.internal.util.DataClass.PluralOf(\"displayCategory\") @android.annotation.NonNull java.util.List<java.lang.String> mDisplayCategories\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
    @Deprecated
    private void __metadata() {}

+23 −3
Original line number Diff line number Diff line
@@ -130,6 +130,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
    @Nullable
    private final @AssociationRequest.DeviceProfile String mDeviceProfile;
    @Nullable private final SecureWindowCallback mSecureWindowCallback;
    @Nullable private final List<String> mDisplayCategories;

    /**
     * Creates a window policy controller that is generic to the different use cases of virtual
@@ -168,7 +169,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
            @NonNull PipBlockedCallback pipBlockedCallback,
            @NonNull ActivityBlockedCallback activityBlockedCallback,
            @NonNull SecureWindowCallback secureWindowCallback,
            @AssociationRequest.DeviceProfile String deviceProfile) {
            @AssociationRequest.DeviceProfile String deviceProfile,
            @NonNull List<String> displayCategories) {
        super();
        mAllowedUsers = allowedUsers;
        mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
@@ -182,6 +184,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
        mDeviceProfile = deviceProfile;
        mPipBlockedCallback = pipBlockedCallback;
        mSecureWindowCallback = secureWindowCallback;
        mDisplayCategories = displayCategories;
    }

    /**
@@ -350,6 +353,15 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
        }
    }

    private boolean activityMatchesDisplayCategory(ActivityInfo activityInfo) {
        if (mDisplayCategories.isEmpty()) {
            return activityInfo.targetDisplayCategory == null;
        }
        return activityInfo.targetDisplayCategory != null
                    && mDisplayCategories.contains(activityInfo.targetDisplayCategory);

    }

    private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags,
            int systemWindowFlags) {
        if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
@@ -357,9 +369,17 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
        }
        ComponentName activityComponent = activityInfo.getComponentName();
        if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
            // The error dialog alerting users that streaming is blocked is always allowed.
            // The error dialog alerting users that streaming is blocked is always allowed. Need to
            // run before the clauses below to ensure error dialog always shows up.
            return true;
        }
        if (!activityMatchesDisplayCategory(activityInfo)) {
            Slog.d(TAG, String.format(
                    "The activity's target display category: %s is not found on virtual display"
                            + " with the following allowed display categories: %s",
                    activityInfo.targetDisplayCategory, mDisplayCategories.toString()));
            return false;
        }
        final UserHandle activityUser =
                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
        if (!mAllowedUsers.contains(activityUser)) {
+5 −2
Original line number Diff line number Diff line
@@ -74,6 +74,7 @@ import com.android.server.companion.virtual.audio.VirtualAudioController;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
@@ -628,7 +629,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        mInputController.dump(fout);
    }

    GenericWindowPolicyController createWindowPolicyController() {
    GenericWindowPolicyController createWindowPolicyController(
            @NonNull List<String> displayCategories) {
        synchronized (mVirtualDeviceLock) {
            final GenericWindowPolicyController gwpc =
                    new GenericWindowPolicyController(FLAG_SECURE,
@@ -643,7 +645,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                            this::onEnteringPipBlocked,
                            this::onActivityBlocked,
                            this::onSecureWindowShown,
                            mAssociationInfo.getDeviceProfile());
                            mAssociationInfo.getDeviceProfile(),
                            displayCategories);
            gwpc.registerRunningAppsChangedListener(/* listener= */ this);
            return gwpc;
        }
Loading