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

Commit 4450a8b7 authored by Jayant Chowdhary's avatar Jayant Chowdhary Committed by Mina Granic
Browse files

camera2 impl: Allow connecting clients to specify rotation override



CameraManager can specify a rotation override value (obtained through
other framework components in certain scenarios) which can help clients get rotated feeds
from the camera even in cases where the sensor isn't overriden to be portrait -
for example: it could already be a portrait sensor and in some device mode
decided by the WindowManager clients may want rotated sensor feeds.

Bug: 331307771

Test: Desktop compat mode on large screen device

Change-Id: Ie739d47f693d9a2a9f3d958f0b9a53e7bd003490
Signed-off-by: default avatarJayant Chowdhary <jchowdhary@google.com>
parent 1516fd86
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -308,8 +308,10 @@ public class Camera {
     */
    public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
        Context context = ActivityThread.currentApplication().getApplicationContext();
        boolean overrideToPortrait = CameraManager.shouldOverrideToPortrait(context);
        getCameraInfo(cameraId, context, overrideToPortrait, cameraInfo);
        final int rotationOverride = CameraManager.shouldOverrideToPortrait(context)
                ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
                : ICameraService.ROTATION_OVERRIDE_NONE;
        getCameraInfo(cameraId, context, rotationOverride, cameraInfo);
    }

    /**
@@ -320,8 +322,8 @@ public class Camera {
    @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
    @TestApi
    public static void getCameraInfo(int cameraId, @NonNull Context context,
            boolean overrideToPortrait, CameraInfo cameraInfo) {
        _getCameraInfo(cameraId, overrideToPortrait, context.getDeviceId(),
            int rotationOverride, CameraInfo cameraInfo) {
        _getCameraInfo(cameraId, rotationOverride, context.getDeviceId(),
                getDevicePolicyFromContext(context), cameraInfo);
        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
        IAudioService audioService = IAudioService.Stub.asInterface(b);
@@ -336,7 +338,7 @@ public class Camera {
        }
    }

    private native static void _getCameraInfo(int cameraId, boolean overrideToPortrait,
    private native static void _getCameraInfo(int cameraId, int rotationOverride,
            int deviceId, int devicePolicy, CameraInfo cameraInfo);

    private static int getDevicePolicyFromContext(Context context) {
@@ -541,10 +543,13 @@ public class Camera {
        } else {
            mEventHandler = null;
        }
        final int rotationOverride = CameraManager.shouldOverrideToPortrait(context)
                ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
                : ICameraService.ROTATION_OVERRIDE_NONE;

        boolean forceSlowJpegMode = shouldForceSlowJpegMode();
        return native_setup(new WeakReference<>(this), cameraId,
                ActivityThread.currentOpPackageName(), overrideToPortrait, forceSlowJpegMode,
                ActivityThread.currentOpPackageName(), rotationOverride, forceSlowJpegMode,
                context.getDeviceId(), getDevicePolicyFromContext(context));
    }

@@ -629,7 +634,7 @@ public class Camera {

    @UnsupportedAppUsage
    private native int native_setup(Object cameraThis, int cameraId, String packageName,
            boolean overrideToPortrait, boolean forceSlowJpegMode, int deviceId, int devicePolicy);
            int rotationOverride, boolean forceSlowJpegMode, int deviceId, int devicePolicy);

    private native final void native_release();

+33 −10
Original line number Diff line number Diff line
@@ -627,7 +627,8 @@ public final class CameraManager {
                CameraMetadataNative physicalCameraInfo =
                        cameraService.getCameraCharacteristics(physicalCameraId,
                                mContext.getApplicationInfo().targetSdkVersion,
                                /*overrideToPortrait*/ false, DEVICE_ID_DEFAULT,
                                /*rotationOverride*/ ICameraService.ROTATION_OVERRIDE_NONE,
                                DEVICE_ID_DEFAULT,
                                DEVICE_POLICY_DEFAULT);
                StreamConfiguration[] configs = physicalCameraInfo.get(
                        CameraCharacteristics.
@@ -699,7 +700,16 @@ public final class CameraManager {
    @NonNull
    public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId,
            boolean overrideToPortrait) throws CameraAccessException {
        CameraCharacteristics characteristics;
        return getCameraCharacteristics(cameraId,
                overrideToPortrait
                        ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
                        : ICameraService.ROTATION_OVERRIDE_NONE);
    }

    @NonNull
    private CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId,
            int rotationOverride) throws CameraAccessException {
        CameraCharacteristics characteristics = null;
        if (CameraManagerGlobal.sCameraServiceDisabled) {
            throw new IllegalArgumentException("No cameras available on device");
        }
@@ -711,7 +721,7 @@ public final class CameraManager {
            }
            try {
                CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId,
                        mContext.getApplicationInfo().targetSdkVersion, overrideToPortrait,
                        mContext.getApplicationInfo().targetSdkVersion, rotationOverride,
                        mContext.getDeviceId(), getDevicePolicyFromContext(mContext));
                characteristics = prepareCameraCharacteristics(cameraId, info, cameraService);
            } catch (ServiceSpecificException e) {
@@ -926,7 +936,7 @@ public final class CameraManager {
     */
    private CameraDevice openCameraDeviceUserAsync(String cameraId,
            CameraDevice.StateCallback callback, Executor executor, final int uid,
            final int oomScoreOffset, boolean overrideToPortrait) throws CameraAccessException {
            final int oomScoreOffset, int rotationOverride) throws CameraAccessException {
        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
        CameraDevice device = null;
        Map<String, CameraCharacteristics> physicalIdsToChars =
@@ -961,7 +971,7 @@ public final class CameraManager {
                cameraUser = cameraService.connectDevice(callbacks, cameraId,
                    mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
                    oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion,
                    overrideToPortrait, mContext.getDeviceId(),
                        rotationOverride, mContext.getDeviceId(),
                        getDevicePolicyFromContext(mContext));
            } catch (ServiceSpecificException e) {
                if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
@@ -1126,7 +1136,10 @@ public final class CameraManager {
            @Nullable Handler handler,
            @NonNull final CameraDevice.StateCallback callback) throws CameraAccessException {
        openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
                         USE_CALLING_UID, /*oomScoreOffset*/0, overrideToPortrait);
                         USE_CALLING_UID, /*oomScoreOffset*/0,
                         overrideToPortrait
                                 ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
                                 : ICameraService.ROTATION_OVERRIDE_NONE);
    }

    /**
@@ -1239,8 +1252,11 @@ public final class CameraManager {
            throw new IllegalArgumentException(
                    "oomScoreOffset < 0, cannot increase priority of camera client");
        }
        final int rotationOverride = shouldOverrideToPortrait(mContext)
                ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
                : ICameraService.ROTATION_OVERRIDE_NONE;
        openCameraForUid(cameraId, callback, executor, USE_CALLING_UID, oomScoreOffset,
                shouldOverrideToPortrait(mContext));
                rotationOverride);
    }

    /**
@@ -1258,11 +1274,14 @@ public final class CameraManager {
     *             Must be USE_CALLING_UID unless the caller is a trusted service.
     * @param oomScoreOffset
     *             The minimum oom score that cameraservice must see for this client.
     * @param rotationOverride
     *             The type of rotation override (none, override_to_portrait, rotation_only)
     *             that should be followed for this camera id connection
     * @hide
     */
    public void openCameraForUid(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
            int clientUid, int oomScoreOffset, boolean overrideToPortrait)
            int clientUid, int oomScoreOffset, int rotationOverride)
            throws CameraAccessException {

        if (cameraId == null) {
@@ -1275,7 +1294,7 @@ public final class CameraManager {
        }

        openCameraDeviceUserAsync(cameraId, callback, executor, clientUid, oomScoreOffset,
                overrideToPortrait);
                rotationOverride);
    }

    /**
@@ -1296,8 +1315,12 @@ public final class CameraManager {
    public void openCameraForUid(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
            int clientUid) throws CameraAccessException {
        final int rotationOverride = shouldOverrideToPortrait(mContext)
                ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT
                : ICameraService.ROTATION_OVERRIDE_NONE;

        openCameraForUid(cameraId, callback, executor, clientUid, /*oomScoreOffset*/0,
                shouldOverrideToPortrait(mContext));
                rotationOverride);
    }

    /**
+7 −7
Original line number Diff line number Diff line
@@ -529,7 +529,7 @@ static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz
}

static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jint cameraId,
                                                  jboolean overrideToPortrait, jint deviceId,
                                                  jint rotationOverride, jint deviceId,
                                                  jint devicePolicy, jobject info_obj) {
    CameraInfo cameraInfo;
    if (cameraId >= Camera::getNumberOfCameras(deviceId, devicePolicy) || cameraId < 0) {
@@ -538,7 +538,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jin
        return;
    }

    status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, deviceId, devicePolicy,
    status_t rc = Camera::getCameraInfo(cameraId, rotationOverride, deviceId, devicePolicy,
                                        &cameraInfo);
    if (rc != NO_ERROR) {
        jniThrowRuntimeException(env, "Fail to get camera info");
@@ -557,7 +557,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jin
// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
                                                 jint cameraId, jstring clientPackageName,
                                                 jboolean overrideToPortrait,
                                                 jint rotationOverride,
                                                 jboolean forceSlowJpegMode, jint deviceId,
                                                 jint devicePolicy) {
    // Convert jstring to String16
@@ -571,7 +571,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj
    int targetSdkVersion = android_get_application_target_sdk_version();
    sp<Camera> camera =
            Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID,
                            targetSdkVersion, overrideToPortrait, forceSlowJpegMode, deviceId,
                            targetSdkVersion, rotationOverride, forceSlowJpegMode, deviceId,
                            devicePolicy);
    if (camera == NULL) {
        return -EACCES;
@@ -600,7 +600,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj

    // Update default display orientation in case the sensor is reverse-landscape
    CameraInfo cameraInfo;
    status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, deviceId, devicePolicy,
    status_t rc = Camera::getCameraInfo(cameraId, rotationOverride, deviceId, devicePolicy,
                                        &cameraInfo);
    if (rc != NO_ERROR) {
        ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc);
@@ -1057,9 +1057,9 @@ static int32_t android_hardware_Camera_getAudioRestriction(

static const JNINativeMethod camMethods[] = {
        {"_getNumberOfCameras", "(II)I", (void *)android_hardware_Camera_getNumberOfCameras},
        {"_getCameraInfo", "(IZIILandroid/hardware/Camera$CameraInfo;)V",
        {"_getCameraInfo", "(IIIILandroid/hardware/Camera$CameraInfo;)V",
         (void *)android_hardware_Camera_getCameraInfo},
        {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;ZZII)I",
        {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;IZII)I",
         (void *)android_hardware_Camera_native_setup},
        {"native_release", "()V", (void *)android_hardware_Camera_release},
        {"setPreviewSurface", "(Landroid/view/Surface;)V",
+5 −3
Original line number Diff line number Diff line
@@ -89,7 +89,8 @@ public class CameraBinderTest extends AndroidTestCase {
    public void testCameraInfo() throws Exception {
        for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
            CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId,
                    /*overrideToPortrait*/false, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
                    ICameraService.ROTATION_OVERRIDE_NONE, DEVICE_ID_DEFAULT,
                    DEVICE_POLICY_DEFAULT);
            assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
            assertTrue("Orientation was not set for camera " + cameraId,
                    info.info.orientation != -1);
