summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorChien-Yu Chen <cychen@google.com>2015-03-03 22:20:37 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-03-03 22:20:38 +0000
commit38445e493d4cab2abc29515fd3f2ce2e411a6868 (patch)
tree09303b3079864d8a921d45c14d591addb25ee965 /services
parentd702a568cb62e5aebe048147350bb3c76f9386ba (diff)
parent88da526d97442c80731e01bfc94c6b47c4b0c3c7 (diff)
downloadframeworks_av-38445e493d4cab2abc29515fd3f2ce2e411a6868.zip
frameworks_av-38445e493d4cab2abc29515fd3f2ce2e411a6868.tar.gz
frameworks_av-38445e493d4cab2abc29515fd3f2ce2e411a6868.tar.bz2
Merge "camera: fix flashlight implementation for HAL v2"
Diffstat (limited to 'services')
-rw-r--r--services/camera/libcameraservice/CameraFlashlight.cpp330
-rw-r--r--services/camera/libcameraservice/CameraFlashlight.h72
-rw-r--r--services/camera/libcameraservice/CameraService.cpp201
-rw-r--r--services/camera/libcameraservice/CameraService.h21
4 files changed, 423 insertions, 201 deletions
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 00a70eb..a00a49f 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -16,7 +16,7 @@
#define LOG_TAG "CameraFlashlight"
#define ATRACE_TAG ATRACE_TAG_CAMERA
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -32,16 +32,21 @@
namespace android {
+/////////////////////////////////////////////////////////////////////
+// CameraFlashlight implementation begins
+// used by camera service to control flashflight.
+/////////////////////////////////////////////////////////////////////
CameraFlashlight::CameraFlashlight(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
mCameraModule(&cameraModule),
- mCallbacks(&callbacks) {
+ mCallbacks(&callbacks),
+ mFlashlightMapInitialized(false) {
}
CameraFlashlight::~CameraFlashlight() {
}
-status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
+status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) {
ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
cameraId.string());
if (mFlashControl != NULL) {
@@ -52,7 +57,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
if (mCameraModule->getRawModule()->module_api_version >=
CAMERA_MODULE_API_VERSION_2_4) {
- mFlashControl = new FlashControl(*mCameraModule, *mCallbacks);
+ mFlashControl = new ModuleFlashControl(*mCameraModule, *mCallbacks);
if (mFlashControl == NULL) {
ALOGV("%s: cannot create flash control for module api v2.4+",
__FUNCTION__);
@@ -67,7 +72,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
res = mCameraModule->getCameraInfo(
atoi(String8(cameraId).string()), &info);
if (res) {
- ALOGV("%s: failed to get camera info for camera %s",
+ ALOGE("%s: failed to get camera info for camera %s",
__FUNCTION__, cameraId.string());
return res;
}
@@ -83,8 +88,7 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
}
mFlashControl = flashControl;
- }
- else {
+ } else {
// todo: implement for device api 1
return INVALID_OPERATION;
}
@@ -93,8 +97,9 @@ status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
return OK;
}
-status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) {
- if (!mCameraModule) {
+status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
return NO_INIT;
}
@@ -105,6 +110,10 @@ status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled)
Mutex::Autolock l(mLock);
if (mFlashControl == NULL) {
+ if (enabled == false) {
+ return OK;
+ }
+
res = createFlashlightControl(cameraId);
if (res) {
return res;
@@ -130,88 +139,169 @@ status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled)
return res;
}
-bool CameraFlashlight::hasFlashUnit(const String16& cameraId) {
+status_t CameraFlashlight::findFlashUnits() {
+ Mutex::Autolock l(mLock);
status_t res;
+ int32_t numCameras = mCameraModule->getNumberOfCameras();
- Mutex::Autolock l(mLock);
+ mHasFlashlightMap.clear();
+ mFlashlightMapInitialized = false;
- if (mFlashControl == NULL) {
- res = createFlashlightControl(cameraId);
+ for (int32_t i = 0; i < numCameras; i++) {
+ bool hasFlash = false;
+ String8 id = String8::format("%d", i);
+
+ res = createFlashlightControl(id);
if (res) {
- ALOGE("%s: failed to create flash control for %s ",
- __FUNCTION__, cameraId.string());
- return false;
+ ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
+ id.string());
+ } else {
+ res = mFlashControl->hasFlashUnit(id, &hasFlash);
+ if (res == -EUSERS || res == -EBUSY) {
+ ALOGE("%s: failed to check if camera %s has a flash unit. Some "
+ "camera devices may be opened", __FUNCTION__,
+ id.string());
+ return res;
+ } else if (res) {
+ ALOGE("%s: failed to check if camera %s has a flash unit. %s"
+ " (%d)", __FUNCTION__, id.string(), strerror(-res),
+ res);
+ }
+
+ mFlashControl.clear();
}
+ mHasFlashlightMap.add(id, hasFlash);
}
- bool flashUnit = false;
+ mFlashlightMapInitialized = true;
+ return OK;
+}
- // if flash control already exists, querying if a camera device has a flash
- // unit may fail if it's module v1
- res = mFlashControl->hasFlashUnit(cameraId, &flashUnit);
- if (res == BAD_INDEX) {
- // need to close the flash control before query.
- mFlashControl.clear();
- res = createFlashlightControl(cameraId);
- if (res) {
- ALOGE("%s: failed to create flash control for %s ", __FUNCTION__,
- cameraId.string());
- return false;
- }
- res = mFlashControl->hasFlashUnit(cameraId, &flashUnit);
- if (res) {
- flashUnit = false;
- }
+bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
+ status_t res;
+
+ Mutex::Autolock l(mLock);
+ return hasFlashUnitLocked(cameraId);
+}
+
+bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return false;
}
- return flashUnit;
+ ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: camera %s not present when findFlashUnits() was called",
+ __FUNCTION__, cameraId.string());
+ return false;
+ }
+
+ return mHasFlashlightMap.valueAt(index);
}
-status_t CameraFlashlight::prepareDeviceOpen() {
+status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
ALOGV("%s: prepare for device open", __FUNCTION__);
Mutex::Autolock l(mLock);
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
- if (mCameraModule && mCameraModule->getRawModule()->module_api_version <
+ if (mCameraModule->getRawModule()->module_api_version <
CAMERA_MODULE_API_VERSION_2_4) {
// framework is going to open a camera device, all flash light control
// should be closed for backward compatible support.
- if (mFlashControl != NULL) {
- mFlashControl.clear();
+ mFlashControl.clear();
+
+ if (mOpenedCameraIds.size() == 0) {
+ // notify torch unavailable for all cameras with a flash
+ int numCameras = mCameraModule->getNumberOfCameras();
+ for (int i = 0; i < numCameras; i++) {
+ if (hasFlashUnitLocked(String8::format("%d", i))) {
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8::format("%d", i).string(),
+ TORCH_MODE_STATUS_NOT_AVAILABLE);
+ }
+ }
}
+
+ // close flash control that may be opened by calling hasFlashUnitLocked.
+ mFlashControl.clear();
+ }
+
+ if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
+ mOpenedCameraIds.add(cameraId);
}
return OK;
}
+status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
+ ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
-FlashControlBase::~FlashControlBase() {
+ Mutex::Autolock l(mLock);
+ if (!mFlashlightMapInitialized) {
+ ALOGE("%s: findFlashUnits() must be called before this method.");
+ return NO_INIT;
+ }
+
+ ssize_t index = mOpenedCameraIds.indexOf(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
+ cameraId.string());
+ } else {
+ mOpenedCameraIds.removeAt(index);
+ }
+
+ // Cannot do anything until all cameras are closed.
+ if (mOpenedCameraIds.size() != 0)
+ return OK;
+
+ if (mCameraModule->getRawModule()->module_api_version <
+ CAMERA_MODULE_API_VERSION_2_4) {
+ // notify torch available for all cameras with a flash
+ int numCameras = mCameraModule->getNumberOfCameras();
+ for (int i = 0; i < numCameras; i++) {
+ if (hasFlashUnitLocked(String8::format("%d", i))) {
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8::format("%d", i).string(),
+ TORCH_MODE_STATUS_AVAILABLE_OFF);
+ }
+ }
+ }
+
+ return OK;
}
+// CameraFlashlight implementation ends
-FlashControl::FlashControl(CameraModule& cameraModule,
+FlashControlBase::~FlashControlBase() {
+}
+
+/////////////////////////////////////////////////////////////////////
+// ModuleFlashControl implementation begins
+// Flash control for camera module v2.4 and above.
+/////////////////////////////////////////////////////////////////////
+ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
mCameraModule(&cameraModule) {
}
-FlashControl::~FlashControl() {
+ModuleFlashControl::~ModuleFlashControl() {
}
-status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) {
+status_t ModuleFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
if (!hasFlash) {
return BAD_VALUE;
}
*hasFlash = false;
-
Mutex::Autolock l(mLock);
- if (!mCameraModule) {
- return NO_INIT;
- }
-
camera_info info;
- status_t res = mCameraModule->getCameraInfo(atoi(String8(cameraId).string()),
+ status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()),
&info);
if (res != 0) {
return res;
@@ -228,33 +318,31 @@ status_t FlashControl::hasFlashUnit(const String16& cameraId, bool *hasFlash) {
return OK;
}
-status_t FlashControl::setTorchMode(const String16& cameraId, bool enabled) {
+status_t ModuleFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
cameraId.string(), enabled);
Mutex::Autolock l(mLock);
- if (!mCameraModule) {
- return NO_INIT;
- }
-
- return mCameraModule->setTorchMode(String8(cameraId).string(), enabled);
+ return mCameraModule->setTorchMode(cameraId.string(), enabled);
}
+// ModuleFlashControl implementation ends
+/////////////////////////////////////////////////////////////////////
+// CameraDeviceClientFlashControl implementation begins
+// Flash control for camera module <= v2.3 and camera HAL v2-v3
+/////////////////////////////////////////////////////////////////////
CameraDeviceClientFlashControl::CameraDeviceClientFlashControl(
CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
mCameraModule(&cameraModule),
mCallbacks(&callbacks),
mTorchEnabled(false),
- mMetadata(NULL) {
+ mMetadata(NULL),
+ mStreaming(false) {
}
CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
- if (mDevice != NULL) {
- mDevice->flush();
- mDevice->deleteStream(mStreamId);
- mDevice.clear();
- }
+ disconnectCameraDevice();
if (mMetadata) {
delete mMetadata;
}
@@ -269,13 +357,13 @@ CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
ALOGV("%s: notify the framework that torch was turned off",
__FUNCTION__);
mCallbacks->torch_mode_status_change(mCallbacks,
- String8(mCameraId).string(), TORCH_MODE_STATUS_OFF);
+ mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
}
}
}
-status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width,
- int32_t height) {
+status_t CameraDeviceClientFlashControl::initializeSurface(
+ sp<CameraDeviceBase> &device, int32_t width, int32_t height) {
status_t res;
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
@@ -295,27 +383,16 @@ status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width,
return res;
}
- bool useAsync = false;
- int32_t consumerUsage;
- res = mProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
- if (res) {
- return res;
- }
-
- if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
- useAsync = true;
- }
-
- mAnw = new Surface(mProducer, useAsync);
+ mAnw = new Surface(mProducer, /*useAsync*/ true);
if (mAnw == NULL) {
return NO_MEMORY;
}
- res = mDevice->createStream(mAnw, width, height, format, &mStreamId);
+ res = device->createStream(mAnw, width, height, format, &mStreamId);
if (res) {
return res;
}
- res = mDevice->configureStreams();
+ res = device->configureStreams();
if (res) {
return res;
}
@@ -342,7 +419,21 @@ status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
int32_t ww = streamConfigs.data.i32[i + 1];
int32_t hh = streamConfigs.data.i32[i + 2];
- if (w* h > ww * hh) {
+ if (w * h > ww * hh) {
+ w = ww;
+ h = hh;
+ }
+ }
+ }
+
+ // if stream configuration is not found, try available processed sizes.
+ if (streamConfigs.count == 0) {
+ camera_metadata_entry availableProcessedSizes =
+ metadata.find(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
+ for (size_t i = 0; i < availableProcessedSizes.count; i += 2) {
+ int32_t ww = availableProcessedSizes.data.i32[i];
+ int32_t hh = availableProcessedSizes.data.i32[i + 1];
+ if (w * h > ww * hh) {
w = ww;
h = hh;
}
@@ -360,24 +451,24 @@ status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
}
status_t CameraDeviceClientFlashControl::connectCameraDevice(
- const String16& cameraId) {
- String8 id = String8(cameraId);
+ const String8& cameraId) {
camera_info info;
- status_t res = mCameraModule->getCameraInfo(atoi(id.string()), &info);
+ status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info);
if (res != 0) {
ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
- mCameraId.string());
+ cameraId.string());
return res;
}
- mDevice = CameraDeviceFactory::createDevice(atoi(id.string()));
- if (mDevice == NULL) {
+ sp<CameraDeviceBase> device =
+ CameraDeviceFactory::createDevice(atoi(cameraId.string()));
+ if (device == NULL) {
return NO_MEMORY;
}
- res = mDevice->initialize(mCameraModule);
+ res = device->initialize(mCameraModule);
if (res) {
- goto fail;
+ return res;
}
int32_t width, height;
@@ -385,22 +476,30 @@ status_t CameraDeviceClientFlashControl::connectCameraDevice(
if (res) {
return res;
}
- res = initializeSurface(width, height);
+ res = initializeSurface(device, width, height);
if (res) {
- goto fail;
+ return res;
}
mCameraId = cameraId;
+ mStreaming = (info.device_version <= CAMERA_DEVICE_API_VERSION_3_1);
+ mDevice = device;
return OK;
+}
-fail:
- mDevice.clear();
- return res;
+status_t CameraDeviceClientFlashControl::disconnectCameraDevice() {
+ if (mDevice != NULL) {
+ mDevice->disconnect();
+ mDevice.clear();
+ }
+
+ return OK;
}
-status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId,
+
+status_t CameraDeviceClientFlashControl::hasFlashUnit(const String8& cameraId,
bool *hasFlash) {
ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__,
cameraId.string());
@@ -411,19 +510,14 @@ status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId,
}
status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
- const String16& cameraId, bool *hasFlash) {
- if (!mCameraModule) {
- ALOGE("%s: camera module is NULL", __FUNCTION__);
- return NO_INIT;
- }
-
+ const String8& cameraId, bool *hasFlash) {
if (!hasFlash) {
return BAD_VALUE;
}
camera_info info;
status_t res = mCameraModule->getCameraInfo(
- atoi(String8(cameraId).string()), &info);
+ atoi(cameraId.string()), &info);
if (res != 0) {
ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
cameraId.string());
@@ -441,7 +535,7 @@ status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
return OK;
}
-status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) {
+status_t CameraDeviceClientFlashControl::submitTorchEnabledRequest() {
status_t res;
if (mMetadata == NULL) {
@@ -456,27 +550,29 @@ status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) {
}
}
- uint8_t torchOn = enabled ? ANDROID_FLASH_MODE_TORCH :
- ANDROID_FLASH_MODE_OFF;
-
+ uint8_t torchOn = ANDROID_FLASH_MODE_TORCH;
mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1);
mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1);
+ uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
+ mMetadata->update(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
+
int32_t requestId = 0;
mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1);
- List<const CameraMetadata> metadataRequestList;
- metadataRequestList.push_back(*mMetadata);
-
- int64_t lastFrameNumber = 0;
- res = mDevice->captureList(metadataRequestList, &lastFrameNumber);
-
+ if (mStreaming) {
+ res = mDevice->setStreamingRequest(*mMetadata);
+ } else {
+ res = mDevice->capture(*mMetadata);
+ }
return res;
}
+
+
status_t CameraDeviceClientFlashControl::setTorchMode(
- const String16& cameraId, bool enabled) {
+ const String8& cameraId, bool enabled) {
bool hasFlash = false;
Mutex::Autolock l(mLock);
@@ -499,6 +595,13 @@ status_t CameraDeviceClientFlashControl::setTorchMode(
} else if (mDevice == NULL || cameraId != mCameraId) {
// disabling the torch mode of an un-opened or different device.
return OK;
+ } else {
+ // disabling the torch mode of currently opened device
+ disconnectCameraDevice();
+ mTorchEnabled = false;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
+ return OK;
}
if (mDevice == NULL) {
@@ -508,13 +611,16 @@ status_t CameraDeviceClientFlashControl::setTorchMode(
}
}
- res = submitTorchRequest(enabled);
+ res = submitTorchEnabledRequest();
if (res) {
return res;
}
- mTorchEnabled = enabled;
+ mTorchEnabled = true;
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
return OK;
}
+// CameraDeviceClientFlashControl implementation ends
}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
index a0de0b0..ae502b9 100644
--- a/services/camera/libcameraservice/CameraFlashlight.h
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -19,6 +19,7 @@
#include "hardware/camera_common.h"
#include "utils/KeyedVector.h"
+#include "utils/SortedVector.h"
#include "gui/GLConsumer.h"
#include "gui/Surface.h"
#include "common/CameraDeviceBase.h"
@@ -37,11 +38,11 @@ class FlashControlBase : public virtual VirtualLightRefBase {
// cause the torch mode to be turned off in HAL v1 devices. If
// previously-on torch mode is turned off,
// callbacks.torch_mode_status_change() should be invoked.
- virtual status_t hasFlashUnit(const String16& cameraId,
+ virtual status_t hasFlashUnit(const String8& cameraId,
bool *hasFlash) = 0;
// set the torch mode to on or off.
- virtual status_t setTorchMode(const String16& cameraId,
+ virtual status_t setTorchMode(const String8& cameraId,
bool enabled) = 0;
};
@@ -54,43 +55,61 @@ class CameraFlashlight : public virtual VirtualLightRefBase {
const camera_module_callbacks_t& callbacks);
virtual ~CameraFlashlight();
- // set the torch mode to on or off.
- status_t setTorchMode(const String16& cameraId, bool enabled);
+ // Find all flash units. This must be called before other methods. All
+ // camera devices must be closed when it's called because HAL v1 devices
+ // need to be opened to query available flash modes.
+ status_t findFlashUnits();
- // Whether a camera device has a flash unit. Calling this function may
- // cause the torch mode to be turned off in HAL v1 devices.
- bool hasFlashUnit(const String16& cameraId);
+ // Whether a camera device has a flash unit. Before findFlashUnits() is
+ // called, this function always returns false.
+ bool hasFlashUnit(const String8& cameraId);
+
+ // set the torch mode to on or off.
+ status_t setTorchMode(const String8& cameraId, bool enabled);
// Notify CameraFlashlight that camera service is going to open a camera
// device. CameraFlashlight will free the resources that may cause the
// camera open to fail. Camera service must call this function before
// opening a camera device.
- status_t prepareDeviceOpen();
+ status_t prepareDeviceOpen(const String8& cameraId);
+
+ // Notify CameraFlashlight that camera service has closed a camera
+ // device. CameraFlashlight may invoke callbacks for torch mode
+ // available depending on the implementation.
+ status_t deviceClosed(const String8& cameraId);
private:
// create flashlight control based on camera module API and camera
// device API versions.
- status_t createFlashlightControl(const String16& cameraId);
+ status_t createFlashlightControl(const String8& cameraId);
+
+ // mLock should be locked.
+ bool hasFlashUnitLocked(const String8& cameraId);
sp<FlashControlBase> mFlashControl;
CameraModule *mCameraModule;
const camera_module_callbacks_t *mCallbacks;
+ SortedVector<String8> mOpenedCameraIds;
- Mutex mLock;
+ // camera id -> if it has a flash unit
+ KeyedVector<String8, bool> mHasFlashlightMap;
+ bool mFlashlightMapInitialized;
+
+ Mutex mLock; // protect CameraFlashlight API
};
/**
* Flash control for camera module v2.4 and above.
*/
-class FlashControl : public FlashControlBase {
+class ModuleFlashControl : public FlashControlBase {
public:
- FlashControl(CameraModule& cameraModule,
+ ModuleFlashControl(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks);
- virtual ~FlashControl();
+ virtual ~ModuleFlashControl();
// FlashControlBase
- status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
- status_t setTorchMode(const String16& cameraId, bool enabled);
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
+ status_t setTorchMode(const String8& cameraId, bool enabled);
private:
CameraModule *mCameraModule;
@@ -108,30 +127,37 @@ class CameraDeviceClientFlashControl : public FlashControlBase {
virtual ~CameraDeviceClientFlashControl();
// FlashControlBase
- status_t setTorchMode(const String16& cameraId, bool enabled);
- status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
+ status_t setTorchMode(const String8& cameraId, bool enabled);
+ status_t hasFlashUnit(const String8& cameraId, bool *hasFlash);
private:
// connect to a camera device
- status_t connectCameraDevice(const String16& cameraId);
+ status_t connectCameraDevice(const String8& cameraId);
+ // disconnect and free mDevice
+ status_t disconnectCameraDevice();
// initialize a surface
- status_t initializeSurface(int32_t width, int32_t height);
+ status_t initializeSurface(sp<CameraDeviceBase>& device, int32_t width,
+ int32_t height);
- // submit a request with the given torch mode
- status_t submitTorchRequest(bool enabled);
+ // submit a request to enable the torch mode
+ status_t submitTorchEnabledRequest();
// get the smallest surface size of IMPLEMENTATION_DEFINED
status_t getSmallestSurfaceSize(const camera_info& info, int32_t *width,
int32_t *height);
- status_t hasFlashUnitLocked(const String16& cameraId, bool *hasFlash);
+ status_t hasFlashUnitLocked(const String8& cameraId, bool *hasFlash);
CameraModule *mCameraModule;
const camera_module_callbacks_t *mCallbacks;
- String16 mCameraId;
+ String8 mCameraId;
bool mTorchEnabled;
CameraMetadata *mMetadata;
+ // WORKAROUND: will be set to true for HAL v2 devices where
+ // setStreamingRequest() needs to be call for torch mode settings to
+ // take effect.
+ bool mStreaming;
sp<CameraDeviceBase> mDevice;
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index d65ac21..8fdfaa8 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -101,14 +101,14 @@ static void torch_mode_status_change(
ICameraServiceListener::TorchStatus status;
switch (new_status) {
- case TORCH_MODE_STATUS_AVAILABLE:
- status = ICameraServiceListener::TORCH_STATUS_AVAILABLE;
- break;
- case TORCH_MODE_STATUS_RESOURCE_BUSY:
+ case TORCH_MODE_STATUS_NOT_AVAILABLE:
status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
break;
- case TORCH_MODE_STATUS_OFF:
- status = ICameraServiceListener::TORCH_STATUS_OFF;
+ case TORCH_MODE_STATUS_AVAILABLE_OFF:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF;
+ break;
+ case TORCH_MODE_STATUS_AVAILABLE_ON:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE_ON;
break;
default:
ALOGE("Unknown torch status %d", new_status);
@@ -116,7 +116,7 @@ static void torch_mode_status_change(
}
cs->onTorchStatusChanged(
- String16(camera_id),
+ String8(camera_id),
status);
}
} // extern "C"
@@ -156,23 +156,29 @@ void CameraService::onFirstRef()
}
else {
mModule = new CameraModule(rawModule);
- mFlashlight = new CameraFlashlight(*mModule, *this);
-
const hw_module_t *common = mModule->getRawModule();
- ALOGI("Loaded \"%s\" camera module", common->name);
+ ALOGI("Loaded \"%s\" cameraCa module", common->name);
mNumberOfCameras = mModule->getNumberOfCameras();
if (mNumberOfCameras > MAX_CAMERAS) {
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
+
+ mFlashlight = new CameraFlashlight(*mModule, *this);
+ status_t res = mFlashlight->findFlashUnits();
+ if (res) {
+ // impossible because we haven't open any camera devices.
+ ALOGE("failed to find flash units.");
+ }
+
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
- String16 cameraName = String16(String8::format("%d", i));
+ String8 cameraName = String8::format("%d", i);
if (mFlashlight->hasFlashUnit(cameraName)) {
mTorchStatusMap.add(cameraName,
- ICameraServiceListener::TORCH_STATUS_AVAILABLE);
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
}
}
@@ -207,7 +213,7 @@ CameraService::~CameraService() {
void CameraService::onDeviceStatusChanged(int cameraId,
int newStatus)
{
- ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
+ ALOGV("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
cameraId, newStatus);
if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
@@ -268,24 +274,30 @@ void CameraService::onDeviceStatusChanged(int cameraId,
}
-void CameraService::onTorchStatusChanged(const String16& cameraId,
+void CameraService::onTorchStatusChanged(const String8& cameraId,
ICameraServiceListener::TorchStatus newStatus) {
Mutex::Autolock al(mTorchStatusMutex);
onTorchStatusChangedLocked(cameraId, newStatus);
}
-void CameraService::onTorchStatusChangedLocked(const String16& cameraId,
+void CameraService::onTorchStatusChangedLocked(const String8& cameraId,
ICameraServiceListener::TorchStatus newStatus) {
ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
__FUNCTION__, cameraId.string(), newStatus);
- if (getTorchStatusLocked(cameraId) == newStatus) {
+ ICameraServiceListener::TorchStatus status;
+ status_t res = getTorchStatusLocked(cameraId, &status);
+ if (res) {
+ ALOGE("%s: cannot get torch status of camera %s", cameraId.string());
+ return;
+ }
+ if (status == newStatus) {
ALOGE("%s: Torch state transition to the same status 0x%x not allowed",
__FUNCTION__, (uint32_t)newStatus);
return;
}
- status_t res = setTorchStatusLocked(cameraId, newStatus);
+ res = setTorchStatusLocked(cameraId, newStatus);
if (res) {
ALOGE("%s: Failed to set the torch status", __FUNCTION__,
(uint32_t)newStatus);
@@ -294,7 +306,7 @@ void CameraService::onTorchStatusChangedLocked(const String16& cameraId,
Vector<sp<ICameraServiceListener> >::const_iterator it;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
- (*it)->onTorchStatusChanged(newStatus, cameraId);
+ (*it)->onTorchStatusChanged(newStatus, String16(cameraId.string()));
}
}
@@ -754,7 +766,7 @@ status_t CameraService::connectHelperLocked(
bool legacyMode) {
// give flashlight a chance to close devices if necessary.
- mFlashlight->prepareDeviceOpen();
+ mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId));
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
@@ -932,44 +944,94 @@ status_t CameraService::connectLegacy(
return OK;
}
+bool CameraService::validCameraIdForSetTorchMode(const String8& cameraId) {
+ // invalid string for int
+ if (cameraId.string() == NULL) {
+ return false;
+ }
+ errno = 0;
+ char *endptr;
+ long id = strtol(cameraId.string(), &endptr, 10); // base 10
+ if (errno || id > INT_MAX || id < INT_MIN || *endptr != 0) {
+ return false;
+ }
+
+ // id matches one of the plugged-in devices?
+ ICameraServiceListener::Status deviceStatus = getStatus(id);
+ if (deviceStatus != ICameraServiceListener::STATUS_PRESENT &&
+ deviceStatus != ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ return false;
+ }
+
+ return true;
+}
+
status_t CameraService::setTorchMode(const String16& cameraId, bool enabled,
const sp<IBinder>& clientBinder) {
if (enabled && clientBinder == NULL) {
ALOGE("%s: torch client binder is NULL", __FUNCTION__);
- return -ENOSYS;
+ return -EINVAL;
}
- Mutex::Autolock al(mTorchStatusMutex);
- status_t res = mFlashlight->setTorchMode(cameraId, enabled);
+ String8 id = String8(cameraId.string());
+
+ // verify id is valid.
+ if (validCameraIdForSetTorchMode(id) == false) {
+ ALOGE("%s: camera id is invalid %s", id.string());
+ return -EINVAL;
+ }
+
+ {
+ Mutex::Autolock al(mTorchStatusMutex);
+ ICameraServiceListener::TorchStatus status;
+ status_t res = getTorchStatusLocked(id, &status);
+ if (res) {
+ ALOGE("%s: getting current torch status failed for camera %s",
+ __FUNCTION__, id.string());
+ return -EINVAL;
+ }
+
+ if (status == ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE) {
+ if (getStatus(atoi(id.string())) ==
+ ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ ALOGE("%s: torch mode of camera %s is not available because "
+ "camera is in use", __FUNCTION__, id.string());
+ return -EBUSY;
+ } else {
+ ALOGE("%s: torch mode of camera %s is not available due to "
+ "insufficient resources", __FUNCTION__, id.string());
+ return -EUSERS;
+ }
+ }
+ }
+
+ status_t res = mFlashlight->setTorchMode(id, enabled);
if (res) {
- ALOGE("%s: setting torch mode of camera %s to %d failed", __FUNCTION__,
- cameraId.string(), enabled);
+ ALOGE("%s: setting torch mode of camera %s to %d failed. %s (%d)",
+ __FUNCTION__, id.string(), enabled, strerror(-res), res);
return res;
}
- // update the link to client's death
- ssize_t index = mTorchClientMap.indexOfKey(cameraId);
- if (enabled) {
- if (index == NAME_NOT_FOUND) {
- mTorchClientMap.add(cameraId, clientBinder);
- } else {
- const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
- oldBinder->unlinkToDeath(this);
+ {
+ // update the link to client's death
+ Mutex::Autolock al(mTorchClientMapMutex);
+ ssize_t index = mTorchClientMap.indexOfKey(id);
+ if (enabled) {
+ if (index == NAME_NOT_FOUND) {
+ mTorchClientMap.add(id, clientBinder);
+ } else {
+ const sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+ oldBinder->unlinkToDeath(this);
- mTorchClientMap.replaceValueAt(index, clientBinder);
+ mTorchClientMap.replaceValueAt(index, clientBinder);
+ }
+ clientBinder->linkToDeath(this);
+ } else if (index != NAME_NOT_FOUND) {
+ sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
+ oldBinder->unlinkToDeath(this);
}
- clientBinder->linkToDeath(this);
- } else if (index != NAME_NOT_FOUND) {
- sp<IBinder> oldBinder = mTorchClientMap.valueAt(index);
- oldBinder->unlinkToDeath(this);
}
- // notify the listeners the change.
- ICameraServiceListener::TorchStatus status = enabled ?
- ICameraServiceListener::TORCH_STATUS_ON :
- ICameraServiceListener::TORCH_STATUS_OFF;
- onTorchStatusChangedLocked(cameraId, status);
-
return OK;
}
@@ -1099,7 +1161,7 @@ status_t CameraService::connectDevice(
int deviceVersion = getDeviceVersion(cameraId, &facing);
// give flashlight a chance to close devices if necessary.
- mFlashlight->prepareDeviceOpen();
+ mFlashlight->prepareDeviceOpen(String8::format("%d", cameraId));
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
@@ -1176,8 +1238,8 @@ status_t CameraService::addListener(
{
Mutex::Autolock al(mTorchStatusMutex);
for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) {
- listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i),
- mTorchStatusMap.keyAt(i));
+ String16 id = String16(mTorchStatusMap.keyAt(i).string());
+ listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i), id);
}
}
@@ -1616,6 +1678,9 @@ status_t CameraService::BasicClient::finishCameraOps() {
mCameraId,
&rejectSourceStates);
+ // Notify flashlight that a camera device is closed.
+ mCameraService->mFlashlight->deviceClosed(
+ String8::format("%d", mCameraId));
}
// Always stop watching, even if no camera op is active
if (mOpsCallback != NULL) {
@@ -1862,17 +1927,18 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
}
void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
- Mutex::Autolock al(mTorchStatusMutex);
+ Mutex::Autolock al(mTorchClientMapMutex);
for (size_t i = 0; i < mTorchClientMap.size(); i++) {
if (mTorchClientMap[i] == who) {
// turn off the torch mode that was turned on by dead client
- String16 cameraId = mTorchClientMap.keyAt(i);
- mFlashlight->setTorchMode(cameraId, false);
+ String8 cameraId = mTorchClientMap.keyAt(i);
+ status_t res = mFlashlight->setTorchMode(cameraId, false);
+ if (res) {
+ ALOGE("%s: torch client died but couldn't turn off torch: "
+ "%s (%d)", __FUNCTION__, strerror(-res), res);
+ return;
+ }
mTorchClientMap.removeItemsAt(i);
-
- // notify torch mode was turned off
- onTorchStatusChangedLocked(cameraId,
- ICameraServiceListener::TORCH_STATUS_OFF);
break;
}
}
@@ -1968,6 +2034,19 @@ void CameraService::updateStatus(ICameraServiceListener::Status status,
}
}
+ if (status == ICameraServiceListener::STATUS_NOT_PRESENT ||
+ status == ICameraServiceListener::STATUS_NOT_AVAILABLE) {
+ // update torch status to not available when the camera device
+ // becomes not present or not available.
+ onTorchStatusChanged(String8::format("%d", cameraId),
+ ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE);
+ } else if (status == ICameraServiceListener::STATUS_PRESENT) {
+ // update torch status to available when the camera device becomes
+ // present or available
+ onTorchStatusChanged(String8::format("%d", cameraId),
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE_OFF);
+ }
+
Vector<sp<ICameraServiceListener> >::const_iterator it;
for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
(*it)->onStatusChanged(status, cameraId);
@@ -1985,17 +2064,23 @@ ICameraServiceListener::Status CameraService::getStatus(int cameraId) const {
return mStatusList[cameraId];
}
-ICameraServiceListener::TorchStatus CameraService::getTorchStatusLocked(
- const String16& cameraId) const {
+status_t CameraService::getTorchStatusLocked(
+ const String8& cameraId,
+ ICameraServiceListener::TorchStatus *status) const {
+ if (!status) {
+ return BAD_VALUE;
+ }
ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
if (index == NAME_NOT_FOUND) {
- return ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+ // invalid camera ID or the camera doesn't have a flash unit
+ return NAME_NOT_FOUND;
}
- return mTorchStatusMap.valueAt(index);
+ *status = mTorchStatusMap.valueAt(index);
+ return OK;
}
-status_t CameraService::setTorchStatusLocked(const String16& cameraId,
+status_t CameraService::setTorchStatusLocked(const String8& cameraId,
ICameraServiceListener::TorchStatus status) {
ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
if (index == NAME_NOT_FOUND) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 84bcdb8..74b3623 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -72,7 +72,7 @@ public:
// HAL Callbacks
virtual void onDeviceStatusChanged(int cameraId,
int newStatus);
- virtual void onTorchStatusChanged(const String16& cameraId,
+ virtual void onTorchStatusChanged(const String8& cameraId,
ICameraServiceListener::TorchStatus
newStatus);
@@ -418,28 +418,33 @@ private:
// flashlight control
sp<CameraFlashlight> mFlashlight;
- // guard mTorchStatusMap and mTorchClientMap
+ // guard mTorchStatusMap
Mutex mTorchStatusMutex;
+ // guard mTorchClientMap
+ Mutex mTorchClientMapMutex;
// camera id -> torch status
- KeyedVector<String16, ICameraServiceListener::TorchStatus> mTorchStatusMap;
+ KeyedVector<String8, ICameraServiceListener::TorchStatus> mTorchStatusMap;
// camera id -> torch client binder
// only store the last client that turns on each camera's torch mode
- KeyedVector<String16, sp<IBinder> > mTorchClientMap;
+ KeyedVector<String8, sp<IBinder> > mTorchClientMap;
// check and handle if torch client's process has died
void handleTorchClientBinderDied(const wp<IBinder> &who);
// handle torch mode status change and invoke callbacks. mTorchStatusMutex
// should be locked.
- void onTorchStatusChangedLocked(const String16& cameraId,
+ void onTorchStatusChangedLocked(const String8& cameraId,
ICameraServiceListener::TorchStatus newStatus);
+ // validate the camera id for use of setting a torch mode.
+ bool validCameraIdForSetTorchMode(const String8& cameraId);
+
// get a camera's torch status. mTorchStatusMutex should be locked.
- ICameraServiceListener::TorchStatus getTorchStatusLocked(
- const String16 &cameraId) const;
+ status_t getTorchStatusLocked(const String8 &cameraId,
+ ICameraServiceListener::TorchStatus *status) const;
// set a camera's torch status. mTorchStatusMutex should be locked.
- status_t setTorchStatusLocked(const String16 &cameraId,
+ status_t setTorchStatusLocked(const String8 &cameraId,
ICameraServiceListener::TorchStatus status);
// IBinder::DeathRecipient implementation