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

Commit 24219576 authored by Maurice Lam's avatar Maurice Lam
Browse files

Add VDM.createVirtualDisplay

Add the association ID parameter in VDM, and use that to generate the
label for the virtual display name. The association ID check is
currently commented out because the API for companion apps to get the
association ID from CDM is not submitted yet.

Bug: 194949534
Test: Manual
CTS-Coverage-Bug: 204606917
Change-Id: I4d1207fc57a59c8d5b00cc200d507685e7e7a702
parent 3cc48403
Loading
Loading
Loading
Loading
+106 −0
Original line number Diff line number Diff line
@@ -16,21 +16,32 @@

package android.companion.virtual;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.companion.AssociationInfo;
import android.content.Context;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.VirtualKeyboard;
import android.hardware.input.VirtualMouse;
import android.hardware.input.VirtualTouchscreen;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Surface;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * System level service for managing virtual devices.
@@ -44,6 +55,31 @@ public final class VirtualDeviceManager {
    private static final boolean DEBUG = false;
    private static final String LOG_TAG = "VirtualDeviceManager";

    /** @hide */
    @IntDef(prefix = "DISPLAY_FLAG_",
            flag = true,
            value = {DISPLAY_FLAG_TRUSTED})
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface DisplayFlags {}

    /**
     * Indicates that the display is trusted to show system decorations and receive inputs without
     * users' touch.
     *
     * @see DisplayManager#VIRTUAL_DISPLAY_FLAG_TRUSTED
     * @hide  // TODO(b/194949534): Unhide this API
     */
    public static final int DISPLAY_FLAG_TRUSTED = 1;

    private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
            DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;

    private final IVirtualDeviceManager mService;
    private final Context mContext;

@@ -92,6 +128,56 @@ public final class VirtualDeviceManager {
            mVirtualDevice = virtualDevice;
        }

        /**
         * 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 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 Either 0, or {@link #DISPLAY_FLAG_TRUSTED}.
         * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
         * @param handler The handler on which the listener should be invoked, or null
         * if the listener should be invoked on the calling thread's looper.
         * @return The newly created virtual display, or {@code null} if the application could
         * not create the virtual display.
         *
         * @see DisplayManager#createVirtualDisplay
         * @hide
         */
        // TODO(b/194949534): Unhide this API
        // Suppress "ExecutorRegistration" because DisplayManager.createVirtualDisplay takes a
        // handler
        @SuppressLint("ExecutorRegistration")
        @Nullable
        public VirtualDisplay createVirtualDisplay(
                int width,
                int height,
                int densityDpi,
                @Nullable Surface surface,
                @DisplayFlags int flags,
                @Nullable Handler handler,
                @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.
            DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
            // DisplayManager will call into VirtualDeviceManagerInternal to register the
            // created displays.
            return displayManager.createVirtualDisplay(
                    mVirtualDevice,
                    new VirtualDisplayConfig.Builder(
                            getVirtualDisplayName(), width, height, densityDpi)
                            .setSurface(surface)
                            .setFlags(getVirtualDisplayFlags(flags))
                            .build(),
                    callback,
                    handler);
        }

        /**
         * Closes the virtual device, stopping and tearing down any virtual displays,
         * audio policies, and event injection that's currently in progress.
@@ -186,5 +272,25 @@ public final class VirtualDeviceManager {
                throw e.rethrowFromSystemServer();
            }
        }

        private int getVirtualDisplayFlags(@DisplayFlags int flags) {
            int virtualDisplayFlags = DEFAULT_VIRTUAL_DISPLAY_FLAGS;
            if ((flags & DISPLAY_FLAG_TRUSTED) != 0) {
                virtualDisplayFlags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
            }
            return virtualDisplayFlags;
        }

        private String getVirtualDisplayName() {
            try {
                // Currently this just use the association ID, which means all of the virtual
                // displays created using the same virtual device will have the same name. The name
                // should only be used for informational purposes, and not for identifying the
                // display in code.
                return "VirtualDevice_" + mVirtualDevice.getAssociationId();
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
    @VisibleForTesting
    final List<Integer> mVirtualDisplayIds = new ArrayList<>();
    private final OnDeviceCloseListener mListener;
    private final IBinder mAppToken;

    VirtualDeviceImpl(Context context, AssociationInfo associationInfo,
            IBinder token, int ownerUid, OnDeviceCloseListener listener) {
@@ -69,6 +70,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        mGenericWindowPolicyController = new GenericWindowPolicyController(FLAG_SECURE,
                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
        mOwnerUid = ownerUid;
        mAppToken = token;
        if (inputController == null) {
            mInputController = new InputController(mVirtualDeviceLock);
        } else {
@@ -90,6 +92,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
    @Override // Binder call
    public void close() {
        mListener.onClose(mAssociationInfo.getId());
        mAppToken.unlinkToDeath(this, 0);
        mInputController.close();
    }