From 3068d73c6c7e1f44523b1466b903a9c82408b258 Mon Sep 17 00:00:00 2001 From: Chien-Yu Chen Date: Mon, 9 Feb 2015 13:29:57 -0800 Subject: 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 --- services/camera/libcameraservice/CameraService.cpp | 176 ++++++++++++++++++++- 1 file changed, 175 insertions(+), 1 deletion(-) (limited to 'services/camera/libcameraservice/CameraService.cpp') diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 485b979..488fc42 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 cs = const_cast( + static_cast(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 >::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& 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 oldBinder = mTorchClientMap.valueAt(index); + oldBinder->unlinkToDeath(this); + + mTorchClientMap.replaceValueAt(index, clientBinder); + } + clientBinder->linkToDeath(this); + } else if (index != NAME_NOT_FOUND) { + sp 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& client, const sp& 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( @@ -1727,6 +1857,23 @@ status_t CameraService::dump(int fd, const Vector& args) { return NO_ERROR; } +void CameraService::handleTorchClientBinderDied(const wp &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 &who) { @@ -1737,6 +1884,10 @@ status_t CameraService::dump(int fd, const Vector& args) { ALOGV("java clients' binder died"); + // check torch client + handleTorchClientBinderDied(who); + + // check camera device client sp cameraClient = getClientByRemote(who); if (cameraClient == 0) { @@ -1830,4 +1981,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 -- cgit v1.1