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 "CameraDeviceFactory.h"
31
32
33namespace android {
34
35/////////////////////////////////////////////////////////////////////
36// CameraFlashlight implementation begins
37// used by camera service to control flashflight.
38/////////////////////////////////////////////////////////////////////
39CameraFlashlight::CameraFlashlight(CameraModule& cameraModule,
40        const camera_module_callbacks_t& callbacks) :
41        mCameraModule(&cameraModule),
42        mCallbacks(&callbacks),
43        mFlashlightMapInitialized(false) {
44}
45
46CameraFlashlight::~CameraFlashlight() {
47}
48
49status_t CameraFlashlight::createFlashlightControl(const String8& cameraId) {
50    ALOGV("%s: creating a flash light control for camera %s", __FUNCTION__,
51            cameraId.string());
52    if (mFlashControl != NULL) {
53        return INVALID_OPERATION;
54    }
55
56    status_t res = OK;
57
58    if (mCameraModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_4) {
59        mFlashControl = new ModuleFlashControl(*mCameraModule, *mCallbacks);
60        if (mFlashControl == NULL) {
61            ALOGV("%s: cannot create flash control for module api v2.4+",
62                     __FUNCTION__);
63            return NO_MEMORY;
64        }
65    } else {
66        uint32_t deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
67
68        if (mCameraModule->getModuleApiVersion() >=
69                    CAMERA_MODULE_API_VERSION_2_0) {
70            camera_info info;
71            res = mCameraModule->getCameraInfo(
72                    atoi(String8(cameraId).string()), &info);
73            if (res) {
74                ALOGE("%s: failed to get camera info for camera %s",
75                        __FUNCTION__, cameraId.string());
76                return res;
77            }
78            deviceVersion = info.device_version;
79        }
80
81        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
82            CameraDeviceClientFlashControl *flashControl =
83                    new CameraDeviceClientFlashControl(*mCameraModule,
84                                                       *mCallbacks);
85            if (!flashControl) {
86                return NO_MEMORY;
87            }
88
89            mFlashControl = flashControl;
90        } else {
91            mFlashControl =
92                    new CameraHardwareInterfaceFlashControl(*mCameraModule,
93                                                            *mCallbacks);
94        }
95    }
96
97    return OK;
98}
99
100status_t CameraFlashlight::setTorchMode(const String8& cameraId, bool enabled) {
101    if (!mFlashlightMapInitialized) {
102        ALOGE("%s: findFlashUnits() must be called before this method.",
103               __FUNCTION__);
104        return NO_INIT;
105    }
106
107    ALOGV("%s: set torch mode of camera %s to %d", __FUNCTION__,
108            cameraId.string(), enabled);
109
110    status_t res = OK;
111    Mutex::Autolock l(mLock);
112
113    if (mOpenedCameraIds.indexOf(cameraId) != NAME_NOT_FOUND) {
114        // This case is needed to avoid state corruption during the following call sequence:
115        // CameraService::setTorchMode for camera ID 0 begins, does torch status checks
116        // CameraService::connect for camera ID 0 begins, calls prepareDeviceOpen, ends
117        // CameraService::setTorchMode for camera ID 0 continues, calls
118        //        CameraFlashlight::setTorchMode
119
120        // TODO: Move torch status checks and state updates behind this CameraFlashlight lock
121        // to avoid other similar race conditions.
122        ALOGE("%s: Camera device %s is in use, cannot set torch mode.",
123                __FUNCTION__, cameraId.string());
124        return -EBUSY;
125    }
126
127    if (mFlashControl == NULL) {
128        if (enabled == false) {
129            return OK;
130        }
131
132        res = createFlashlightControl(cameraId);
133        if (res) {
134            return res;
135        }
136        res =  mFlashControl->setTorchMode(cameraId, enabled);
137        return res;
138    }
139
140    // if flash control already exists, turning on torch mode may fail if it's
141    // tied to another camera device for module v2.3 and below.
142    res = mFlashControl->setTorchMode(cameraId, enabled);
143    if (res == BAD_INDEX) {
144        // flash control is tied to another camera device, need to close it and
145        // try again.
146        mFlashControl.clear();
147        res = createFlashlightControl(cameraId);
148        if (res) {
149            return res;
150        }
151        res = mFlashControl->setTorchMode(cameraId, enabled);
152    }
153
154    return res;
155}
156
157status_t CameraFlashlight::findFlashUnits() {
158    Mutex::Autolock l(mLock);
159    status_t res;
160    int32_t numCameras = mCameraModule->getNumberOfCameras();
161
162    mHasFlashlightMap.clear();
163    mFlashlightMapInitialized = false;
164
165    for (int32_t i = 0; i < numCameras; i++) {
166        bool hasFlash = false;
167        String8 id = String8::format("%d", i);
168
169        res = createFlashlightControl(id);
170        if (res) {
171            ALOGE("%s: failed to create flash control for %s", __FUNCTION__,
172                    id.string());
173        } else {
174            res = mFlashControl->hasFlashUnit(id, &hasFlash);
175            if (res == -EUSERS || res == -EBUSY) {
176                ALOGE("%s: failed to check if camera %s has a flash unit. Some "
177                        "camera devices may be opened", __FUNCTION__,
178                        id.string());
179                return res;
180            } else if (res) {
181                ALOGE("%s: failed to check if camera %s has a flash unit. %s"
182                        " (%d)", __FUNCTION__, id.string(), strerror(-res),
183                        res);
184            }
185
186            mFlashControl.clear();
187        }
188        mHasFlashlightMap.add(id, hasFlash);
189    }
190
191    mFlashlightMapInitialized = true;
192    return OK;
193}
194
195bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
196    status_t res;
197
198    Mutex::Autolock l(mLock);
199    return hasFlashUnitLocked(cameraId);
200}
201
202bool CameraFlashlight::hasFlashUnitLocked(const String8& cameraId) {
203    if (!mFlashlightMapInitialized) {
204        ALOGE("%s: findFlashUnits() must be called before this method.",
205               __FUNCTION__);
206        return false;
207    }
208
209    ssize_t index = mHasFlashlightMap.indexOfKey(cameraId);
210    if (index == NAME_NOT_FOUND) {
211        ALOGE("%s: camera %s not present when findFlashUnits() was called",
212                __FUNCTION__, cameraId.string());
213        return false;
214    }
215
216    return mHasFlashlightMap.valueAt(index);
217}
218
219status_t CameraFlashlight::prepareDeviceOpen(const String8& cameraId) {
220    ALOGV("%s: prepare for device open", __FUNCTION__);
221
222    Mutex::Autolock l(mLock);
223    if (!mFlashlightMapInitialized) {
224        ALOGE("%s: findFlashUnits() must be called before this method.",
225               __FUNCTION__);
226        return NO_INIT;
227    }
228
229    if (mCameraModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_4) {
230        // framework is going to open a camera device, all flash light control
231        // should be closed for backward compatible support.
232        mFlashControl.clear();
233
234        if (mOpenedCameraIds.size() == 0) {
235            // notify torch unavailable for all cameras with a flash
236            int numCameras = mCameraModule->getNumberOfCameras();
237            for (int i = 0; i < numCameras; i++) {
238                if (hasFlashUnitLocked(String8::format("%d", i))) {
239                    mCallbacks->torch_mode_status_change(mCallbacks,
240                            String8::format("%d", i).string(),
241                            TORCH_MODE_STATUS_NOT_AVAILABLE);
242                }
243            }
244        }
245
246        // close flash control that may be opened by calling hasFlashUnitLocked.
247        mFlashControl.clear();
248    }
249
250    if (mOpenedCameraIds.indexOf(cameraId) == NAME_NOT_FOUND) {
251        mOpenedCameraIds.add(cameraId);
252    }
253
254    return OK;
255}
256
257status_t CameraFlashlight::deviceClosed(const String8& cameraId) {
258    ALOGV("%s: device %s is closed", __FUNCTION__, cameraId.string());
259
260    Mutex::Autolock l(mLock);
261    if (!mFlashlightMapInitialized) {
262        ALOGE("%s: findFlashUnits() must be called before this method.",
263               __FUNCTION__);
264        return NO_INIT;
265    }
266
267    ssize_t index = mOpenedCameraIds.indexOf(cameraId);
268    if (index == NAME_NOT_FOUND) {
269        ALOGE("%s: couldn't find camera %s in the opened list", __FUNCTION__,
270                cameraId.string());
271    } else {
272        mOpenedCameraIds.removeAt(index);
273    }
274
275    // Cannot do anything until all cameras are closed.
276    if (mOpenedCameraIds.size() != 0)
277        return OK;
278
279    if (mCameraModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_4) {
280        // notify torch available for all cameras with a flash
281        int numCameras = mCameraModule->getNumberOfCameras();
282        for (int i = 0; i < numCameras; i++) {
283            if (hasFlashUnitLocked(String8::format("%d", i))) {
284                mCallbacks->torch_mode_status_change(mCallbacks,
285                        String8::format("%d", i).string(),
286                        TORCH_MODE_STATUS_AVAILABLE_OFF);
287            }
288        }
289    }
290
291    return OK;
292}
293// CameraFlashlight implementation ends
294
295
296FlashControlBase::~FlashControlBase() {
297}
298
299/////////////////////////////////////////////////////////////////////
300// ModuleFlashControl implementation begins
301// Flash control for camera module v2.4 and above.
302/////////////////////////////////////////////////////////////////////
303ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
304        const camera_module_callbacks_t& callbacks) :
305    mCameraModule(&cameraModule) {
306}
307
308ModuleFlashControl::~ModuleFlashControl() {
309}
310
311status_t ModuleFlashControl::hasFlashUnit(const String8& cameraId, bool *hasFlash) {
312    if (!hasFlash) {
313        return BAD_VALUE;
314    }
315
316    *hasFlash = false;
317    Mutex::Autolock l(mLock);
318
319    camera_info info;
320    status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()),
321            &info);
322    if (res != 0) {
323        return res;
324    }
325
326    CameraMetadata metadata;
327    metadata = info.static_camera_characteristics;
328    camera_metadata_entry flashAvailable =
329            metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
330    if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
331        *hasFlash = true;
332    }
333
334    return OK;
335}
336
337status_t ModuleFlashControl::setTorchMode(const String8& cameraId, bool enabled) {
338    ALOGV("%s: set camera %s torch mode to %d", __FUNCTION__,
339            cameraId.string(), enabled);
340
341    Mutex::Autolock l(mLock);
342    return mCameraModule->setTorchMode(cameraId.string(), enabled);
343}
344// ModuleFlashControl implementation ends
345
346/////////////////////////////////////////////////////////////////////
347// CameraDeviceClientFlashControl implementation begins
348// Flash control for camera module <= v2.3 and camera HAL v2-v3
349/////////////////////////////////////////////////////////////////////
350CameraDeviceClientFlashControl::CameraDeviceClientFlashControl(
351        CameraModule& cameraModule,
352        const camera_module_callbacks_t& callbacks) :
353        mCameraModule(&cameraModule),
354        mCallbacks(&callbacks),
355        mTorchEnabled(false),
356        mMetadata(NULL),
357        mStreaming(false) {
358}
359
360CameraDeviceClientFlashControl::~CameraDeviceClientFlashControl() {
361    disconnectCameraDevice();
362    if (mMetadata) {
363        delete mMetadata;
364    }
365
366    mSurface.clear();
367    mSurfaceTexture.clear();
368    mProducer.clear();
369    mConsumer.clear();
370
371    if (mTorchEnabled) {
372        if (mCallbacks) {
373            ALOGV("%s: notify the framework that torch was turned off",
374                    __FUNCTION__);
375            mCallbacks->torch_mode_status_change(mCallbacks,
376                    mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
377        }
378    }
379}
380
381status_t CameraDeviceClientFlashControl::initializeSurface(
382        sp<CameraDeviceBase> &device, int32_t width, int32_t height) {
383    status_t res;
384    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
385
386    mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
387            true, true);
388    if (mSurfaceTexture == NULL) {
389        return NO_MEMORY;
390    }
391
392    int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
393    res = mSurfaceTexture->setDefaultBufferSize(width, height);
394    if (res) {
395        return res;
396    }
397    res = mSurfaceTexture->setDefaultBufferFormat(format);
398    if (res) {
399        return res;
400    }
401
402    mSurface = new Surface(mProducer, /*useAsync*/ true);
403    if (mSurface == NULL) {
404        return NO_MEMORY;
405    }
406    res = device->createStream(mSurface, width, height, format,
407            HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mStreamId);
408    if (res) {
409        return res;
410    }
411
412    res = device->configureStreams();
413    if (res) {
414        return res;
415    }
416
417    return res;
418}
419
420status_t CameraDeviceClientFlashControl::getSmallestSurfaceSize(
421        const camera_info& info, int32_t *width, int32_t *height) {
422    if (!width || !height) {
423        return BAD_VALUE;
424    }
425
426    int32_t w = INT32_MAX;
427    int32_t h = 1;
428
429    CameraMetadata metadata;
430    metadata = info.static_camera_characteristics;
431    camera_metadata_entry streamConfigs =
432            metadata.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
433    for (size_t i = 0; i < streamConfigs.count; i += 4) {
434        int32_t fmt = streamConfigs.data.i32[i];
435        if (fmt == ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED) {
436            int32_t ww = streamConfigs.data.i32[i + 1];
437            int32_t hh = streamConfigs.data.i32[i + 2];
438
439            if (w * h > ww * hh) {
440                w = ww;
441                h = hh;
442            }
443        }
444    }
445
446    // if stream configuration is not found, try available processed sizes.
447    if (streamConfigs.count == 0) {
448        camera_metadata_entry availableProcessedSizes =
449            metadata.find(ANDROID_SCALER_AVAILABLE_PROCESSED_SIZES);
450        for (size_t i = 0; i < availableProcessedSizes.count; i += 2) {
451            int32_t ww = availableProcessedSizes.data.i32[i];
452            int32_t hh = availableProcessedSizes.data.i32[i + 1];
453            if (w * h > ww * hh) {
454                w = ww;
455                h = hh;
456            }
457        }
458    }
459
460    if (w == INT32_MAX) {
461        return NAME_NOT_FOUND;
462    }
463
464    *width = w;
465    *height = h;
466
467    return OK;
468}
469
470status_t CameraDeviceClientFlashControl::connectCameraDevice(
471        const String8& cameraId) {
472    camera_info info;
473    status_t res = mCameraModule->getCameraInfo(atoi(cameraId.string()), &info);
474    if (res != 0) {
475        ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
476                cameraId.string());
477        return res;
478    }
479
480    sp<CameraDeviceBase> device =
481            CameraDeviceFactory::createDevice(atoi(cameraId.string()));
482    if (device == NULL) {
483        return NO_MEMORY;
484    }
485
486    res = device->initialize(mCameraModule);
487    if (res) {
488        return res;
489    }
490
491    int32_t width, height;
492    res = getSmallestSurfaceSize(info, &width, &height);
493    if (res) {
494        return res;
495    }
496    res = initializeSurface(device, width, height);
497    if (res) {
498        return res;
499    }
500
501    mCameraId = cameraId;
502    mStreaming = (info.device_version <= CAMERA_DEVICE_API_VERSION_3_1);
503    mDevice = device;
504
505    return OK;
506}
507
508status_t CameraDeviceClientFlashControl::disconnectCameraDevice() {
509    if (mDevice != NULL) {
510        mDevice->disconnect();
511        mDevice.clear();
512    }
513
514    return OK;
515}
516
517
518
519status_t CameraDeviceClientFlashControl::hasFlashUnit(const String8& cameraId,
520        bool *hasFlash) {
521    ALOGV("%s: checking if camera %s has a flash unit", __FUNCTION__,
522            cameraId.string());
523
524    Mutex::Autolock l(mLock);
525    return hasFlashUnitLocked(cameraId, hasFlash);
526
527}
528
529status_t CameraDeviceClientFlashControl::hasFlashUnitLocked(
530        const String8& cameraId, bool *hasFlash) {
531    if (!hasFlash) {
532        return BAD_VALUE;
533    }
534
535    camera_info info;
536    status_t res = mCameraModule->getCameraInfo(
537            atoi(cameraId.string()), &info);
538    if (res != 0) {
539        ALOGE("%s: failed to get camera info for camera %s", __FUNCTION__,
540                cameraId.string());
541        return res;
542    }
543
544    CameraMetadata metadata;
545    metadata = info.static_camera_characteristics;
546    camera_metadata_entry flashAvailable =
547            metadata.find(ANDROID_FLASH_INFO_AVAILABLE);
548    if (flashAvailable.count == 1 && flashAvailable.data.u8[0] == 1) {
549        *hasFlash = true;
550    }
551
552    return OK;
553}
554
555status_t CameraDeviceClientFlashControl::submitTorchEnabledRequest() {
556    status_t res;
557
558    if (mMetadata == NULL) {
559        mMetadata = new CameraMetadata();
560        if (mMetadata == NULL) {
561            return NO_MEMORY;
562        }
563        res = mDevice->createDefaultRequest(
564                CAMERA3_TEMPLATE_PREVIEW, mMetadata);
565        if (res) {
566            return res;
567        }
568    }
569
570    uint8_t torchOn = ANDROID_FLASH_MODE_TORCH;
571    mMetadata->update(ANDROID_FLASH_MODE, &torchOn, 1);
572    mMetadata->update(ANDROID_REQUEST_OUTPUT_STREAMS, &mStreamId, 1);
573
574    uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;
575    mMetadata->update(ANDROID_CONTROL_AE_MODE, &aeMode, 1);
576
577    int32_t requestId = 0;
578    mMetadata->update(ANDROID_REQUEST_ID, &requestId, 1);
579
580    if (mStreaming) {
581        res = mDevice->setStreamingRequest(*mMetadata);
582    } else {
583        res = mDevice->capture(*mMetadata);
584    }
585    return res;
586}
587
588
589
590
591status_t CameraDeviceClientFlashControl::setTorchMode(
592        const String8& cameraId, bool enabled) {
593    bool hasFlash = false;
594
595    Mutex::Autolock l(mLock);
596    status_t res = hasFlashUnitLocked(cameraId, &hasFlash);
597
598    // pre-check
599    if (enabled) {
600        // invalid camera?
601        if (res) {
602            return -EINVAL;
603        }
604        // no flash unit?
605        if (!hasFlash) {
606            return -ENOSYS;
607        }
608        // already opened for a different device?
609        if (mDevice != NULL && cameraId != mCameraId) {
610            return BAD_INDEX;
611        }
612    } else if (mDevice == NULL || cameraId != mCameraId) {
613        // disabling the torch mode of an un-opened or different device.
614        return OK;
615    } else {
616        // disabling the torch mode of currently opened device
617        disconnectCameraDevice();
618        mTorchEnabled = false;
619        mCallbacks->torch_mode_status_change(mCallbacks,
620            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
621        return OK;
622    }
623
624    if (mDevice == NULL) {
625        res = connectCameraDevice(cameraId);
626        if (res) {
627            return res;
628        }
629    }
630
631    res = submitTorchEnabledRequest();
632    if (res) {
633        return res;
634    }
635
636    mTorchEnabled = true;
637    mCallbacks->torch_mode_status_change(mCallbacks,
638            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
639    return OK;
640}
641// CameraDeviceClientFlashControl implementation ends
642
643
644/////////////////////////////////////////////////////////////////////
645// CameraHardwareInterfaceFlashControl implementation begins
646// Flash control for camera module <= v2.3 and camera HAL v1
647/////////////////////////////////////////////////////////////////////
648CameraHardwareInterfaceFlashControl::CameraHardwareInterfaceFlashControl(
649        CameraModule& cameraModule,
650        const camera_module_callbacks_t& callbacks) :
651        mCameraModule(&cameraModule),
652        mCallbacks(&callbacks),
653        mTorchEnabled(false) {
654
655}
656
657CameraHardwareInterfaceFlashControl::~CameraHardwareInterfaceFlashControl() {
658    disconnectCameraDevice();
659
660    mSurface.clear();
661    mSurfaceTexture.clear();
662    mProducer.clear();
663    mConsumer.clear();
664
665    if (mTorchEnabled) {
666        if (mCallbacks) {
667            ALOGV("%s: notify the framework that torch was turned off",
668                    __FUNCTION__);
669            mCallbacks->torch_mode_status_change(mCallbacks,
670                    mCameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
671        }
672    }
673}
674
675status_t CameraHardwareInterfaceFlashControl::setTorchMode(
676        const String8& cameraId, bool enabled) {
677    Mutex::Autolock l(mLock);
678
679    // pre-check
680    status_t res;
681    if (enabled) {
682        bool hasFlash = false;
683        res = hasFlashUnitLocked(cameraId, &hasFlash);
684        // invalid camera?
685        if (res) {
686            // hasFlashUnitLocked() returns BAD_INDEX if mDevice is connected to
687            // another camera device.
688            return res == BAD_INDEX ? BAD_INDEX : -EINVAL;
689        }
690        // no flash unit?
691        if (!hasFlash) {
692            return -ENOSYS;
693        }
694    } else if (mDevice == NULL || cameraId != mCameraId) {
695        // disabling the torch mode of an un-opened or different device.
696        return OK;
697    } else {
698        // disabling the torch mode of currently opened device
699        disconnectCameraDevice();
700        mTorchEnabled = false;
701        mCallbacks->torch_mode_status_change(mCallbacks,
702            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_OFF);
703        return OK;
704    }
705
706    res = startPreviewAndTorch();
707    if (res) {
708        return res;
709    }
710
711    mTorchEnabled = true;
712    mCallbacks->torch_mode_status_change(mCallbacks,
713            cameraId.string(), TORCH_MODE_STATUS_AVAILABLE_ON);
714    return OK;
715}
716
717status_t CameraHardwareInterfaceFlashControl::hasFlashUnit(
718        const String8& cameraId, bool *hasFlash) {
719    Mutex::Autolock l(mLock);
720    return hasFlashUnitLocked(cameraId, hasFlash);
721}
722
723status_t CameraHardwareInterfaceFlashControl::hasFlashUnitLocked(
724        const String8& cameraId, bool *hasFlash) {
725    if (!hasFlash) {
726        return BAD_VALUE;
727    }
728
729    status_t res;
730    if (mDevice == NULL) {
731        res = connectCameraDevice(cameraId);
732        if (res) {
733            return res;
734        }
735    }
736
737    if (cameraId != mCameraId) {
738        return BAD_INDEX;
739    }
740
741    const char *flashMode =
742            mParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
743    if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) {
744        *hasFlash = true;
745    } else {
746        *hasFlash = false;
747    }
748
749    return OK;
750}
751
752status_t CameraHardwareInterfaceFlashControl::startPreviewAndTorch() {
753    status_t res = OK;
754    res = mDevice->startPreview();
755    if (res) {
756        ALOGE("%s: start preview failed. %s (%d)", __FUNCTION__,
757                strerror(-res), res);
758        return res;
759    }
760
761    mParameters.set(CameraParameters::KEY_FLASH_MODE,
762            CameraParameters::FLASH_MODE_TORCH);
763
764    return mDevice->setParameters(mParameters);
765}
766
767status_t CameraHardwareInterfaceFlashControl::getSmallestSurfaceSize(
768        int32_t *width, int32_t *height) {
769    if (!width || !height) {
770        return BAD_VALUE;
771    }
772
773    int32_t w = INT32_MAX;
774    int32_t h = 1;
775    Vector<Size> sizes;
776
777    mParameters.getSupportedPreviewSizes(sizes);
778    for (size_t i = 0; i < sizes.size(); i++) {
779        Size s = sizes[i];
780        if (w * h > s.width * s.height) {
781            w = s.width;
782            h = s.height;
783        }
784    }
785
786    if (w == INT32_MAX) {
787        return NAME_NOT_FOUND;
788    }
789
790    *width = w;
791    *height = h;
792
793    return OK;
794}
795
796status_t CameraHardwareInterfaceFlashControl::initializePreviewWindow(
797        sp<CameraHardwareInterface> device, int32_t width, int32_t height) {
798    status_t res;
799    BufferQueue::createBufferQueue(&mProducer, &mConsumer);
800
801    mSurfaceTexture = new GLConsumer(mConsumer, 0, GLConsumer::TEXTURE_EXTERNAL,
802            true, true);
803    if (mSurfaceTexture == NULL) {
804        return NO_MEMORY;
805    }
806
807    int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
808    res = mSurfaceTexture->setDefaultBufferSize(width, height);
809    if (res) {
810        return res;
811    }
812    res = mSurfaceTexture->setDefaultBufferFormat(format);
813    if (res) {
814        return res;
815    }
816
817    mSurface = new Surface(mProducer, /*useAsync*/ true);
818    if (mSurface == NULL) {
819        return NO_MEMORY;
820    }
821
822    res = native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_CAMERA);
823    if (res) {
824        ALOGE("%s: Unable to connect to native window", __FUNCTION__);
825        return res;
826    }
827
828    return device->setPreviewWindow(mSurface);
829}
830
831status_t CameraHardwareInterfaceFlashControl::connectCameraDevice(
832        const String8& cameraId) {
833    sp<CameraHardwareInterface> device =
834            new CameraHardwareInterface(cameraId.string());
835
836    status_t res = device->initialize(mCameraModule);
837    if (res) {
838        ALOGE("%s: initializing camera %s failed", __FUNCTION__,
839                cameraId.string());
840        return res;
841    }
842
843    // need to set __get_memory in set_callbacks().
844    device->setCallbacks(NULL, NULL, NULL, NULL);
845
846    mParameters = device->getParameters();
847
848    int32_t width, height;
849    res = getSmallestSurfaceSize(&width, &height);
850    if (res) {
851        ALOGE("%s: failed to get smallest surface size for camera %s",
852                __FUNCTION__, cameraId.string());
853        return res;
854    }
855
856    res = initializePreviewWindow(device, width, height);
857    if (res) {
858        ALOGE("%s: failed to initialize preview window for camera %s",
859                __FUNCTION__, cameraId.string());
860        return res;
861    }
862
863    mCameraId = cameraId;
864    mDevice = device;
865    return OK;
866}
867
868status_t CameraHardwareInterfaceFlashControl::disconnectCameraDevice() {
869    if (mDevice == NULL) {
870        return OK;
871    }
872
873    mParameters.set(CameraParameters::KEY_FLASH_MODE,
874            CameraParameters::FLASH_MODE_OFF);
875    mDevice->setParameters(mParameters);
876    mDevice->stopPreview();
877    status_t res = native_window_api_disconnect(mSurface.get(),
878            NATIVE_WINDOW_API_CAMERA);
879    if (res) {
880        ALOGW("%s: native_window_api_disconnect failed: %s (%d)",
881                __FUNCTION__, strerror(-res), res);
882    }
883    mDevice->setPreviewWindow(NULL);
884    mDevice->release();
885    mDevice = NULL;
886
887    return OK;
888}
889// CameraHardwareInterfaceFlashControl implementation ends
890
891}
892