1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "CameraFlashlight"
18 #define ATRACE_TAG ATRACE_TAG_CAMERA
19 // #define LOG_NDEBUG 0
20
21 #include <utils/Log.h>
22 #include <utils/Trace.h>
23 #include <cutils/properties.h>
24
25 #include "camera/CameraMetadata.h"
26 #include "CameraFlashlight.h"
27 #include "gui/IGraphicBufferConsumer.h"
28 #include "gui/BufferQueue.h"
29 #include "camera/camera2/CaptureRequest.h"
30 #include "device3/Camera3Device.h"
31
32
33 namespace android {
34
35 using hardware::camera::common::V1_0::TorchModeStatus;
36
37 /////////////////////////////////////////////////////////////////////
38 // CameraFlashlight implementation begins
39 // used by camera service to control flashflight.
40 /////////////////////////////////////////////////////////////////////
41
CameraFlashlight(sp<CameraProviderManager> providerManager,CameraProviderManager::StatusListener * callbacks)42 CameraFlashlight::CameraFlashlight(sp<CameraProviderManager> providerManager,
43 CameraProviderManager::StatusListener* callbacks) :
44 mProviderManager(providerManager),
45 mCallbacks(callbacks),
46 mFlashlightMapInitialized(false) {
47 }
48
~CameraFlashlight()49 CameraFlashlight::~CameraFlashlight() {
50 }
51
createFlashlightControl(const String8 & cameraId)52 status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) {
53 ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
54 cameraId.string());
55 if (mFlashControl != NULL) {
56 return INVALID_OPERATION;
57 }
58
59 if (mProviderManager->supportSetTorchMode(cameraId.string())) {
60 mFlashControl = new ProviderFlashControl(mProviderManager);
61 } else {
62 ALOGE("Flashlight control not supported by this device!");
63 return NO_INIT;
64 }
65
66 return OK;
67 }
68
setTorchMode(const String8 & cameraId,bool enabled)69 status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
70 if (!mFlashlightMapInitialized) {
71 ALOGE("%s: findFlashUnits() must be called before this method.",
72 __FUNCTION__);
73 return NO_INIT;
74 }
75
76 ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
77 cameraId.string(), enabled);
78
79 status_t res = OK;
80 Mutex::Autolock l(mLock);
81
82 if (mOpenedCameraIds.indexOf(cameraId) != NAME_NOT_FOUND) {
83 // This case is needed to avoid state corruption during the following call sequence:
84 // CameraService::setTorchMode for camera ID 0 begins, does torch status checks
85 // CameraService::connect for camera ID 0 begins, calls prepareDeviceOpen, ends
86 // CameraService::setTorchMode for camera ID 0 continues, calls
87 // CameraFlashlight::setTorchMode
88
89 // TODO: Move torch status checks and state updates behind this CameraFlashlight lock
90 // to avoid other similar race conditions.
91 ALOGE("%s: Camera device %s is in use, cannot set torch mode.",
92 __FUNCTION__, cameraId.string());
93 return -EBUSY;
94 }
95
96 if (mFlashControl == NULL) {
97 res = createFlashlightControl(cameraId);
98 if (res) {
99 return res;
100 }
101 res = mFlashControl->setTorchMode(cameraId, enabled);
102 return res;
103 }
104
105 // if flash control already exists, turning on torch mode may fail if it's
106 // tied to another camera device for module v2.3 and below.
107 res = mFlashControl->setTorchMode(cameraId, enabled);
108 if (res == BAD_INDEX) {
109 // flash control is tied to another camera device, need to close it and
110 // try again.
111 mFlashControl.clear();
112 res = createFlashlightControl(cameraId);
113 if (res) {
114 return res;
115 }
116 res = mFlashControl->setTorchMode(cameraId, enabled);
117 }
118
119 return res;
120 }
121
findFlashUnits()122 status_t CameraFlashlight::findFlashUnits() {
123 Mutex::Autolock l(mLock);
124 status_t res;
125
126 std::vector<String8> cameraIds;
127 std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
128 int numberOfCameras = static_cast<int>(ids.size());
129 cameraIds.resize(numberOfCameras);
130 // No module, must be provider
131 for (size_t i = 0; i < cameraIds.size(); i++) {
132 cameraIds[i] = String8(ids[i].c_str());
133 }
134
135 mFlashControl.clear();
136
137 for (auto &id : cameraIds) {
138 ssize_t index = mHasFlashlightMap.indexOfKey(id);
139 if (0 <= index) {
140 continue;
141 }
142
143 bool hasFlash = false;
144 res = createFlashlightControl(id);
145 if (res) {
146 ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
147 id.string());
148 } else {
149 res = mFlashControl->hasFlashUnit(id, &hasFlash);
150 if (res == -EUSERS || res == -EBUSY) {
151 ALOGE("%s: failed to check if camera %s has a flash unit. Some "
152 "camera devices may be opened", __FUNCTION__,
153 id.string());
154 return res;
155 } else if (res) {
156 ALOGE("%s: failed to check if camera %s has a flash unit. %s"
157 " (%d)", __FUNCTION__, id.string(), strerror(-res),
158 res);
159 }
160
161 mFlashControl.clear();
162 }
163 mHasFlashlightMap.add(id, hasFlash);
164 }
165
166 mFlashlightMapInitialized = true;
167 return OK;
168 }
169
hasFlashUnit(const String8 & cameraId)170 bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
171 Mutex::Autolock l(mLock);
172 return hasFlashUnitLocked(cameraId);
173 }
174
hasFlashUnitLocked(const String8 & cameraId)175 bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
176 if (!mFlashlightMapInitialized) {
177 ALOGE("%s: findFlashUnits() must be called before this method.",
178 __FUNCTION__);
179 return false;
180 }
181
182 ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
183 if (index == NAME_NOT_FOUND) {
184 // Might be external camera
185 ALOGW("%s: camera %s not present when findFlashUnits() was called",
186 __FUNCTION__, cameraId.string());
187 return false;
188 }
189
190 return mHasFlashlightMap.valueAt(index);
191 }
192
isBackwardCompatibleMode(const String8 & cameraId)193 bool CameraFlashlight::isBackwardCompatibleMode(const String8& cameraId) {
194 bool backwardCompatibleMode = false;
195 if (mProviderManager != nullptr &&
196 !mProviderManager->supportSetTorchMode(cameraId.string())) {
197 backwardCompatibleMode = true;
198 }
199 return backwardCompatibleMode;
200 }
201
prepareDeviceOpen(const String8 & cameraId)202 status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
203 ALOGV("%s: prepare for device open", __FUNCTION__);
204
205 Mutex::Autolock l(mLock);
206 if (!mFlashlightMapInitialized) {
207 ALOGE("%s: findFlashUnits() must be called before this method.",
208 __FUNCTION__);
209 return NO_INIT;
210 }
211
212 if (isBackwardCompatibleMode(cameraId)) {
213 // framework is going to open a camera device, all flash light control
214 // should be closed for backward compatible support.
215 mFlashControl.clear();
216
217 if (mOpenedCameraIds.size() == 0) {
218 // notify torch unavailable for all cameras with a flash
219 std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
220 int numCameras = static_cast<int>(ids.size());
221 for (int i = 0; i < numCameras; i++) {
222 String8 id8(ids[i].c_str());
223 if (hasFlashUnitLocked(id8)) {
224 mCallbacks->onTorchStatusChanged(
225 id8, TorchModeStatus::NOT_AVAILABLE);
226 }
227 }
228 }
229
230 // close flash control that may be opened by calling hasFlashUnitLocked.
231 mFlashControl.clear();
232 }
233
234 if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
235 mOpenedCameraIds.add(cameraId);
236 }
237
238 return OK;
239 }
240
deviceClosed(const String8 & cameraId)241 status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
242 ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
243
244 Mutex::Autolock l(mLock);
245 if (!mFlashlightMapInitialized) {
246 ALOGE("%s: findFlashUnits() must be called before this method.",
247 __FUNCTION__);
248 return NO_INIT;
249 }
250
251 ssize_t index = mOpenedCameraIds.indexOf(cameraId);
252 if (index == NAME_NOT_FOUND) {
253 ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
254 cameraId.string());
255 } else {
256 mOpenedCameraIds.removeAt(index);
257 }
258
259 // Cannot do anything until all cameras are closed.
260 if (mOpenedCameraIds.size() != 0)
261 return OK;
262
263 if (isBackwardCompatibleMode(cameraId)) {
264 // notify torch available for all cameras with a flash
265 std::vector<std::string> ids = mProviderManager->getCameraDeviceIds();
266 int numCameras = static_cast<int>(ids.size());
267 for (int i = 0; i < numCameras; i++) {
268 String8 id8(ids[i].c_str());
269 if (hasFlashUnitLocked(id8)) {
270 mCallbacks->onTorchStatusChanged(
271 id8, TorchModeStatus::AVAILABLE_OFF);
272 }
273 }
274 }
275
276 return OK;
277 }
278 // CameraFlashlight implementation ends
279
280
~FlashControlBase()281 FlashControlBase::~FlashControlBase() {
282 }
283
284 /////////////////////////////////////////////////////////////////////
285 // ModuleFlashControl implementation begins
286 // Flash control for camera module v2.4 and above.
287 /////////////////////////////////////////////////////////////////////
ProviderFlashControl(sp<CameraProviderManager> providerManager)288 ProviderFlashControl::ProviderFlashControl(sp<CameraProviderManager> providerManager) :
289 mProviderManager(providerManager) {
290 }
291
~ProviderFlashControl()292 ProviderFlashControl::~ProviderFlashControl() {
293 }
294
hasFlashUnit(const String8 & cameraId,bool * hasFlash)295 status_t ProviderFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
296 if (!hasFlash) {
297 return BAD_VALUE;
298 }
299 *hasFlash = mProviderManager->hasFlashUnit(cameraId.string());
300 return OK;
301 }
302
setTorchMode(const String8 & cameraId,bool enabled)303 status_t ProviderFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
304 ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
305 cameraId.string(), enabled);
306
307 return mProviderManager->setTorchMode(cameraId.string(), enabled);
308 }
309 // ProviderFlashControl implementation ends
310
311 }
312