@@ -164,7 +165,7 @@ public class CameraBinderTest extends AndroidTestCase {
                            ICameraService.USE_CALLING_UID,
                            ICameraService.USE_CALLING_PID,
                            getContext().getApplicationInfo().targetSdkVersion,
                            /*overrideToPortrait*/false,
                            ICameraService.ROTATION_OVERRIDE_NONE,
                            /*forceSlowJpegMode*/false,
                            DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
@@ -266,7 +267,8 @@ public class CameraBinderTest extends AndroidTestCase {
                        clientPackageName, clientAttributionTag,
                        ICameraService.USE_CALLING_UID, 0 /*oomScoreOffset*/,
                        getContext().getApplicationInfo().targetSdkVersion,
                        /*overrideToPortrait*/false, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
                        ICameraService.ROTATION_OVERRIDE_NONE, DEVICE_ID_DEFAULT,
                        DEVICE_POLICY_DEFAULT);
            assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);

            Log.v(TAG, String.format("Camera %s connected", cameraId));
+3 −2
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
        mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
                clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID,
                /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion,
                /*overrideToPortrait*/false, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
                ICameraService.ROTATION_OVERRIDE_NONE, DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);
        assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
        mHandlerThread = new HandlerThread(TAG);
        mHandlerThread.start();
@@ -415,7 +415,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
    @SmallTest
    public void testCameraCharacteristics() throws RemoteException {
        CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId,
                getContext().getApplicationInfo().targetSdkVersion, /*overrideToPortrait*/false,
                getContext().getApplicationInfo().targetSdkVersion,
                ICameraService.ROTATION_OVERRIDE_NONE,
                DEVICE_ID_DEFAULT, DEVICE_POLICY_DEFAULT);

        assertFalse(info.isEmpty());