diff options
6 files changed, 116 insertions, 110 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 25c4652e9112..16f09655b687 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1157,6 +1157,7 @@ package android.hardware.camera2 { public final class CameraManager { method public String[] getCameraIdListNoLazy() throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; + field public static final long OVERRIDE_FRONT_CAMERA_APP_COMPAT = 250678880L; // 0xef10e60L } public abstract static class CameraManager.AvailabilityCallback { diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 3bdd39f5d7d7..5291d2b73891 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -29,12 +29,14 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.ActivityThread; import android.app.AppOpsManager; +import android.app.compat.CompatChanges; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.graphics.SurfaceTexture; +import android.hardware.camera2.CameraManager; import android.media.AudioAttributes; import android.media.IAudioService; import android.os.Build; @@ -45,6 +47,7 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RSIllegalArgumentException; @@ -281,6 +284,14 @@ public class Camera { */ public native static int getNumberOfCameras(); + private static final boolean sLandscapeToPortrait = + SystemProperties.getBoolean(CameraManager.LANDSCAPE_TO_PORTRAIT_PROP, false); + + private static boolean shouldOverrideToPortrait() { + return CompatChanges.isChangeEnabled(CameraManager.OVERRIDE_FRONT_CAMERA_APP_COMPAT) + && sLandscapeToPortrait; + } + /** * Returns the information about a particular camera. * If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1. @@ -290,7 +301,9 @@ public class Camera { * low-level failure). */ public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) { - _getCameraInfo(cameraId, cameraInfo); + boolean overrideToPortrait = shouldOverrideToPortrait(); + + _getCameraInfo(cameraId, overrideToPortrait, cameraInfo); IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); IAudioService audioService = IAudioService.Stub.asInterface(b); try { @@ -303,7 +316,8 @@ public class Camera { Log.e(TAG, "Audio service is unavailable for queries"); } } - private native static void _getCameraInfo(int cameraId, CameraInfo cameraInfo); + private native static void _getCameraInfo(int cameraId, boolean overrideToPortrait, + CameraInfo cameraInfo); /** * Information about a camera @@ -484,8 +498,9 @@ public class Camera { mEventHandler = null; } + boolean overrideToPortrait = shouldOverrideToPortrait(); return native_setup(new WeakReference<Camera>(this), cameraId, - ActivityThread.currentOpPackageName()); + ActivityThread.currentOpPackageName(), overrideToPortrait); } /** used by Camera#open, Camera#open(int) */ @@ -555,7 +570,8 @@ public class Camera { } @UnsupportedAppUsage - private native int native_setup(Object cameraThis, int cameraId, String packageName); + private native int native_setup(Object cameraThis, int cameraId, String packageName, + boolean overrideToPortrait); private native final void native_release(); diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index f858227a0f1d..127bb0fa3b4c 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -23,6 +23,10 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; +import android.compat.annotation.Overridable; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Point; @@ -104,6 +108,24 @@ public final class CameraManager { private final boolean mHasOpenCloseListenerPermission; /** + * Force camera output to be rotated to portrait orientation on landscape cameras. + * Many apps do not handle this situation and display stretched images otherwise. + * @hide + */ + @ChangeId + @Overridable + @Disabled + @TestApi + public static final long OVERRIDE_FRONT_CAMERA_APP_COMPAT = 250678880L; + + /** + * System property for allowing the above + * @hide + */ + public static final String LANDSCAPE_TO_PORTRAIT_PROP = + "camera.enable_landscape_to_portrait"; + + /** * @hide */ public CameraManager(Context context) { @@ -526,7 +548,8 @@ public final class CameraManager { for (String physicalCameraId : physicalCameraIds) { CameraMetadataNative physicalCameraInfo = cameraService.getCameraCharacteristics(physicalCameraId, - mContext.getApplicationInfo().targetSdkVersion); + mContext.getApplicationInfo().targetSdkVersion, + /*overrideToPortrait*/false); StreamConfiguration[] configs = physicalCameraInfo.get( CameraCharacteristics. SCALER_PHYSICAL_CAMERA_MULTI_RESOLUTION_STREAM_CONFIGURATIONS); @@ -585,8 +608,9 @@ public final class CameraManager { try { Size displaySize = getDisplaySize(); + boolean overrideToPortrait = shouldOverrideToPortrait(); CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId, - mContext.getApplicationInfo().targetSdkVersion); + mContext.getApplicationInfo().targetSdkVersion, overrideToPortrait); try { info.setCameraId(Integer.parseInt(cameraId)); } catch (NumberFormatException e) { @@ -703,9 +727,12 @@ public final class CameraManager { ICameraService.ERROR_DISCONNECTED, "Camera service is currently unavailable"); } + + boolean overrideToPortrait = shouldOverrideToPortrait(); cameraUser = cameraService.connectDevice(callbacks, cameraId, - mContext.getOpPackageName(), mContext.getAttributionTag(), uid, - oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion); + mContext.getOpPackageName(), mContext.getAttributionTag(), uid, + oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion, + overrideToPortrait); } catch (ServiceSpecificException e) { if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) { throw new AssertionError("Should've gone down the shim path"); @@ -1133,6 +1160,11 @@ public final class CameraManager { return CameraManagerGlobal.get().getTorchStrengthLevel(cameraId); } + private static boolean shouldOverrideToPortrait() { + return CompatChanges.isChangeEnabled(OVERRIDE_FRONT_CAMERA_APP_COMPAT) + && CameraManagerGlobal.sLandscapeToPortrait; + } + /** * A callback for camera devices becoming available or unavailable to open. * @@ -1579,6 +1611,9 @@ public final class CameraManager { public static final boolean sCameraServiceDisabled = SystemProperties.getBoolean("config.disable_cameraservice", false); + public static final boolean sLandscapeToPortrait = + SystemProperties.getBoolean(LANDSCAPE_TO_PORTRAIT_PROP, false); + public static CameraManagerGlobal get() { return gCameraManager; } diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 365a18d174c9..a8abe50a9755 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -529,9 +529,8 @@ static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz return Camera::getNumberOfCameras(); } -static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, - jint cameraId, jobject info_obj) -{ +static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, jint cameraId, + jboolean overrideToPortrait, jobject info_obj) { CameraInfo cameraInfo; if (cameraId >= Camera::getNumberOfCameras() || cameraId < 0) { ALOGE("%s: Unknown camera ID %d", __FUNCTION__, cameraId); @@ -539,7 +538,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, return; } - status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); + status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, &cameraInfo); if (rc != NO_ERROR) { jniThrowRuntimeException(env, "Fail to get camera info"); return; @@ -555,9 +554,9 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, } // connect to camera service -static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, - jobject weak_this, jint cameraId, jstring clientPackageName) -{ +static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, + jint cameraId, jstring clientPackageName, + jboolean overrideToPortrait) { // Convert jstring to String16 const char16_t *rawClientName = reinterpret_cast<const char16_t*>( env->GetStringChars(clientPackageName, NULL)); @@ -567,8 +566,9 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, reinterpret_cast<const jchar*>(rawClientName)); int targetSdkVersion = android_get_application_target_sdk_version(); - sp<Camera> camera = Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, - Camera::USE_CALLING_PID, targetSdkVersion); + sp<Camera> camera = + Camera::connect(cameraId, clientName, Camera::USE_CALLING_UID, Camera::USE_CALLING_PID, + targetSdkVersion, overrideToPortrait); if (camera == NULL) { return -EACCES; } @@ -596,7 +596,7 @@ static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, // Update default display orientation in case the sensor is reverse-landscape CameraInfo cameraInfo; - status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo); + status_t rc = Camera::getCameraInfo(cameraId, overrideToPortrait, &cameraInfo); if (rc != NO_ERROR) { ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc); return rc; @@ -1051,93 +1051,43 @@ static int32_t android_hardware_Camera_getAudioRestriction( //------------------------------------------------- static const JNINativeMethod camMethods[] = { - { "getNumberOfCameras", - "()I", - (void *)android_hardware_Camera_getNumberOfCameras }, - { "_getCameraInfo", - "(ILandroid/hardware/Camera$CameraInfo;)V", - (void*)android_hardware_Camera_getCameraInfo }, - { "native_setup", - "(Ljava/lang/Object;ILjava/lang/String;)I", - (void*)android_hardware_Camera_native_setup }, - { "native_release", - "()V", - (void*)android_hardware_Camera_release }, - { "setPreviewSurface", - "(Landroid/view/Surface;)V", - (void *)android_hardware_Camera_setPreviewSurface }, - { "setPreviewTexture", - "(Landroid/graphics/SurfaceTexture;)V", - (void *)android_hardware_Camera_setPreviewTexture }, - { "setPreviewCallbackSurface", - "(Landroid/view/Surface;)V", - (void *)android_hardware_Camera_setPreviewCallbackSurface }, - { "startPreview", - "()V", - (void *)android_hardware_Camera_startPreview }, - { "_stopPreview", - "()V", - (void *)android_hardware_Camera_stopPreview }, - { "previewEnabled", - "()Z", - (void *)android_hardware_Camera_previewEnabled }, - { "setHasPreviewCallback", - "(ZZ)V", - (void *)android_hardware_Camera_setHasPreviewCallback }, - { "_addCallbackBuffer", - "([BI)V", - (void *)android_hardware_Camera_addCallbackBuffer }, - { "native_autoFocus", - "()V", - (void *)android_hardware_Camera_autoFocus }, - { "native_cancelAutoFocus", - "()V", - (void *)android_hardware_Camera_cancelAutoFocus }, - { "native_takePicture", - "(I)V", - (void *)android_hardware_Camera_takePicture }, - { "native_setParameters", - "(Ljava/lang/String;)V", - (void *)android_hardware_Camera_setParameters }, - { "native_getParameters", - "()Ljava/lang/String;", - (void *)android_hardware_Camera_getParameters }, - { "reconnect", - "()V", - (void*)android_hardware_Camera_reconnect }, - { "lock", - "()V", - (void*)android_hardware_Camera_lock }, - { "unlock", - "()V", - (void*)android_hardware_Camera_unlock }, - { "startSmoothZoom", - "(I)V", - (void *)android_hardware_Camera_startSmoothZoom }, - { "stopSmoothZoom", - "()V", - (void *)android_hardware_Camera_stopSmoothZoom }, - { "setDisplayOrientation", - "(I)V", - (void *)android_hardware_Camera_setDisplayOrientation }, - { "_enableShutterSound", - "(Z)Z", - (void *)android_hardware_Camera_enableShutterSound }, - { "_startFaceDetection", - "(I)V", - (void *)android_hardware_Camera_startFaceDetection }, - { "_stopFaceDetection", - "()V", - (void *)android_hardware_Camera_stopFaceDetection}, - { "enableFocusMoveCallback", - "(I)V", - (void *)android_hardware_Camera_enableFocusMoveCallback}, - { "setAudioRestriction", - "(I)V", - (void *)android_hardware_Camera_setAudioRestriction}, - { "getAudioRestriction", - "()I", - (void *)android_hardware_Camera_getAudioRestriction}, + {"getNumberOfCameras", "()I", (void *)android_hardware_Camera_getNumberOfCameras}, + {"_getCameraInfo", "(IZLandroid/hardware/Camera$CameraInfo;)V", + (void *)android_hardware_Camera_getCameraInfo}, + {"native_setup", "(Ljava/lang/Object;ILjava/lang/String;Z)I", + (void *)android_hardware_Camera_native_setup}, + {"native_release", "()V", (void *)android_hardware_Camera_release}, + {"setPreviewSurface", "(Landroid/view/Surface;)V", + (void *)android_hardware_Camera_setPreviewSurface}, + {"setPreviewTexture", "(Landroid/graphics/SurfaceTexture;)V", + (void *)android_hardware_Camera_setPreviewTexture}, + {"setPreviewCallbackSurface", "(Landroid/view/Surface;)V", + (void *)android_hardware_Camera_setPreviewCallbackSurface}, + {"startPreview", "()V", (void *)android_hardware_Camera_startPreview}, + {"_stopPreview", "()V", (void *)android_hardware_Camera_stopPreview}, + {"previewEnabled", "()Z", (void *)android_hardware_Camera_previewEnabled}, + {"setHasPreviewCallback", "(ZZ)V", (void *)android_hardware_Camera_setHasPreviewCallback}, + {"_addCallbackBuffer", "([BI)V", (void *)android_hardware_Camera_addCallbackBuffer}, + {"native_autoFocus", "()V", (void *)android_hardware_Camera_autoFocus}, + {"native_cancelAutoFocus", "()V", (void *)android_hardware_Camera_cancelAutoFocus}, + {"native_takePicture", "(I)V", (void *)android_hardware_Camera_takePicture}, + {"native_setParameters", "(Ljava/lang/String;)V", + (void *)android_hardware_Camera_setParameters}, + {"native_getParameters", "()Ljava/lang/String;", + (void *)android_hardware_Camera_getParameters}, + {"reconnect", "()V", (void *)android_hardware_Camera_reconnect}, + {"lock", "()V", (void *)android_hardware_Camera_lock}, + {"unlock", "()V", (void *)android_hardware_Camera_unlock}, + {"startSmoothZoom", "(I)V", (void *)android_hardware_Camera_startSmoothZoom}, + {"stopSmoothZoom", "()V", (void *)android_hardware_Camera_stopSmoothZoom}, + {"setDisplayOrientation", "(I)V", (void *)android_hardware_Camera_setDisplayOrientation}, + {"_enableShutterSound", "(Z)Z", (void *)android_hardware_Camera_enableShutterSound}, + {"_startFaceDetection", "(I)V", (void *)android_hardware_Camera_startFaceDetection}, + {"_stopFaceDetection", "()V", (void *)android_hardware_Camera_stopFaceDetection}, + {"enableFocusMoveCallback", "(I)V", + (void *)android_hardware_Camera_enableFocusMoveCallback}, + {"setAudioRestriction", "(I)V", (void *)android_hardware_Camera_setAudioRestriction}, + {"getAudioRestriction", "()I", (void *)android_hardware_Camera_getAudioRestriction}, }; struct field { diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index a2eae2c9579a..2b7bcbee79fd 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -85,7 +85,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); + CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId, + /*overrideToPortrait*/false); assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1); assertTrue("Orientation was not set for camera " + cameraId, info.info.orientation != -1); @@ -159,7 +160,8 @@ public class CameraBinderTest extends AndroidTestCase { .connect(dummyCallbacks, cameraId, clientPackageName, ICameraService.USE_CALLING_UID, ICameraService.USE_CALLING_PID, - getContext().getApplicationInfo().targetSdkVersion); + getContext().getApplicationInfo().targetSdkVersion, + /*overrideToPortrait*/false); assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); Log.v(TAG, String.format("Camera %s connected", cameraId)); @@ -264,7 +266,8 @@ public class CameraBinderTest extends AndroidTestCase { dummyCallbacks, String.valueOf(cameraId), clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID, 0 /*oomScoreOffset*/, - getContext().getApplicationInfo().targetSdkVersion); + getContext().getApplicationInfo().targetSdkVersion, + /*overrideToPortrait*/false); assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); Log.v(TAG, String.format("Camera %s connected", cameraId)); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java index 0890346db198..9d09dcc5c440 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -244,7 +244,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase { mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId, clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID, - /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion); + /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion, + /*overrideToPortrait*/false); assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser); mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); @@ -417,7 +418,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase { @SmallTest public void testCameraCharacteristics() throws RemoteException { CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId, - getContext().getApplicationInfo().targetSdkVersion); + getContext().getApplicationInfo().targetSdkVersion, /*overrideToPortrait*/false); assertFalse(info.isEmpty()); assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS)); |