summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChien-Yu Chen <cychen@google.com>2015-02-09 13:29:57 -0800
committerZhijun He <zhijunhe@google.com>2015-03-17 19:23:48 -0700
commit736a7f7b39637e67becef203bb552010ba071467 (patch)
treec1ae9b6f502ec163c24beebdac913ab0ce72e154
parent2f9c62f3e838f358bd5921270d7b1dec39e0a974 (diff)
downloadframeworks_av-736a7f7b39637e67becef203bb552010ba071467.zip
frameworks_av-736a7f7b39637e67becef203bb552010ba071467.tar.gz
frameworks_av-736a7f7b39637e67becef203bb552010ba071467.tar.bz2
camera: implement flashlight control
Implement flashlight API for module v2.4 by calling module APIs and by for hal v2 and v3 by using CameraDeviceBase. Bug: 2682206 Change-Id: Ib8b77f6fd462489d672f27e14fe37801d35b7544
-rw-r--r--camera/ICameraService.cpp24
-rw-r--r--camera/ICameraServiceListener.cpp27
-rw-r--r--camera/tests/ProCameraTests.cpp6
-rw-r--r--include/camera/ICameraService.h7
-rw-r--r--include/camera/ICameraServiceListener.h24
-rw-r--r--services/camera/libcameraservice/Android.mk1
-rw-r--r--services/camera/libcameraservice/CameraFlashlight.cpp520
-rw-r--r--services/camera/libcameraservice/CameraFlashlight.h149
-rw-r--r--services/camera/libcameraservice/CameraService.cpp176
-rw-r--r--services/camera/libcameraservice/CameraService.h34
10 files changed, 965 insertions, 3 deletions
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp
index 5485205..e3f9931 100644
--- a/camera/ICameraService.cpp
+++ b/camera/ICameraService.cpp
@@ -209,6 +209,20 @@ public:
return status;
}
+ virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
+ data.writeString16(cameraId);
+ data.writeInt32(enabled ? 1 : 0);
+ data.writeStrongBinder(clientBinder);
+ remote()->transact(BnCameraService::SET_TORCH_MODE, data, &reply);
+
+ if (readExceptionCode(reply)) return -EPROTO;
+ return reply.readInt32();
+ }
+
// connect to camera service (pro client)
virtual status_t connectPro(const sp<IProCameraCallbacks>& cameraCb, int cameraId,
const String16 &clientPackageName, int clientUid,
@@ -490,6 +504,16 @@ status_t BnCameraService::onTransact(
}
return NO_ERROR;
} break;
+ case SET_TORCH_MODE: {
+ CHECK_INTERFACE(ICameraService, data, reply);
+ String16 cameraId = data.readString16();
+ bool enabled = data.readInt32() != 0 ? true : false;
+ const sp<IBinder> clientBinder = data.readStrongBinder();
+ status_t status = setTorchMode(cameraId, enabled, clientBinder);
+ reply->writeNoException();
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/camera/ICameraServiceListener.cpp b/camera/ICameraServiceListener.cpp
index b2f1729..90a8bc2 100644
--- a/camera/ICameraServiceListener.cpp
+++ b/camera/ICameraServiceListener.cpp
@@ -29,6 +29,7 @@ namespace android {
namespace {
enum {
STATUS_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+ TORCH_STATUS_CHANGED,
};
}; // namespace anonymous
@@ -54,8 +55,21 @@ public:
data,
&reply,
IBinder::FLAG_ONEWAY);
+ }
- reply.readExceptionCode();
+ virtual void onTorchStatusChanged(TorchStatus status, const String16 &cameraId)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(
+ ICameraServiceListener::getInterfaceDescriptor());
+
+ data.writeInt32(static_cast<int32_t>(status));
+ data.writeString16(cameraId);
+
+ remote()->transact(TORCH_STATUS_CHANGED,
+ data,
+ &reply,
+ IBinder::FLAG_ONEWAY);
}
};
@@ -75,7 +89,16 @@ status_t BnCameraServiceListener::onTransact(
int32_t cameraId = data.readInt32();
onStatusChanged(status, cameraId);
- reply->writeNoException();
+
+ return NO_ERROR;
+ } break;
+ case TORCH_STATUS_CHANGED: {
+ CHECK_INTERFACE(ICameraServiceListener, data, reply);
+
+ TorchStatus status = static_cast<TorchStatus>(data.readInt32());
+ String16 cameraId = data.readString16();
+
+ onTorchStatusChanged(status, cameraId);
return NO_ERROR;
} break;
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 1f5867a..6212678 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -89,6 +89,12 @@ struct ServiceListener : public BnCameraServiceListener {
mCondition.broadcast();
}
+ void onTorchStatusChanged(TorchStatus status, const String16& cameraId) {
+ dout << "On torch status changed: 0x" << std::hex
+ << (unsigned int) status << " cameraId " << cameraId.string()
+ << std::endl;
+ }
+
status_t waitForStatusChange(Status& newStatus) {
Mutex::Autolock al(mMutex);
diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h
index f7f06bb..cc41efe 100644
--- a/include/camera/ICameraService.h
+++ b/include/camera/ICameraService.h
@@ -53,6 +53,7 @@ public:
GET_LEGACY_PARAMETERS,
SUPPORTS_CAMERA_API,
CONNECT_LEGACY,
+ SET_TORCH_MODE,
};
enum {
@@ -142,6 +143,12 @@ public:
int clientUid,
/*out*/
sp<ICamera>& device) = 0;
+
+ /**
+ * Turn on or off a camera's torch mode.
+ */
+ virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/camera/ICameraServiceListener.h b/include/camera/ICameraServiceListener.h
index 0a0e43a..9e8b912 100644
--- a/include/camera/ICameraServiceListener.h
+++ b/include/camera/ICameraServiceListener.h
@@ -66,9 +66,33 @@ public:
STATUS_UNKNOWN = 0xFFFFFFFF,
};
+ /**
+ * The torch mode status of a camera.
+ *
+ * Initial status will be transmitted with onTorchStatusChanged immediately
+ * after this listener is added to the service listener list.
+ */
+ enum TorchStatus {
+ // The camera's torch mode has become available to use via
+ // setTorchMode().
+ TORCH_STATUS_AVAILABLE = TORCH_MODE_STATUS_AVAILABLE,
+ // The camera's torch mode has become not available to use via
+ // setTorchMode().
+ TORCH_STATUS_NOT_AVAILABLE = TORCH_MODE_STATUS_RESOURCE_BUSY,
+ // The camera's torch mode has been turned off by setTorchMode().
+ TORCH_STATUS_OFF = TORCH_MODE_STATUS_OFF,
+ // The camera's torch mode has been turned on by setTorchMode().
+ TORCH_STATUS_ON = 0x80000000,
+
+ // Use to initialize variables only
+ TORCH_STATUS_UNKNOWN = 0xFFFFFFFF,
+ };
+
DECLARE_META_INTERFACE(CameraServiceListener);
virtual void onStatusChanged(Status status, int32_t cameraId) = 0;
+
+ virtual void onTorchStatusChanged(TorchStatus status, const String16& cameraId) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index de9551d..5d6423a 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -23,6 +23,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
CameraService.cpp \
CameraDeviceFactory.cpp \
+ CameraFlashlight.cpp \
common/Camera2ClientBase.cpp \
common/CameraDeviceBase.cpp \
common/CameraModule.cpp \
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
new file mode 100644
index 0000000..00a70eb
--- /dev/null
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#define LOG_TAG "CameraFlashlight"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <cutils/properties.h>
+
+#include "camera/CameraMetadata.h"
+#include "CameraFlashlight.h"
+#include "gui/IGraphicBufferConsumer.h"
+#include "gui/BufferQueue.h"
+#include "camera/camera2/CaptureRequest.h"
+#include "CameraDeviceFactory.h"
+
+
+namespace android {
+
+CameraFlashlight::CameraFlashlight(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule),
+ mCallbacks(&callbacks) {
+}
+
+CameraFlashlight::~CameraFlashlight() {
+}
+
+status_t CameraFlashlight::createFlashlightControl(const String16& cameraId) {
+ ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
+ cameraId.string());
+ if (mFlashControl != NULL) {
+ return INVALID_OPERATION;
+ }
+
+ status_t res = OK;
+
+ if (mCameraModule->getRawModule()->module_api_version >=
+ CAMERA_MODULE_API_VERSION_2_4) {
+ mFlashControl = new FlashControl(*mCameraModule, *mCallbacks);
+ if (mFlashControl == NULL) {
+ ALOGV("%s: cannot create flash control for module api v2.4+",
+ __FUNCTION__);
+ return NO_MEMORY;
+ }
+ } else {
+ uint32_t deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
+
+ if (mCameraModule->getRawModule()->module_api_version >=
+ CAMERA_MODULE_API_VERSION_2_0) {
+ camera_info info;
+ res = mCameraModule->getCameraInfo(
+ atoi(String8(cameraId).string()), &info);
+ if (res) {
+ ALOGV("%s: failed to get camera info for camera %s",
+ __FUNCTION__, cameraId.string());
+ return res;
+ }
+ deviceVersion = info.device_version;
+ }
+
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+ CameraDeviceClientFlashControl *flashControl =
+ new CameraDeviceClientFlashControl(*mCameraModule,
+ *mCallbacks);
+ if (!flashControl) {
+ return NO_MEMORY;
+ }
+
+ mFlashControl = flashControl;
+ }
+ else {
+ // todo: implement for device api 1
+ return INVALID_OPERATION;
+ }
+ }
+
+ return OK;
+}
+
+status_t CameraFlashlight::setTorchMode(const String16& cameraId, bool enabled) {
+ if (!mCameraModule) {
+ return NO_INIT;
+ }
+
+ ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
+ cameraId.string(), enabled);
+
+ status_t res = OK;
+ Mutex::Autolock l(mLock);
+
+ if (mFlashControl == NULL) {
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ return res;
+ }
+ res = mFlashControl->setTorchMode(cameraId, enabled);
+ return res;
+ }
+
+ // if flash control already exists, turning on torch mode may fail if it's
+ // tied to another camera device for module v2.3 and below.
+ res = mFlashControl->setTorchMode(cameraId, enabled);
+ if (res == BAD_INDEX) {
+ // flash control is tied to another camera device, need to close it and
+ // try again.
+ mFlashControl.clear();
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ return res;
+ }
+ res = mFlashControl->setTorchMode(cameraId, enabled);
+ }
+
+ return res;
+}
+
+bool CameraFlashlight::hasFlashUnit(const String16& cameraId) {
+ status_t res;
+
+ Mutex::Autolock l(mLock);
+
+ if (mFlashControl == NULL) {
+ res = createFlashlightControl(cameraId);
+ if (res) {
+ ALOGE("%s: failed to create flash control for %s ",
+ __FUNCTION__, cameraId.string());
+ return false;
+ }
+ }
+
+ bool flashUnit = false;
+
+ // 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;
+ }
+ }
+
+ return flashUnit;
+}
+
+status_t CameraFlashlight::prepareDeviceOpen() {
+ ALOGV("%s: prepare for device open", __FUNCTION__);
+
+ Mutex::Autolock l(mLock);
+
+ if (mCameraModule && 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();
+ }
+ }
+
+ return OK;
+}
+
+
+FlashControlBase::~FlashControlBase() {
+}
+
+
+FlashControl::FlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule) {
+}
+
+FlashControl::~FlashControl() {
+}
+
+status_t FlashControl::hasFlashUnit(const String16& 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()),
+ &info);
+ if (res != 0) {
+ return res;
+ }
+
+ CameraMetadata metadata;
+ metadata = info.static_camera_characteristics;
+ camera_metadata_entry flashAvailable =
+ metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
+ *hasFlash = true;
+ }
+
+ return OK;
+}
+
+status_t FlashControl::setTorchMode(const String16& 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);
+}
+
+CameraDeviceClientFlashControl::CameraDeviceClientFlashControl(
+ CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks) :
+ mCameraModule(&cameraModule),
+ mCallbacks(&callbacks),
+ mTorchEnabled(false),
+ mMetadata(NULL) {
+}
+
+CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
+ if (mDevice != NULL) {
+ mDevice->flush();
+ mDevice->deleteStream(mStreamId);
+ mDevice.clear();
+ }
+ if (mMetadata) {
+ delete mMetadata;
+ }
+
+ mAnw.clear();
+ mSurfaceTexture.clear();
+ mProducer.clear();
+ mConsumer.clear();
+
+ if (mTorchEnabled) {
+ if (mCallbacks) {
+ ALOGV("%s: notify the framework that torch was turned off",
+ __FUNCTION__);
+ mCallbacks->torch_mode_status_change(mCallbacks,
+ String8(mCameraId).string(), TORCH_MODE_STATUS_OFF);
+ }
+ }
+}
+
+status_t CameraDeviceClientFlashControl::initializeSurface(int32_t width,
+ int32_t height) {
+ status_t res;
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+
+ mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
+ true, true);
+ if (mSurfaceTexture == NULL) {
+ return NO_MEMORY;
+ }
+
+ int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ res = mSurfaceTexture->setDefaultBufferSize(width, height);
+ if (res) {
+ return res;
+ }
+ res = mSurfaceTexture->setDefaultBufferFormat(format);
+ if (res) {
+ 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);
+ if (mAnw == NULL) {
+ return NO_MEMORY;
+ }
+ res = mDevice->createStream(mAnw, width, height, format, &mStreamId);
+ if (res) {
+ return res;
+ }
+
+ res = mDevice->configureStreams();
+ if (res) {
+ return res;
+ }
+
+ return res;
+}
+
+status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
+ const camera_info& info, int32_t *width, int32_t *height) {
+ if (!width || !height) {
+ return BAD_VALUE;
+ }
+
+ int32_t w = INT32_MAX;
+ int32_t h = 1;
+
+ CameraMetadata metadata;
+ metadata = info.static_camera_characteristics;
+ camera_metadata_entry streamConfigs =
+ metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ for (size_t i = 0; i < streamConfigs.count; i += 4) {
+ int32_t fmt = streamConfigs.data.i32[i];
+ if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED) {
+ int32_t ww = streamConfigs.data.i32[i + 1];
+ int32_t hh = streamConfigs.data.i32[i + 2];
+
+ if (w* h > ww * hh) {
+ w = ww;
+ h = hh;
+ }
+ }
+ }
+
+ if (w == INT32_MAX) {
+ return NAME_NOT_FOUND;
+ }
+
+ *width = w;
+ *height = h;
+
+ return OK;
+}
+
+status_t CameraDeviceClientFlashControl::connectCameraDevice(
+ const String16& cameraId) {
+ String8 id = String8(cameraId);
+ camera_info info;
+ status_t res = mCameraModule->getCameraInfo(atoi(id.string()), &info);
+ if (res != 0) {
+ ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
+ mCameraId.string());
+ return res;
+ }
+
+ mDevice = CameraDeviceFactory::createDevice(atoi(id.string()));
+ if (mDevice == NULL) {
+ return NO_MEMORY;
+ }
+
+ res = mDevice->initialize(mCameraModule);
+ if (res) {
+ goto fail;
+ }
+
+ int32_t width, height;
+ res = getSmallestSurfaceSize(info, &width, &height);
+ if (res) {
+ return res;
+ }
+ res = initializeSurface(width, height);
+ if (res) {
+ goto fail;
+ }
+
+ mCameraId = cameraId;
+
+ return OK;
+
+fail:
+ mDevice.clear();
+ return res;
+}
+
+
+status_t CameraDeviceClientFlashControl::hasFlashUnit(const String16& cameraId,
+ bool *hasFlash) {
+ ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__,
+ cameraId.string());
+
+ Mutex::Autolock l(mLock);
+ return hasFlashUnitLocked(cameraId, hasFlash);
+
+}
+
+status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
+ const String16& cameraId, bool *hasFlash) {
+ if (!mCameraModule) {
+ ALOGE("%s: camera module is NULL", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ if (!hasFlash) {
+ return BAD_VALUE;
+ }
+
+ camera_info info;
+ status_t res = mCameraModule->getCameraInfo(
+ atoi(String8(cameraId).string()), &info);
+ if (res != 0) {
+ ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
+ cameraId.string());
+ return res;
+ }
+
+ CameraMetadata metadata;
+ metadata = info.static_camera_characteristics;
+ camera_metadata_entry flashAvailable =
+ metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
+ if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
+ *hasFlash = true;
+ }
+
+ return OK;
+}
+
+status_t CameraDeviceClientFlashControl::submitTorchRequest(bool enabled) {
+ status_t res;
+
+ if (mMetadata == NULL) {
+ mMetadata = new CameraMetadata();
+ if (mMetadata == NULL) {
+ return NO_MEMORY;
+ }
+ res = mDevice->createDefaultRequest(
+ CAMERA3_TEMPLATE_PREVIEW, mMetadata);
+ if (res) {
+ return res;
+ }
+ }
+
+ uint8_t torchOn = enabled ? ANDROID_FLASH_MODE_TORCH :
+ ANDROID_FLASH_MODE_OFF;
+
+ mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1);
+ mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 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);
+
+ return res;
+}
+
+
+status_t CameraDeviceClientFlashControl::setTorchMode(
+ const String16& cameraId, bool enabled) {
+ bool hasFlash = false;
+
+ Mutex::Autolock l(mLock);
+ status_t res = hasFlashUnitLocked(cameraId, &hasFlash);
+
+ // pre-check
+ if (enabled) {
+ // invalid camera?
+ if (res) {
+ return -EINVAL;
+ }
+ // no flash unit?
+ if (!hasFlash) {
+ return -ENOSYS;
+ }
+ // already opened for a different device?
+ if (mDevice != NULL && cameraId != mCameraId) {
+ return BAD_INDEX;
+ }
+ } else if (mDevice == NULL || cameraId != mCameraId) {
+ // disabling the torch mode of an un-opened or different device.
+ return OK;
+ }
+
+ if (mDevice == NULL) {
+ res = connectCameraDevice(cameraId);
+ if (res) {
+ return res;
+ }
+ }
+
+ res = submitTorchRequest(enabled);
+ if (res) {
+ return res;
+ }
+
+ mTorchEnabled = enabled;
+ return OK;
+}
+
+}
diff --git a/services/camera/libcameraservice/CameraFlashlight.h b/services/camera/libcameraservice/CameraFlashlight.h
new file mode 100644
index 0000000..a0de0b0
--- /dev/null
+++ b/services/camera/libcameraservice/CameraFlashlight.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERAFLASHLIGHT_H
+#define ANDROID_SERVERS_CAMERA_CAMERAFLASHLIGHT_H
+
+#include "hardware/camera_common.h"
+#include "utils/KeyedVector.h"
+#include "gui/GLConsumer.h"
+#include "gui/Surface.h"
+#include "common/CameraDeviceBase.h"
+
+namespace android {
+
+/**
+ * FlashControlBase is a base class for flash control. It defines the functions
+ * that a flash control for each camera module/device version should implement.
+ */
+class FlashControlBase : public virtual VirtualLightRefBase {
+ public:
+ virtual ~FlashControlBase();
+
+ // Whether a camera device has a flash unit. Calling this function may
+ // 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,
+ bool *hasFlash) = 0;
+
+ // set the torch mode to on or off.
+ virtual status_t setTorchMode(const String16& cameraId,
+ bool enabled) = 0;
+};
+
+/**
+ * CameraFlashlight can be used by camera service to control flashflight.
+ */
+class CameraFlashlight : public virtual VirtualLightRefBase {
+ public:
+ CameraFlashlight(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~CameraFlashlight();
+
+ // set the torch mode to on or off.
+ status_t setTorchMode(const String16& cameraId, bool enabled);
+
+ // 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);
+
+ // 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();
+
+ private:
+ // create flashlight control based on camera module API and camera
+ // device API versions.
+ status_t createFlashlightControl(const String16& cameraId);
+
+ sp<FlashControlBase> mFlashControl;
+ CameraModule *mCameraModule;
+ const camera_module_callbacks_t *mCallbacks;
+
+ Mutex mLock;
+};
+
+/**
+ * Flash control for camera module v2.4 and above.
+ */
+class FlashControl : public FlashControlBase {
+ public:
+ FlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~FlashControl();
+
+ // FlashControlBase
+ status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
+ status_t setTorchMode(const String16& cameraId, bool enabled);
+
+ private:
+ CameraModule *mCameraModule;
+
+ Mutex mLock;
+};
+
+/**
+ * Flash control for camera module <= v2.3 and camera HAL v2-v3
+ */
+class CameraDeviceClientFlashControl : public FlashControlBase {
+ public:
+ CameraDeviceClientFlashControl(CameraModule& cameraModule,
+ const camera_module_callbacks_t& callbacks);
+ virtual ~CameraDeviceClientFlashControl();
+
+ // FlashControlBase
+ status_t setTorchMode(const String16& cameraId, bool enabled);
+ status_t hasFlashUnit(const String16& cameraId, bool *hasFlash);
+
+ private:
+ // connect to a camera device
+ status_t connectCameraDevice(const String16& cameraId);
+
+ // initialize a surface
+ status_t initializeSurface(int32_t width, int32_t height);
+
+ // submit a request with the given torch mode
+ status_t submitTorchRequest(bool enabled);
+
+ // 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);
+
+ CameraModule *mCameraModule;
+ const camera_module_callbacks_t *mCallbacks;
+ String16 mCameraId;
+ bool mTorchEnabled;
+ CameraMetadata *mMetadata;
+
+ sp<CameraDeviceBase> mDevice;
+
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<GLConsumer> mSurfaceTexture;
+ sp<ANativeWindow> mAnw;
+ int32_t mStreamId;
+
+ Mutex mLock;
+};
+
+} // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f3cd9de..f35f7f0 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -86,6 +86,38 @@ static void camera_device_status_change(
camera_id,
new_status);
}
+
+static void torch_mode_status_change(
+ const struct camera_module_callbacks* callbacks,
+ const char* camera_id,
+ int new_status) {
+ if (!callbacks || !camera_id) {
+ ALOGE("%s invalid parameters. callbacks %p, camera_id %p", __FUNCTION__,
+ callbacks, camera_id);
+ }
+ sp<CameraService> cs = const_cast<CameraService*>(
+ static_cast<const CameraService*>(callbacks));
+
+ ICameraServiceListener::TorchStatus status;
+ switch (new_status) {
+ case TORCH_MODE_STATUS_AVAILABLE:
+ status = ICameraServiceListener::TORCH_STATUS_AVAILABLE;
+ break;
+ case TORCH_MODE_STATUS_RESOURCE_BUSY:
+ status = ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+ break;
+ case TORCH_MODE_STATUS_OFF:
+ status = ICameraServiceListener::TORCH_STATUS_OFF;
+ break;
+ default:
+ ALOGE("Unknown torch status %d", new_status);
+ return;
+ }
+
+ cs->onTorchStatusChanged(
+ String16(camera_id),
+ status);
+}
} // extern "C"
// ----------------------------------------------------------------------------
@@ -95,7 +127,7 @@ static void camera_device_status_change(
static CameraService *gCameraService;
CameraService::CameraService()
- :mSoundRef(0), mModule(0)
+ :mSoundRef(0), mModule(0), mFlashlight(0)
{
ALOGI("CameraService started (pid=%d)", getpid());
gCameraService = this;
@@ -105,6 +137,8 @@ CameraService::CameraService()
}
this->camera_device_status_change = android::camera_device_status_change;
+ this->torch_mode_status_change = android::torch_mode_status_change;
+
}
void CameraService::onFirstRef()
@@ -121,6 +155,8 @@ 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);
mNumberOfCameras = mModule->getNumberOfCameras();
@@ -131,6 +167,12 @@ void CameraService::onFirstRef()
}
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
+
+ String16 cameraName = String16(String8::format("%d", i));
+ if (mFlashlight->hasFlashUnit(cameraName)) {
+ mTorchStatusMap.add(cameraName,
+ ICameraServiceListener::TORCH_STATUS_AVAILABLE);
+ }
}
if (common->module_api_version >= CAMERA_MODULE_API_VERSION_2_1) {
@@ -225,6 +267,37 @@ void CameraService::onDeviceStatusChanged(int cameraId,
}
+void CameraService::onTorchStatusChanged(const String16& cameraId,
+ ICameraServiceListener::TorchStatus newStatus) {
+ Mutex::Autolock al(mTorchStatusMutex);
+ onTorchStatusChangedLocked(cameraId, newStatus);
+}
+
+void CameraService::onTorchStatusChangedLocked(const String16& cameraId,
+ ICameraServiceListener::TorchStatus newStatus) {
+ ALOGI("%s: Torch status changed for cameraId=%s, newStatus=%d",
+ __FUNCTION__, cameraId.string(), newStatus);
+
+ if (getTorchStatusLocked(cameraId) == 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);
+ if (res) {
+ ALOGE("%s: Failed to set the torch status", __FUNCTION__,
+ (uint32_t)newStatus);
+ return;
+ }
+
+ Vector<sp<ICameraServiceListener> >::const_iterator it;
+ for (it = mListenerList.begin(); it != mListenerList.end(); ++it) {
+ (*it)->onTorchStatusChanged(newStatus, cameraId);
+ }
+}
+
+
int32_t CameraService::getNumberOfCameras() {
return mNumberOfCameras;
}
@@ -676,6 +749,9 @@ status_t CameraService::connectHelperLocked(
int halVersion,
bool legacyMode) {
+ // give flashlight a chance to close devices if necessary.
+ mFlashlight->prepareDeviceOpen();
+
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
@@ -852,6 +928,47 @@ status_t CameraService::connectLegacy(
return OK;
}
+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;
+ }
+
+ Mutex::Autolock al(mTorchStatusMutex);
+ status_t res = mFlashlight->setTorchMode(cameraId, enabled);
+ if (res) {
+ ALOGE("%s: setting torch mode of camera %s to %d failed", __FUNCTION__,
+ cameraId.string(), enabled);
+ 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);
+
+ mTorchClientMap.replaceValueAt(index, clientBinder);
+ }
+ 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;
+}
+
status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
const sp<IBinder>& remoteCallback) {
status_t status = client->initialize(mModule);
@@ -977,6 +1094,9 @@ status_t CameraService::connectDevice(
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
+ // give flashlight a chance to close devices if necessary.
+ mFlashlight->prepareDeviceOpen();
+
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
ALOGW("Camera using old HAL version: %d", deviceVersion);
@@ -1048,6 +1168,16 @@ status_t CameraService::addListener(
}
}
+ /* Immediately signal current torch status to this listener only */
+ {
+ Mutex::Autolock al(mTorchStatusMutex);
+ for (size_t i = 0; i < mTorchStatusMap.size(); i++ ) {
+ listener->onTorchStatusChanged(mTorchStatusMap.valueAt(i),
+ mTorchStatusMap.keyAt(i));
+ }
+
+ }
+
return OK;
}
status_t CameraService::removeListener(
@@ -1724,6 +1854,23 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
return NO_ERROR;
}
+void CameraService::handleTorchClientBinderDied(const wp<IBinder> &who) {
+ Mutex::Autolock al(mTorchStatusMutex);
+ 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);
+ mTorchClientMap.removeItemsAt(i);
+
+ // notify torch mode was turned off
+ onTorchStatusChangedLocked(cameraId,
+ ICameraServiceListener::TORCH_STATUS_OFF);
+ break;
+ }
+ }
+}
+
/*virtual*/void CameraService::binderDied(
const wp<IBinder> &who) {
@@ -1734,6 +1881,10 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) {
ALOGV("java clients' binder died");
+ // check torch client
+ handleTorchClientBinderDied(who);
+
+ // check camera device client
sp<BasicClient> cameraClient = getClientByRemote(who);
if (cameraClient == 0) {
@@ -1827,4 +1978,27 @@ ICameraServiceListener::Status CameraService::getStatus(int cameraId) const {
return mStatusList[cameraId];
}
+ICameraServiceListener::TorchStatus CameraService::getTorchStatusLocked(
+ const String16& cameraId) const {
+ ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ return ICameraServiceListener::TORCH_STATUS_NOT_AVAILABLE;
+ }
+
+ return mTorchStatusMap.valueAt(index);
+}
+
+status_t CameraService::setTorchStatusLocked(const String16& cameraId,
+ ICameraServiceListener::TorchStatus status) {
+ ssize_t index = mTorchStatusMap.indexOfKey(cameraId);
+ if (index == NAME_NOT_FOUND) {
+ return BAD_VALUE;
+ }
+ ICameraServiceListener::TorchStatus& item =
+ mTorchStatusMap.editValueAt(index);
+ item = status;
+
+ return OK;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 3f989c8..158825e 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -36,6 +36,8 @@
#include <camera/CameraParameters.h>
#include <camera/ICameraServiceListener.h>
+#include "CameraFlashlight.h"
+
#include "common/CameraModule.h"
@@ -70,6 +72,9 @@ public:
// HAL Callbacks
virtual void onDeviceStatusChanged(int cameraId,
int newStatus);
+ virtual void onTorchStatusChanged(const String16& cameraId,
+ ICameraServiceListener::TorchStatus
+ newStatus);
/////////////////////////////////////////////////////////////////////
// ICameraService
@@ -112,6 +117,9 @@ public:
/*out*/
String16* parameters);
+ virtual status_t setTorchMode(const String16& cameraId, bool enabled,
+ const sp<IBinder>& clientBinder);
+
// OK = supports api of that version, -EOPNOTSUPP = does not support
virtual status_t supportsCameraApi(
int cameraId, int apiVersion);
@@ -408,6 +416,32 @@ private:
int32_t cameraId,
const StatusVector *rejectSourceStates = NULL);
+ // flashlight control
+ sp<CameraFlashlight> mFlashlight;
+ // guard mTorchStatusMap and mTorchClientMap
+ Mutex mTorchStatusMutex;
+ // camera id -> torch status
+ KeyedVector<String16, 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;
+
+ // 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,
+ ICameraServiceListener::TorchStatus newStatus);
+
+ // get a camera's torch status. mTorchStatusMutex should be locked.
+ ICameraServiceListener::TorchStatus getTorchStatusLocked(
+ const String16 &cameraId) const;
+
+ // set a camera's torch status. mTorchStatusMutex should be locked.
+ status_t setTorchStatusLocked(const String16 &cameraId,
+ ICameraServiceListener::TorchStatus status);
+
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);