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
33namespace android {
34
35using hardware::camera::common::V1_0::TorchModeStatus;
36
37/////////////////////////////////////////////////////////////////////
38// CameraFlashlight implementation begins
39// used by camera service to control flashflight.
40/////////////////////////////////////////////////////////////////////
41
42CameraFlashlight::CameraFlashlight(sp<CameraProviderManager> providerManager,
43        CameraProviderManager::StatusListener* callbacks) :
44        mProviderManager(providerManager),
45        mCallbacks(callbacks),
46        mFlashlightMapInitialized(false) {
47}
48
49CameraFlashlight::~CameraFlashlight() {
50}
51
52status_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        // Only HAL1 devices do not support setTorchMode
63        mFlashControl =
64                new CameraHardwareInterfaceFlashControl(mProviderManager, mCallbacks);
65    }
66
67    return OK;
68}
69
70status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
71    if (!mFlashlightMapInitialized) {
72        ALOGE("%s: findFlashUnits() must be called before this method.",
73               __FUNCTION__);
74        return NO_INIT;
75    }
76
77    ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
78            cameraId.string(), enabled);
79
80    status_t res = OK;
81    Mutex::Autolock l(mLock);
82
83    if (mOpenedCameraIds.indexOf(cameraId) != NAME_NOT_FOUND) {
84        // This case is needed to avoid state corruption during the following call sequence:
85        // CameraService::setTorchMode for camera ID 0 begins, does torch status checks
86        // CameraService::connect for camera ID 0 begins, calls prepareDeviceOpen, ends
87        // CameraService::setTorchMode for camera ID 0 continues, calls
88        //        CameraFlashlight::setTorchMode
89
90        // TODO: Move torch status checks and state updates behind this CameraFlashlight lock
91        // to avoid other similar race conditions.
92        ALOGE("%s: Camera device %s is in use, cannot set torch mode.",
93                __FUNCTION__, cameraId.string());
94        return -EBUSY;
95    }
96
97    if (mFlashControl == NULL) {
98        res = createFlashlightControl(cameraId);
99        if (res) {
100            return res;
101        }
102        res =  mFlashControl->setTorchMode(cameraId, enabled);
103        return res;
104    }
105
106    // if flash control already exists, turning on torch mode may fail if it's
107    // tied to another camera device for module v2.3 and below.
108    res = mFlashControl->setTorchMode(cameraId, enabled);
109    if (res == BAD_INDEX) {
110        // flash control is tied to another camera device, need to close it and
111        // try again.
112        mFlashControl.clear();
113        res = createFlashlightControl(cameraId);
114        if (res) {
115            return res;
116        }
117        res = mFlashControl->setTorchMode(cameraId, enabled);
118    }
119
120    return res;
121}
122
123status_t CameraFlashlight::findFlashUnits() {
124    Mutex::Autolock l(mLock);
125    status_t res;
126
127    std::vector<String8> cameraIds;
128    std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
129    int numberOfCameras = static_cast<int>(ids.size());
130    cameraIds.resize(numberOfCameras);
131    // No module, must be provider
132    for (size_t i = 0; i < cameraIds.size(); i++) {
133        cameraIds[i] = String8(ids[i].c_str());
134    }
135
136    mFlashControl.clear();
137
138    for (auto &id : cameraIds) {
139        ssize_t index = mHasFlashlightMap.indexOfKey(id);
140        if (0 <= index) {
141            continue;
142        }
143
144        bool hasFlash = false;
145        res = createFlashlightControl(id);
146        if (res) {
147            ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
148                    id.string());
149        } else {
150            res = mFlashControl->hasFlashUnit(id, &hasFlash);
151            if (res == -EUSERS || res == -EBUSY) {
152                ALOGE("%s: failed to check if camera %s has a flash unit. Some "
153                        "camera devices may be opened", __FUNCTION__,
154                        id.string());
155                return res;
156            } else if (res) {
157                ALOGE("%s: failed to check if camera %s has a flash unit. %s"
158                        " (%d)", __FUNCTION__, id.string(), strerror(-res),
159                        res);
160            }
161
162            mFlashControl.clear();
163        }
164        mHasFlashlightMap.add(id, hasFlash);
165    }
166
167    mFlashlightMapInitialized = true;
168    return OK;
169}
170
171bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
172    Mutex::Autolock l(mLock);
173    return hasFlashUnitLocked(cameraId);
174}
175
176bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
177    if (!mFlashlightMapInitialized) {
178        ALOGE("%s: findFlashUnits() must be called before this method.",
179               __FUNCTION__);
180        return false;
181    }
182
183    ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
184    if (index == NAME_NOT_FOUND) {
185        // Might be external camera
186        ALOGW("%s: camera %s not present when findFlashUnits() was called",
187                __FUNCTION__, cameraId.string());
188        return false;
189    }
190
191    return mHasFlashlightMap.valueAt(index);
192}
193
194bool CameraFlashlight::isBackwardCompatibleMode(const String8& cameraId) {
195    bool backwardCompatibleMode = false;
196    if (mProviderManager != nullptr &&
197            !mProviderManager->supportSetTorchMode(cameraId.string())) {
198        backwardCompatibleMode = true;
199    }
200    return backwardCompatibleMode;
201}
202
203status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
204    ALOGV("%s: prepare for device open", __FUNCTION__);
205
206    Mutex::Autolock l(mLock);
207    if (!mFlashlightMapInitialized) {
208        ALOGE("%s: findFlashUnits() must be called before this method.",
209               __FUNCTION__);
210        return NO_INIT;
211    }
212
213    if (isBackwardCompatibleMode(cameraId)) {
214        // framework is going to open a camera device, all flash light control
215        // should be closed for backward compatible support.
216        mFlashControl.clear();
217
218        if (mOpenedCameraIds.size() == 0) {
219            // notify torch unavailable for all cameras with a flash
220            std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
221            int numCameras = static_cast<int>(ids.size());
222            for (int i = 0; i < numCameras; i++) {
223                String8 id8(ids[i].c_str());
224                if (hasFlashUnitLocked(id8)) {
225                    mCallbacks->onTorchStatusChanged(
226                            id8, TorchModeStatus::NOT_AVAILABLE);
227                }
228            }
229        }
230
231        // close flash control that may be opened by calling hasFlashUnitLocked.
232        mFlashControl.clear();
233    }
234
235    if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
236        mOpenedCameraIds.add(cameraId);
237    }
238
239    return OK;
240}
241
242status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
243    ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
244
245    Mutex::Autolock l(mLock);
246    if (!mFlashlightMapInitialized) {
247        ALOGE("%s: findFlashUnits() must be called before this method.",
248               __FUNCTION__);
249        return NO_INIT;
250    }
251
252    ssize_t index = mOpenedCameraIds.indexOf(cameraId);
253    if (index == NAME_NOT_FOUND) {
254        ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
255                cameraId.string());
256    } else {
257        mOpenedCameraIds.removeAt(index);
258    }
259
260    // Cannot do anything until all cameras are closed.
261    if (mOpenedCameraIds.size() != 0)
262        return OK;
263
264    if (isBackwardCompatibleMode(cameraId)) {
265        // notify torch available for all cameras with a flash
266        std::vector<std::string> ids = mProviderManager->getAPI1CompatibleCameraDeviceIds();
267        int numCameras = static_cast<int>(ids.size());
268        for (int i = 0; i < numCameras; i++) {
269            String8 id8(ids[i].c_str());
270            if (hasFlashUnitLocked(id8)) {
271                mCallbacks->onTorchStatusChanged(
272                        id8, TorchModeStatus::AVAILABLE_OFF);
273            }
274        }
275    }
276
277    return OK;
278}
279// CameraFlashlight implementation ends
280
281
282FlashControlBase::~FlashControlBase() {
283}
284
285/////////////////////////////////////////////////////////////////////
286// ModuleFlashControl implementation begins
287// Flash control for camera module v2.4 and above.
288/////////////////////////////////////////////////////////////////////
289ProviderFlashControl::ProviderFlashControl(sp<CameraProviderManager> providerManager) :
290        mProviderManager(providerManager) {
291}
292
293ProviderFlashControl::~ProviderFlashControl() {
294}
295
296status_t ProviderFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
297    if (!hasFlash) {
298        return BAD_VALUE;
299    }
300    *hasFlash = mProviderManager->hasFlashUnit(cameraId.string());
301    return OK;
302}
303
304status_t ProviderFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
305    ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
306            cameraId.string(), enabled);
307
308    return mProviderManager->setTorchMode(cameraId.string(), enabled);
309}
310// ProviderFlashControl implementation ends
311
312/////////////////////////////////////////////////////////////////////
313// CameraHardwareInterfaceFlashControl implementation begins
314// Flash control for camera module <= v2.3 and camera HAL v1
315/////////////////////////////////////////////////////////////////////
316
317CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl(
318        sp<CameraProviderManager> manager,
319        CameraProviderManager::StatusListener* callbacks) :
320        mProviderManager(manager),
321        mCallbacks(callbacks),
322        mTorchEnabled(false) {
323}
324
325CameraHardwareInterfaceFlashControl::~CameraHardwareInterfaceFlashControl() {
326    disconnectCameraDevice();
327
328    mSurface.clear();
329    mSurfaceTexture.clear();
330    mProducer.clear();
331    mConsumer.clear();
332
333    if (mTorchEnabled) {
334        if (mCallbacks) {
335            ALOGV("%s: notify the framework that torch was turned off",
336                    __FUNCTION__);
337            mCallbacks->onTorchStatusChanged(mCameraId, TorchModeStatus::AVAILABLE_OFF);
338        }
339    }
340}
341
342status_t CameraHardwareInterfaceFlashControl::setTorchMode(
343        const String8& cameraId, bool enabled) {
344    Mutex::Autolock l(mLock);
345
346    // pre-check
347    status_t res;
348    if (enabled) {
349        bool hasFlash = false;
350        // Check if it has a flash unit and leave camera device open.
351        res = hasFlashUnitLocked(cameraId, &hasFlash, /*keepDeviceOpen*/true);
352        // invalid camera?
353        if (res) {
354            // hasFlashUnitLocked() returns BAD_INDEX if mDevice is connected to
355            // another camera device.
356            return res == BAD_INDEX ? BAD_INDEX : -EINVAL;
357        }
358        // no flash unit?
359        if (!hasFlash) {
360            // Disconnect camera device if it has no flash.
361            disconnectCameraDevice();
362            return -ENOSYS;
363        }
364    } else if (mDevice == NULL || cameraId != mCameraId) {
365        // disabling the torch mode of an un-opened or different device.
366        return OK;
367    } else {
368        // disabling the torch mode of currently opened device
369        disconnectCameraDevice();
370        mTorchEnabled = false;
371        mCallbacks->onTorchStatusChanged(cameraId, TorchModeStatus::AVAILABLE_OFF);
372        return OK;
373    }
374
375    res = startPreviewAndTorch();
376    if (res) {
377        return res;
378    }
379
380    mTorchEnabled = true;
381    mCallbacks->onTorchStatusChanged(cameraId, TorchModeStatus::AVAILABLE_ON);
382    return OK;
383}
384
385status_t CameraHardwareInterfaceFlashControl::hasFlashUnit(
386        const String8& cameraId, bool *hasFlash) {
387    Mutex::Autolock l(mLock);
388    // Close device after checking if it has a flash unit.
389    return hasFlashUnitLocked(cameraId, hasFlash, /*keepDeviceOpen*/false);
390}
391
392status_t CameraHardwareInterfaceFlashControl::hasFlashUnitLocked(
393        const String8& cameraId, bool *hasFlash, bool keepDeviceOpen) {
394    bool closeCameraDevice = false;
395
396    if (!hasFlash) {
397        return BAD_VALUE;
398    }
399
400    status_t res;
401    if (mDevice == NULL) {
402        // Connect to camera device to query if it has a flash unit.
403        res = connectCameraDevice(cameraId);
404        if (res) {
405            return res;
406        }
407        // Close camera device only when it is just opened and the caller doesn't want to keep
408        // the camera device open.
409        closeCameraDevice = !keepDeviceOpen;
410    }
411
412    if (cameraId != mCameraId) {
413        return BAD_INDEX;
414    }
415
416    const char *flashMode =
417            mParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
418    if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) {
419        *hasFlash = true;
420    } else {
421        *hasFlash = false;
422    }
423
424    if (closeCameraDevice) {
425        res = disconnectCameraDevice();
426        if (res != OK) {
427            ALOGE("%s: Failed to disconnect camera device. %s (%d)", __FUNCTION__,
428                    strerror(-res), res);
429            return res;
430        }
431    }
432
433    return OK;
434}
435
436status_t CameraHardwareInterfaceFlashControl::startPreviewAndTorch() {
437    status_t res = OK;
438    res = mDevice->startPreview();
439    if (res) {
440        ALOGE("%s: start preview failed. %s (%d)", __FUNCTION__,
441                strerror(-res), res);
442        return res;
443    }
444
445    mParameters.set(CameraParameters::KEY_FLASH_MODE,
446            CameraParameters::FLASH_MODE_TORCH);
447
448    return mDevice->setParameters(mParameters);
449}
450
451status_t CameraHardwareInterfaceFlashControl::getSmallestSurfaceSize(
452        int32_t *width, int32_t *height) {
453    if (!width || !height) {
454        return BAD_VALUE;
455    }
456
457    int32_t w = INT32_MAX;
458    int32_t h = 1;
459    Vector<Size> sizes;
460
461    mParameters.getSupportedPreviewSizes(sizes);
462    for (size_t i = 0; i < sizes.size(); i++) {
463        Size s = sizes[i];
464        if (w * h > s.width * s.height) {
465            w = s.width;
466            h = s.height;
467        }
468    }
469
470    if (w == INT32_MAX) {
471        return NAME_NOT_FOUND;
472    }
473
474    *width = w;
475    *height = h;
476
477    return OK;
478}
479
480status_t CameraHardwareInterfaceFlashControl::initializePreviewWindow(
481        const sp<CameraHardwareInterface>& device, int32_t width, int32_t height) {
482    status_t res;
483    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
484
485    mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
486            true, true);
487    if (mSurfaceTexture == NULL) {
488        return NO_MEMORY;
489    }
490
491    int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
492    res = mSurfaceTexture->setDefaultBufferSize(width, height);
493    if (res) {
494        return res;
495    }
496    res = mSurfaceTexture->setDefaultBufferFormat(format);
497    if (res) {
498        return res;
499    }
500
501    mSurface = new Surface(mProducer, /*useAsync*/ true);
502    if (mSurface == NULL) {
503        return NO_MEMORY;
504    }
505
506    res = native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_CAMERA);
507    if (res) {
508        ALOGE("%s: Unable to connect to native window", __FUNCTION__);
509        return res;
510    }
511
512    return device->setPreviewWindow(mSurface);
513}
514
515status_t CameraHardwareInterfaceFlashControl::connectCameraDevice(
516        const String8& cameraId) {
517    sp<CameraHardwareInterface> device =
518            new CameraHardwareInterface(cameraId.string());
519
520    status_t res = device->initialize(mProviderManager);
521    if (res) {
522        ALOGE("%s: initializing camera %s failed", __FUNCTION__,
523                cameraId.string());
524        return res;
525    }
526
527    // need to set __get_memory in set_callbacks().
528    device->setCallbacks(NULL, NULL, NULL, NULL, NULL);
529
530    mParameters = device->getParameters();
531
532    int32_t width, height;
533    res = getSmallestSurfaceSize(&width, &height);
534    if (res) {
535        ALOGE("%s: failed to get smallest surface size for camera %s",
536                __FUNCTION__, cameraId.string());
537        return res;
538    }
539
540    res = initializePreviewWindow(device, width, height);
541    if (res) {
542        ALOGE("%s: failed to initialize preview window for camera %s",
543                __FUNCTION__, cameraId.string());
544        return res;
545    }
546
547    mCameraId = cameraId;
548    mDevice = device;
549    return OK;
550}
551
552status_t CameraHardwareInterfaceFlashControl::disconnectCameraDevice() {
553    if (mDevice == NULL) {
554        return OK;
555    }
556
557    if (mParameters.get(CameraParameters::KEY_FLASH_MODE)) {
558        // There is a flash, turn if off.
559        // (If there isn't one, leave the parameter null)
560        mParameters.set(CameraParameters::KEY_FLASH_MODE,
561                CameraParameters::FLASH_MODE_OFF);
562        mDevice->setParameters(mParameters);
563    }
564    mDevice->stopPreview();
565    status_t res = native_window_api_disconnect(mSurface.get(),
566            NATIVE_WINDOW_API_CAMERA);
567    if (res) {
568        ALOGW("%s: native_window_api_disconnect failed: %s (%d)",
569                __FUNCTION__, strerror(-res), res);
570    }
571    mDevice->setPreviewWindow(NULL);
572    mDevice->release();
573    mDevice = NULL;
574
575    return OK;
576}
577// CameraHardwareInterfaceFlashControl implementation ends
578
579}
580