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

Commit 3be6d3f6 authored by Biswarup Pal's avatar Biswarup Pal
Browse files

Add API for virtual camera device policy and lens facing

- DEVICE_POLICY_DEFAULT doesn't allow the creation of any
virtual cameras.
- DEVICE_POLICY_CUSTOM allows the creation of virtual cameras,
but every virtual device can have at most one virtual camera
with LENS_FACING_FRONT and one virtual camera with LENS_FACING_BACK.

Note that this change doesn't yet add device awareness to the camera
framework.

Test: atest VirtualCameraControllerTest
Test: atest CtsVirtualDevicesCameraTestCases
Bug: 310857519
Change-Id: I5a1e7336e682dfcbd09e775f19dc53659cc77d25
parent bc7bab29
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -3221,6 +3221,7 @@ package android.companion.virtual {
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
    method @NonNull public android.content.Context createContext();
    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 @FlaggedApi("android.companion.virtual.flags.virtual_camera") @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.camera.VirtualCamera createVirtualCamera(@NonNull android.companion.virtual.camera.VirtualCameraConfig);
    method @Deprecated @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(@NonNull android.hardware.display.VirtualDisplayConfig, @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.input.VirtualDpadConfig);
@@ -3274,6 +3275,7 @@ package android.companion.virtual {
    field @Deprecated public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
    field @FlaggedApi("android.companion.virtual.flags.dynamic_policy") public static final int POLICY_TYPE_ACTIVITY = 3; // 0x3
    field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
    field @FlaggedApi("android.companion.virtual.flags.virtual_camera") public static final int POLICY_TYPE_CAMERA = 5; // 0x5
    field @FlaggedApi("android.companion.virtual.flags.cross_device_clipboard") public static final int POLICY_TYPE_CLIPBOARD = 4; // 0x4
    field public static final int POLICY_TYPE_RECENTS = 2; // 0x2
    field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
@@ -3361,6 +3363,7 @@ package android.companion.virtual.camera {
  @FlaggedApi("android.companion.virtual.flags.virtual_camera") public final class VirtualCameraConfig implements android.os.Parcelable {
    method public int describeContents();
    method public int getLensFacing();
    method @NonNull public String getName();
    method public int getSensorOrientation();
    method @NonNull public java.util.Set<android.companion.virtual.camera.VirtualCameraStreamConfig> getStreamConfigs();
@@ -3376,6 +3379,7 @@ package android.companion.virtual.camera {
    ctor public VirtualCameraConfig.Builder();
    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder addStreamConfig(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int);
    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig build();
    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setLensFacing(int);
    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setName(@NonNull String);
    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setSensorOrientation(int);
    method @NonNull public android.companion.virtual.camera.VirtualCameraConfig.Builder setVirtualCameraCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.camera.VirtualCameraCallback);
+7 −4
Original line number Diff line number Diff line
@@ -886,11 +886,14 @@ public final class VirtualDeviceManager {
        }

        /**
         * Creates a new virtual camera. If a virtual camera was already created, it will be closed.
         *
         * @param config camera config.
         * @return newly created camera;
         * @hide
         * Creates a new virtual camera with the given {@link VirtualCameraConfig}. A virtual device
         * can create a virtual camera only if it has
         * {@link VirtualDeviceParams#DEVICE_POLICY_CUSTOM} as its
         * {@link VirtualDeviceParams#POLICY_TYPE_CAMERA}.
         *
         * @param config camera configuration.
         * @return newly created camera.
         * @see VirtualDeviceParams#POLICY_TYPE_CAMERA
         */
        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
        @NonNull
+22 −1
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ public final class VirtualDeviceParams implements Parcelable {
     * @hide
     */
    @IntDef(prefix = "POLICY_TYPE_", value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO,
            POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY})
            POLICY_TYPE_RECENTS, POLICY_TYPE_ACTIVITY, POLICY_TYPE_CAMERA})
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface PolicyType {}
@@ -246,6 +246,23 @@ public final class VirtualDeviceParams implements Parcelable {
    @FlaggedApi(Flags.FLAG_CROSS_DEVICE_CLIPBOARD)
    public static final int POLICY_TYPE_CLIPBOARD = 4;

    /**
     * Tells the camera framework how to handle camera requests for the front and back cameras from
     * contexts associated with this virtual device.
     *
     * <ul>
     *     <li>{@link #DEVICE_POLICY_DEFAULT}: Returns the front and back cameras of the default
     *     device.
     *     <li>{@link #DEVICE_POLICY_CUSTOM}: Returns the front and back cameras cameras of the
     *     virtual device. Note that if the virtual device did not create any virtual cameras,
     *     then no front and back cameras will be available.
     * </ul>
     *
     * @see Context#getDeviceId
     */
    @FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
    public static final int POLICY_TYPE_CAMERA = 5;

    private final int mLockState;
    @NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
    @NavigationPolicy
@@ -1153,6 +1170,10 @@ public final class VirtualDeviceParams implements Parcelable {
                mDevicePolicies.delete(POLICY_TYPE_CLIPBOARD);
            }

            if (!Flags.virtualCamera()) {
                mDevicePolicies.delete(POLICY_TYPE_CAMERA);
            }

            if ((mAudioPlaybackSessionId != AUDIO_SESSION_ID_GENERATE
                    || mAudioRecordingSessionId != AUDIO_SESSION_ID_GENERATE)
                    && mDevicePolicies.get(POLICY_TYPE_AUDIO, DEVICE_POLICY_DEFAULT)
+50 −4
Original line number Diff line number Diff line
@@ -24,9 +24,11 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.flags.Flags;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.camera2.CameraMetadata;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.ArraySet;
@@ -48,6 +50,8 @@ import java.util.concurrent.Executor;
@FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
public final class VirtualCameraConfig implements Parcelable {

    private static final int LENS_FACING_UNKNOWN = -1;

    /**
     * Sensor orientation of {@code 0} degrees.
     * @see #getSensorOrientation
@@ -83,14 +87,20 @@ public final class VirtualCameraConfig implements Parcelable {
    private final IVirtualCameraCallback mCallback;
    @SensorOrientation
    private final int mSensorOrientation;
    private final int mLensFacing;

    private VirtualCameraConfig(
            @NonNull String name,
            @NonNull Set<VirtualCameraStreamConfig> streamConfigurations,
            @NonNull Executor executor,
            @NonNull VirtualCameraCallback callback,
            @SensorOrientation int sensorOrientation) {
            @SensorOrientation int sensorOrientation,
            int lensFacing) {
        mName = requireNonNull(name, "Missing name");
        if (lensFacing == LENS_FACING_UNKNOWN) {
            throw new IllegalArgumentException("Lens facing must be set");
        }
        mLensFacing = lensFacing;
        mStreamConfigurations =
                Set.copyOf(requireNonNull(streamConfigurations, "Missing stream configurations"));
        if (mStreamConfigurations.isEmpty()) {
@@ -113,6 +123,7 @@ public final class VirtualCameraConfig implements Parcelable {
                                VirtualCameraStreamConfig.class.getClassLoader(),
                                VirtualCameraStreamConfig.class));
        mSensorOrientation = in.readInt();
        mLensFacing = in.readInt();
    }

    @Override
@@ -127,6 +138,7 @@ public final class VirtualCameraConfig implements Parcelable {
        dest.writeParcelableArray(
                mStreamConfigurations.toArray(new VirtualCameraStreamConfig[0]), flags);
        dest.writeInt(mSensorOrientation);
        dest.writeInt(mLensFacing);
    }

    /**
@@ -168,6 +180,15 @@ public final class VirtualCameraConfig implements Parcelable {
        return mSensorOrientation;
    }

    /**
     * Returns the direction that the virtual camera faces relative to the virtual device's screen.
     *
     * @see Builder#setLensFacing(int)
     */
    public int getLensFacing() {
        return mLensFacing;
    }

    /**
     * Builder for {@link VirtualCameraConfig}.
     *
@@ -176,6 +197,7 @@ public final class VirtualCameraConfig implements Parcelable {
     * <li>A callback must be set with {@link #setVirtualCameraCallback(Executor,
     *     VirtualCameraCallback)}
     * <li>A camera name must be set with {@link #setName(String)}
     * <li>A lens facing must be set with {@link #setLensFacing(int)}
     */
    @FlaggedApi(Flags.FLAG_VIRTUAL_CAMERA)
    public static final class Builder {
@@ -185,9 +207,10 @@ public final class VirtualCameraConfig implements Parcelable {
        private Executor mCallbackExecutor;
        private VirtualCameraCallback mCallback;
        private int mSensorOrientation = SENSOR_ORIENTATION_0;
        private int mLensFacing = LENS_FACING_UNKNOWN;

        /**
         * Set the name of the virtual camera instance.
         * Sets the name of the virtual camera instance.
         */
        @NonNull
        public Builder setName(@NonNull String name) {
@@ -196,7 +219,7 @@ public final class VirtualCameraConfig implements Parcelable {
        }

        /**
         * Add an available stream configuration fot this {@link VirtualCamera}.
         * Adds a supported input stream configuration for this {@link VirtualCamera}.
         *
         * <p>At least one {@link VirtualCameraStreamConfig} must be added.
         *
@@ -266,6 +289,27 @@ public final class VirtualCameraConfig implements Parcelable {
            return this;
        }

        /**
         * Sets the lens facing direction of the virtual camera, can be either
         * {@link CameraMetadata#LENS_FACING_FRONT} or {@link CameraMetadata#LENS_FACING_BACK}.
         *
         * <p>A {@link VirtualDevice} can have at most one {@link VirtualCamera} with
         * {@link CameraMetadata#LENS_FACING_FRONT} and at most one {@link VirtualCamera} with
         * {@link CameraMetadata#LENS_FACING_BACK}.
         *
         * @param lensFacing The direction that the virtual camera faces relative to the device's
         *                   screen.
         */
        @NonNull
        public Builder setLensFacing(int lensFacing) {
            if (lensFacing != CameraMetadata.LENS_FACING_BACK
                    && lensFacing != CameraMetadata.LENS_FACING_FRONT) {
                throw new IllegalArgumentException("Unsupported lens facing: " + lensFacing);
            }
            mLensFacing = lensFacing;
            return this;
        }

        /**
         * Sets the {@link VirtualCameraCallback} used by the framework to communicate with the
         * {@link VirtualCamera} owner.
@@ -289,11 +333,13 @@ public final class VirtualCameraConfig implements Parcelable {
         * Builds a new instance of {@link VirtualCameraConfig}
         *
         * @throws NullPointerException if some required parameters are missing.
         * @throws IllegalArgumentException if any parameter is invalid.
         */
        @NonNull
        public VirtualCameraConfig build() {
            return new VirtualCameraConfig(
                    mName, mStreamConfigurations, mCallbackExecutor, mCallback, mSensorOrientation);
                    mName, mStreamConfigurations, mCallbackExecutor, mCallback, mSensorOrientation,
                    mLensFacing);
        }
    }

+4 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFA
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_ACTIVITY;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CAMERA;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_CLIPBOARD;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
import static android.content.pm.PackageManager.ACTION_REQUEST_PERMISSIONS;
@@ -258,7 +259,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                runningAppsChangedCallback,
                params,
                DisplayManagerGlobal.getInstance(),
                Flags.virtualCamera() ? new VirtualCameraController() : null);
                Flags.virtualCamera()
                        ? new VirtualCameraController(params.getDevicePolicy(POLICY_TYPE_CAMERA))
                        : null);
    }

    @VisibleForTesting
Loading