/*
|
* Copyright (C) 2013 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;
|
|
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;
|
|
/**
|
* 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, CameraApi api) {
|
api = validateApiChoice(api);
|
|
if (api == CameraApi.API_1) {
|
if (sAndroidCameraAgent == null) {
|
sAndroidCameraAgent = new AndroidCameraAgentImpl();
|
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;
|
}
|
}
|
|
/**
|
* 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(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;
|
}
|
}
|
}
|
}
|