summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSol Boucher <solb@google.com>2014-08-16 00:23:31 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-08-15 18:45:09 +0000
commitb2df32dd892ae8076714b7ebd33c715378c4c730 (patch)
tree5274854790d76d0bfe57f2265051099da127d950
parentfa88947e17223d1e52eb8bfbac2f1cab7f2e56ba (diff)
parent50f5b019ba3f333a09a1beb9667fd7290082dc31 (diff)
downloadandroid_frameworks_ex-b2df32dd892ae8076714b7ebd33c715378c4c730.tar.gz
android_frameworks_ex-b2df32dd892ae8076714b7ebd33c715378c4c730.tar.bz2
android_frameworks_ex-b2df32dd892ae8076714b7ebd33c715378c4c730.zip
Merge "camera2-portability: Make factory offer choice of backing API" into lmp-dev
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java5
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java1
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java136
-rw-r--r--camera2/portability/src/com/android/ex/camera2/portability/util/SystemProperties.java51
4 files changed, 179 insertions, 14 deletions
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
index 65047f1..fc19aed 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCamera2AgentImpl.java
@@ -215,6 +215,8 @@ class AndroidCamera2AgentImpl extends CameraAgent {
mOpenCallback = openCallback;
mCameraIndex = cameraIndex;
mCameraId = mCameraDevices.get(mCameraIndex);
+ Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API",
+ cameraIndex, mCameraId));
if (mCameraId == null) {
mOpenCallback.onCameraDisabled(msg.arg1);
@@ -858,6 +860,9 @@ class AndroidCamera2AgentImpl extends CameraAgent {
public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)
{}
+ // TODO: Implement
+ public void addCallbackBuffer(final byte[] callbackBuffer) {}
+
@Override
public void autoFocus(final Handler handler, final CameraAFCallback cb) {
mDispatchThread.runJob(new Runnable() {
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
index 95f0320..6885cee 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/AndroidCameraAgentImpl.java
@@ -304,6 +304,7 @@ class AndroidCameraAgentImpl extends CameraAgent {
break;
}
+ Log.i(TAG, "Opening camera " + cameraId + " with camera1 API");
mCamera = android.hardware.Camera.open(cameraId);
if (mCamera != null) {
mCameraId = cameraId;
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java
index 00dc280..77ad0c3 100644
--- a/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java
+++ b/camera2/portability/src/com/android/ex/camera2/portability/CameraAgentFactory.java
@@ -17,42 +17,150 @@
package com.android.ex.camera2.portability;
import android.content.Context;
+import android.os.Build;
+
+import com.android.ex.camera2.portability.debug.Log;
+import com.android.ex.camera2.portability.util.SystemProperties;
/**
* A factory class for {@link CameraAgent}.
+ *
+ * <p>The choice of framework API to use can be made automatically based on the
+ * system API level, explicitly forced by the client app, or overridden entirely
+ * by setting the system property com.camera2.portability.fwk_api to 1 or 2.</p>
*/
public class CameraAgentFactory {
+ private static final Log.Tag TAG = new Log.Tag("CamAgntFact");
+
+ /** Android release replacing the Camera class with the camera2 package. */
+ private static final int FIRST_SDK_WITH_API_2 = 21;
+
+ // The debugging override, which overrides *all* API level selections if set
+ // to API_LEVEL_OVERRIDE_API{1,2}; otherwise, this has no effect. Note that
+ // we check this once when the library is first loaded so that #recycle()
+ // doesn't try to clean up the wrong type of CameraAgent.
+ private static final String API_LEVEL_OVERRIDE_KEY = "camera2.portability.force_api";
+ private static final String API_LEVEL_OVERRIDE_DEFAULT = "0";
+ private static final String API_LEVEL_OVERRIDE_API1 = "1";
+ private static final String API_LEVEL_OVERRIDE_API2 = "2";
+ private static final String API_LEVEL_OVERRIDE_VALUE =
+ SystemProperties.get(API_LEVEL_OVERRIDE_KEY, API_LEVEL_OVERRIDE_DEFAULT);
private static CameraAgent sAndroidCameraAgent;
+ private static CameraAgent sAndroidCamera2Agent;
private static int sAndroidCameraAgentClientCount;
+ private static int sAndroidCamera2AgentClientCount;
/**
- * Returns the android camera implementation of {@link com.android.camera.cameradevice.CameraAgent}.
+ * Used to indicate which camera framework should be used.
+ */
+ public static enum CameraApi {
+ /** Automatically select based on the device's SDK level. */
+ AUTO,
+
+ /** Use the {@link android.hardware.Camera} class. */
+ API_1,
+
+ /** Use the {@link android.hardware.camera2} package. */
+ API_2
+ };
+
+ private static CameraApi highestSupportedApi() {
+ // TODO: Check SDK_INT instead of RELEASE before L launch
+ if (Build.VERSION.SDK_INT >= FIRST_SDK_WITH_API_2 || Build.VERSION.CODENAME.equals("L")) {
+ return CameraApi.API_2;
+ } else {
+ return CameraApi.API_1;
+ }
+ }
+
+ private static CameraApi validateApiChoice(CameraApi choice) {
+ if (API_LEVEL_OVERRIDE_VALUE.equals(API_LEVEL_OVERRIDE_API1)) {
+ Log.d(TAG, "API level overridden by system property: forced to 1");
+ return CameraApi.API_1;
+ } else if (API_LEVEL_OVERRIDE_VALUE.equals(API_LEVEL_OVERRIDE_API2)) {
+ Log.d(TAG, "API level overridden by system property: forced to 2");
+ return CameraApi.API_2;
+ }
+
+ if (choice == null) {
+ Log.w(TAG, "null API level request, so assuming AUTO");
+ choice = CameraApi.AUTO;
+ }
+ if (choice == CameraApi.AUTO) {
+ choice = highestSupportedApi();
+ }
+
+ return choice;
+ }
+
+ /**
+ * Returns the android camera implementation of
+ * {@link com.android.camera.cameradevice.CameraAgent}.
+ *
+ * <p>To clean up the resources allocated by this call, be sure to invoke
+ * {@link #recycle(boolean)} with the same {@code api} value provided
+ * here.</p>
*
+ * @param context The application context.
+ * @param api Which camera framework to use.
* @return The {@link CameraAgent} to control the camera device.
+ *
+ * @throws UnsupportedOperationException If {@code CameraApi.API_2} was
+ * requested on an unsupported device.
*/
- public static synchronized CameraAgent getAndroidCameraAgent(Context context) {
- if (sAndroidCameraAgent == null) {
- if (false) {
- sAndroidCameraAgent = new AndroidCamera2AgentImpl(context);
- } else {
+ public static synchronized CameraAgent getAndroidCameraAgent(Context context, CameraApi api) {
+ api = validateApiChoice(api);
+
+ if (api == CameraApi.API_1) {
+ if (sAndroidCameraAgent == null) {
sAndroidCameraAgent = new AndroidCameraAgentImpl();
+ sAndroidCameraAgentClientCount = 1;
+ } else {
+ ++sAndroidCameraAgentClientCount;
}
- sAndroidCameraAgentClientCount = 1;
- } else {
- ++sAndroidCameraAgentClientCount;
+ return sAndroidCameraAgent;
+ } else { // API_2
+ if (highestSupportedApi() == CameraApi.API_1) {
+ throw new UnsupportedOperationException("Camera API_2 unavailable on this device");
+ }
+
+ if (sAndroidCamera2Agent == null) {
+ sAndroidCamera2Agent = new AndroidCamera2AgentImpl(context);
+ sAndroidCamera2AgentClientCount = 1;
+ } else {
+ ++sAndroidCamera2AgentClientCount;
+ }
+ return sAndroidCamera2Agent;
}
- return sAndroidCameraAgent;
}
/**
* Recycles the resources. Always call this method when the activity is
* stopped.
+ *
+ * @param api Which camera framework handle to recycle.
+ *
+ * @throws UnsupportedOperationException If {@code CameraApi.API_2} was
+ * requested on an unsupported device.
*/
- public static synchronized void recycle() {
- if (--sAndroidCameraAgentClientCount == 0 && sAndroidCameraAgent != null) {
- sAndroidCameraAgent.recycle();
- sAndroidCameraAgent = null;
+ public static synchronized void recycle(CameraApi api) {
+ api = validateApiChoice(api);
+
+ if (api == CameraApi.API_1) {
+ if (--sAndroidCameraAgentClientCount == 0 && sAndroidCameraAgent != null) {
+ sAndroidCameraAgent.recycle();
+ sAndroidCameraAgent = null;
+ }
+ } else { // API_2
+ if (highestSupportedApi() == CameraApi.API_1) {
+ throw new UnsupportedOperationException("Camera API_2 unavailable on this device");
+ }
+
+ if (--sAndroidCamera2AgentClientCount == 0 && sAndroidCamera2Agent != null) {
+ sAndroidCamera2Agent.recycle();
+ sAndroidCamera2Agent = null;
+ }
}
}
}
diff --git a/camera2/portability/src/com/android/ex/camera2/portability/util/SystemProperties.java b/camera2/portability/src/com/android/ex/camera2/portability/util/SystemProperties.java
new file mode 100644
index 0000000..81493f3
--- /dev/null
+++ b/camera2/portability/src/com/android/ex/camera2/portability/util/SystemProperties.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ex.camera2.portability.util;
+
+import com.android.ex.camera2.portability.debug.Log;
+
+import java.lang.reflect.Method;
+
+/**
+ * Mirrors hidden class {@link android.os.SystemProperties} (available since API Level 1).
+ */
+public final class SystemProperties {
+ private static final Log.Tag TAG = new Log.Tag("SysProps");
+
+ /**
+ * Gets system properties set by <code>adb shell setprop <em>key</em> <em>value</em></code>
+ *
+ * @param key the property key.
+ * @param defaultValue the value to return if the property is undefined or empty (this parameter
+ * may be {@code null}).
+ * @return the system property value or the default value.
+ */
+ public static String get(String key, String defaultValue) {
+ try {
+ final Class<?> systemProperties = Class.forName("android.os.SystemProperties");
+ final Method get = systemProperties.getMethod("get", String.class, String.class);
+ return (String) get.invoke(null, key, defaultValue);
+ } catch (Exception e) {
+ // This should never happen
+ Log.e(TAG, "Exception while getting system property: ", e);
+ return defaultValue;
+ }
+ }
+
+ private SystemProperties() {
+ }
+}