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

Commit a6c807eb authored by Dorin Drimus's avatar Dorin Drimus Committed by Android (Google) Code Review
Browse files

Merge "Enable virtual external cameras (base)" into main

parents 0864bd93 fa6b2d9b
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -24,8 +24,10 @@ import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
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;
@@ -281,20 +283,25 @@ public final class VirtualCameraConfig implements Parcelable {
        }

        /**
         * Sets the lens facing direction of the virtual camera, can be either
         * {@link CameraMetadata#LENS_FACING_FRONT} or {@link CameraMetadata#LENS_FACING_BACK}.
         * Sets the lens facing direction of the virtual camera.
         *
         * <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}.
         * {@link CameraMetadata#LENS_FACING_BACK}, though it can create multiple cameras with
         * {@link CameraMetadata#LENS_FACING_EXTERNAL}.
         *
         * @param lensFacing The direction that the virtual camera faces relative to the device's
         *                   screen.
         * @see CameraCharacteristics#LENS_FACING
         */
        @NonNull
        public Builder setLensFacing(int lensFacing) {
            if (lensFacing != CameraMetadata.LENS_FACING_BACK
                    && lensFacing != CameraMetadata.LENS_FACING_FRONT) {
            boolean allowLensFacing = lensFacing == CameraMetadata.LENS_FACING_FRONT
                    || lensFacing == CameraMetadata.LENS_FACING_BACK;
            if (Flags.externalVirtualCameras()) {
                allowLensFacing |= lensFacing == CameraMetadata.LENS_FACING_EXTERNAL;
            }
            if (!allowLensFacing) {
                throw new IllegalArgumentException("Unsupported lens facing: " + lensFacing);
            }
            mLensFacing = lensFacing;
+7 −2
Original line number Diff line number Diff line
@@ -26,7 +26,9 @@ import android.companion.virtual.VirtualDeviceParams.DevicePolicy;
import android.companion.virtual.camera.VirtualCameraConfig;
import android.companion.virtualcamera.IVirtualCameraService;
import android.companion.virtualcamera.VirtualCameraConfiguration;
import android.companion.virtualdevice.flags.Flags;
import android.content.AttributionSource;
import android.hardware.camera2.CameraMetadata;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
@@ -197,14 +199,17 @@ public final class VirtualCameraController implements IBinder.DeathRecipient {
            throw new IllegalArgumentException(
                    "Cannot create virtual camera with DEVICE_POLICY_DEFAULT for "
                            + "POLICY_TYPE_CAMERA");
        } else if (isLensFacingAlreadyPresent(config.getLensFacing())) {
        } else if (isNonExternalLensFacingAlreadyPresent(config.getLensFacing())) {
            throw new IllegalArgumentException(
                    "Only a single virtual camera can be created with lens facing "
                            + config.getLensFacing());
        }
    }

    private boolean isLensFacingAlreadyPresent(int lensFacing) {
    private boolean isNonExternalLensFacingAlreadyPresent(int lensFacing) {
        if (Flags.externalVirtualCameras() && CameraMetadata.LENS_FACING_EXTERNAL == lensFacing) {
            return false;
        }
        synchronized (mCameras) {
            for (CameraDescriptor cameraDescriptor : mCameras.values()) {
                if (cameraDescriptor.mConfig.getLensFacing() == lensFacing) {
+47 −3
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.companion.virtual.camera.VirtualCameraConfig.SENSOR_ORIENT
import static android.graphics.ImageFormat.YUV_420_888;
import static android.graphics.PixelFormat.RGBA_8888;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_BACK;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_EXTERNAL;
import static android.hardware.camera2.CameraMetadata.LENS_FACING_FRONT;

import static com.google.common.truth.Truth.assertThat;
@@ -38,11 +39,15 @@ import android.companion.virtual.camera.VirtualCameraCallback;
import android.companion.virtual.camera.VirtualCameraConfig;
import android.companion.virtualcamera.IVirtualCameraService;
import android.companion.virtualcamera.VirtualCameraConfiguration;
import android.companion.virtualdevice.flags.Flags;
import android.content.AttributionSource;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.testing.TestableLooper;

import junitparams.JUnitParamsRunner;
@@ -50,12 +55,14 @@ import junitparams.Parameters;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

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

@Presubmit
@@ -89,6 +96,8 @@ public class VirtualCameraControllerTest {
    private final HandlerExecutor mCallbackHandler =
            new HandlerExecutor(new Handler(Looper.getMainLooper()));

    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
@@ -168,7 +177,7 @@ public class VirtualCameraControllerTest {
                CAMERA_LENS_FACING_2);
    }

    @Parameters(method = "getAllLensFacingDirections")
    @Parameters(method = "getSingleCamerasLensFacingDirections")
    @Test
    public void registerMultipleSameLensFacingCameras_withCustomCameraPolicy_throwsException(
            int lensFacing) {
@@ -182,6 +191,30 @@ public class VirtualCameraControllerTest {
                        AttributionSource.myAttributionSource()));
    }

    @Test
    @EnableFlags(Flags.FLAG_EXTERNAL_VIRTUAL_CAMERAS)
    public void registerMultipleExternalCameras_withCustomCameraPolicy_succeeds() {
        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 registerExternalCameras_withCustomCameraPolicy_throwsException_whenNotSupported() {
        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()));
    }

    @Parameters(method = "getAllLensFacingDirections")
    @Test
    public void registerCamera_withDefaultCameraPolicy_throwsException(int lensFacing) {
@@ -218,10 +251,21 @@ public class VirtualCameraControllerTest {
        assertThat(configuration.lensFacing).isEqualTo(lensFacing);
    }

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

    @SuppressWarnings("unused") // Parameter for parametrized tests
    private static List<Integer> getAllLensFacingDirections() {
        List<Integer> lensFacingDirections = new ArrayList<>(
                List.of(LENS_FACING_BACK, LENS_FACING_FRONT));
        if (Flags.externalVirtualCameras()) {
            lensFacingDirections.add(LENS_FACING_EXTERNAL);
        }
        return lensFacingDirections;
    }
}