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

Commit 6b1695bd authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow virtual external cameras on default policy" into main

parents 873d8d17 72f69c6e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1083,6 +1083,7 @@ public final class VirtualDeviceManager {
         * @throws UnsupportedOperationException if virtual camera isn't supported on this device.
         * @see VirtualDeviceParams#POLICY_TYPE_CAMERA
         */
        // TODO: b/406957588 - Update documentation after 25Q2 release
        @NonNull
        public VirtualCamera createVirtualCamera(@NonNull VirtualCameraConfig config) {
            return mVirtualDeviceInternal.createVirtualCamera(Objects.requireNonNull(config));
+4 −5
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ import android.companion.virtual.VirtualDevice;
import android.companion.virtualdevice.flags.Flags;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraMetadata;
import android.os.Parcel;
import android.os.Parcelable;
@@ -283,17 +282,17 @@ public final class VirtualCameraConfig implements Parcelable {
        }

        /**
         * Sets the lens facing direction of the virtual camera.
         * 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}, though it can create multiple cameras with
         * {@link CameraMetadata#LENS_FACING_EXTERNAL}.
         * {@link CameraMetadata#LENS_FACING_BACK}.
         *
         * @param lensFacing The direction that the virtual camera faces relative to the device's
         *                   screen.
         * @see CameraCharacteristics#LENS_FACING
         */
        // TODO: b/406957588 - Update documentation after 25Q2 release
        @NonNull
        public Builder setLensFacing(int lensFacing) {
            boolean allowLensFacing = lensFacing == CameraMetadata.LENS_FACING_FRONT
+15 −8
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.companion.virtualcamera.IVirtualCameraService;
import android.companion.virtualcamera.VirtualCameraConfiguration;
import android.companion.virtualdevice.flags.Flags;
import android.content.AttributionSource;
import android.content.Context;
import android.hardware.camera2.CameraMetadata;
import android.os.Binder;
import android.os.IBinder;
@@ -195,21 +196,25 @@ public final class VirtualCameraController implements IBinder.DeathRecipient {
    }

    private void checkConfigByPolicy(VirtualCameraConfig config) {
        // Multiple external cameras are allowed on any policy
        if (Flags.externalVirtualCameras()
                && CameraMetadata.LENS_FACING_EXTERNAL == config.getLensFacing()) {
            return;
        }

        if (mCameraPolicy == DEVICE_POLICY_DEFAULT) {
            throw new IllegalArgumentException(
                    "Cannot create virtual camera with DEVICE_POLICY_DEFAULT for "
                            + "POLICY_TYPE_CAMERA");
        } else if (isNonExternalLensFacingAlreadyPresent(config.getLensFacing())) {
                            + "POLICY_TYPE_CAMERA and lens facing " + config.getLensFacing());
        }

        if (isLensFacingAlreadyPresent(config.getLensFacing())) {
            throw new IllegalArgumentException(
                    "Only a single virtual camera can be created with lens facing "
                            + config.getLensFacing());
        }
    }

    private boolean isNonExternalLensFacingAlreadyPresent(int lensFacing) {
        if (Flags.externalVirtualCameras() && CameraMetadata.LENS_FACING_EXTERNAL == lensFacing) {
            return false;
        }
    private boolean isLensFacingAlreadyPresent(int lensFacing) {
        synchronized (mCameras) {
            for (CameraDescriptor cameraDescriptor : mCameras.values()) {
                if (cameraDescriptor.mConfig.getLensFacing() == lensFacing) {
@@ -255,8 +260,10 @@ public final class VirtualCameraController implements IBinder.DeathRecipient {
    private boolean registerCameraWithService(VirtualCameraConfig config) throws RemoteException {
        VirtualCameraConfiguration serviceConfiguration = getServiceCameraConfiguration(config);
        synchronized (mServiceLock) {
            int ownerDeviceId =
                    mCameraPolicy != DEVICE_POLICY_DEFAULT ? mDeviceId : Context.DEVICE_ID_DEFAULT;
            return mVirtualCameraService.registerCamera(config.getCallback().asBinder(),
                    serviceConfiguration, mDeviceId);
                    serviceConfiguration, ownerDeviceId);
        }
    }

+34 −3
Original line number Diff line number Diff line
@@ -177,7 +177,7 @@ public class VirtualCameraControllerTest {
                CAMERA_LENS_FACING_2);
    }

    @Parameters(method = "getSingleCamerasLensFacingDirections")
    @Parameters(method = "getFixedCamerasLensFacingDirections")
    @Test
    public void registerMultipleSameLensFacingCameras_withCustomCameraPolicy_throwsException(
            int lensFacing) {
@@ -215,7 +215,7 @@ public class VirtualCameraControllerTest {
                        LENS_FACING_EXTERNAL), AttributionSource.myAttributionSource()));
    }

    @Parameters(method = "getAllLensFacingDirections")
    @Parameters(method = "getFixedCamerasLensFacingDirections")
    @Test
    public void registerCamera_withDefaultCameraPolicy_throwsException(int lensFacing) {
        mVirtualCameraController.close();
@@ -229,6 +229,37 @@ public class VirtualCameraControllerTest {
                        AttributionSource.myAttributionSource()));
    }

    @Test
    @EnableFlags(Flags.FLAG_EXTERNAL_VIRTUAL_CAMERAS)
    public void registerCamera_withDefaultCameraPolicy_allowsMultipleExternal() {
        mVirtualCameraController.close();
        mVirtualCameraController = new VirtualCameraController(mVirtualCameraServiceMock,
                DEVICE_POLICY_DEFAULT, DEVICE_ID);

        mVirtualCameraController.registerCamera(
                createVirtualCameraConfig(CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1,
                        CAMERA_MAX_FPS_1, CAMERA_NAME_1, CAMERA_SENSOR_ORIENTATION_1,
                        LENS_FACING_EXTERNAL), AttributionSource.myAttributionSource());

        mVirtualCameraController.registerCamera(
                createVirtualCameraConfig(CAMERA_WIDTH_2, CAMERA_HEIGHT_2, CAMERA_FORMAT_2,
                        CAMERA_MAX_FPS_2, CAMERA_NAME_2, CAMERA_SENSOR_ORIENTATION_2,
                        LENS_FACING_EXTERNAL), AttributionSource.myAttributionSource());
    }

    @Test
    @DisableFlags(Flags.FLAG_EXTERNAL_VIRTUAL_CAMERAS)
    public void registerCamera_withDefaultCameraPolicy_throwsException_whenNotSupported() {
        mVirtualCameraController.close();
        mVirtualCameraController = new VirtualCameraController(mVirtualCameraServiceMock,
                DEVICE_POLICY_DEFAULT, DEVICE_ID);

        assertThrows(IllegalArgumentException.class, () -> mVirtualCameraController.registerCamera(
                createVirtualCameraConfig(CAMERA_WIDTH_1, CAMERA_HEIGHT_1, CAMERA_FORMAT_1,
                        CAMERA_MAX_FPS_1, CAMERA_NAME_1, CAMERA_SENSOR_ORIENTATION_1,
                        LENS_FACING_EXTERNAL), AttributionSource.myAttributionSource()));
    }

    private VirtualCameraConfig createVirtualCameraConfig(
            int width, int height, int format, int maximumFramesPerSecond,
            String name, int sensorOrientation, int lensFacing) {
@@ -252,7 +283,7 @@ public class VirtualCameraControllerTest {
    }

    @SuppressWarnings("unused") // Parameter for parametrized tests
    private static Integer[] getSingleCamerasLensFacingDirections() {
    private static Integer[] getFixedCamerasLensFacingDirections() {
        return new Integer[]{
                LENS_FACING_BACK,
                LENS_FACING_FRONT,