CameraDeviceClient.cpp revision f0b7026fca225581c7711e4d802117869b66e9dc
1/*
2 * Copyright (C) 2013 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 "CameraDeviceClient"
18#define ATRACE_TAG ATRACE_TAG_CAMERA
19// #define LOG_NDEBUG 0
20
21#include <cutils/properties.h>
22#include <utils/Log.h>
23#include <utils/Trace.h>
24#include <gui/Surface.h>
25#include <camera/camera2/CaptureRequest.h>
26
27#include "common/CameraDeviceBase.h"
28#include "api2/CameraDeviceClient.h"
29
30
31
32namespace android {
33using namespace camera2;
34
35CameraDeviceClientBase::CameraDeviceClientBase(
36        const sp<CameraService>& cameraService,
37        const sp<ICameraDeviceCallbacks>& remoteCallback,
38        const String16& clientPackageName,
39        int cameraId,
40        int cameraFacing,
41        int clientPid,
42        uid_t clientUid,
43        int servicePid) :
44    BasicClient(cameraService, remoteCallback->asBinder(), clientPackageName,
45                cameraId, cameraFacing, clientPid, clientUid, servicePid),
46    mRemoteCallback(remoteCallback) {
47}
48
49// Interface used by CameraService
50
51CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
52                                   const sp<ICameraDeviceCallbacks>& remoteCallback,
53                                   const String16& clientPackageName,
54                                   int cameraId,
55                                   int cameraFacing,
56                                   int clientPid,
57                                   uid_t clientUid,
58                                   int servicePid) :
59    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
60                cameraId, cameraFacing, clientPid, clientUid, servicePid),
61    mRequestIdCounter(0) {
62
63    ATRACE_CALL();
64    ALOGI("CameraDeviceClient %d: Opened", cameraId);
65}
66
67status_t CameraDeviceClient::initialize(camera_module_t *module)
68{
69    ATRACE_CALL();
70    status_t res;
71
72    res = Camera2ClientBase::initialize(module);
73    if (res != OK) {
74        return res;
75    }
76
77    String8 threadName;
78    mFrameProcessor = new FrameProcessorBase(mDevice);
79    threadName = String8::format("CDU-%d-FrameProc", mCameraId);
80    mFrameProcessor->run(threadName.string());
81
82    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
83                                      FRAME_PROCESSOR_LISTENER_MAX_ID,
84                                      /*listener*/this,
85                                      /*quirkSendPartials*/true);
86
87    return OK;
88}
89
90CameraDeviceClient::~CameraDeviceClient() {
91}
92
93status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
94                                         bool streaming) {
95    ATRACE_CALL();
96    ALOGV("%s", __FUNCTION__);
97
98    status_t res;
99
100    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
101
102    Mutex::Autolock icl(mBinderSerializationLock);
103
104    if (!mDevice.get()) return DEAD_OBJECT;
105
106    if (request == 0) {
107        ALOGE("%s: Camera %d: Sent null request. Rejecting request.",
108              __FUNCTION__, mCameraId);
109        return BAD_VALUE;
110    }
111
112    CameraMetadata metadata(request->mMetadata);
113
114    if (metadata.isEmpty()) {
115        ALOGE("%s: Camera %d: Sent empty metadata packet. Rejecting request.",
116               __FUNCTION__, mCameraId);
117        return BAD_VALUE;
118    } else if (request->mSurfaceList.size() == 0) {
119        ALOGE("%s: Camera %d: Requests must have at least one surface target. "
120              "Rejecting request.", __FUNCTION__, mCameraId);
121        return BAD_VALUE;
122    }
123
124    if (!enforceRequestPermissions(metadata)) {
125        // Callee logs
126        return PERMISSION_DENIED;
127    }
128
129    /**
130     * Write in the output stream IDs which we calculate from
131     * the capture request's list of surface targets
132     */
133    Vector<int32_t> outputStreamIds;
134    outputStreamIds.setCapacity(request->mSurfaceList.size());
135    for (size_t i = 0; i < request->mSurfaceList.size(); ++i) {
136        sp<Surface> surface = request->mSurfaceList[i];
137
138        if (surface == 0) continue;
139
140        sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
141        int idx = mStreamMap.indexOfKey(gbp->asBinder());
142
143        // Trying to submit request with surface that wasn't created
144        if (idx == NAME_NOT_FOUND) {
145            ALOGE("%s: Camera %d: Tried to submit a request with a surface that"
146                  " we have not called createStream on",
147                  __FUNCTION__, mCameraId);
148            return BAD_VALUE;
149        }
150
151        int streamId = mStreamMap.valueAt(idx);
152        outputStreamIds.push_back(streamId);
153        ALOGV("%s: Camera %d: Appending output stream %d to request",
154              __FUNCTION__, mCameraId, streamId);
155    }
156
157    metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
158                    outputStreamIds.size());
159
160    int32_t requestId = mRequestIdCounter++;
161    metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
162    ALOGV("%s: Camera %d: Submitting request with ID %d",
163          __FUNCTION__, mCameraId, requestId);
164
165    if (streaming) {
166        res = mDevice->setStreamingRequest(metadata);
167        if (res != OK) {
168            ALOGE("%s: Camera %d:  Got error %d after trying to set streaming "
169                  "request", __FUNCTION__, mCameraId, res);
170        } else {
171            mStreamingRequestList.push_back(requestId);
172        }
173    } else {
174        res = mDevice->capture(metadata);
175        if (res != OK) {
176            ALOGE("%s: Camera %d: Got error %d after trying to set capture",
177                  __FUNCTION__, mCameraId, res);
178        }
179    }
180
181    ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId);
182    if (res == OK) {
183        return requestId;
184    }
185
186    return res;
187}
188
189status_t CameraDeviceClient::cancelRequest(int requestId) {
190    ATRACE_CALL();
191    ALOGV("%s, requestId = %d", __FUNCTION__, requestId);
192
193    status_t res;
194
195    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
196
197    Mutex::Autolock icl(mBinderSerializationLock);
198
199    if (!mDevice.get()) return DEAD_OBJECT;
200
201    Vector<int>::iterator it, end;
202    for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
203         it != end; ++it) {
204        if (*it == requestId) {
205            break;
206        }
207    }
208
209    if (it == end) {
210        ALOGE("%s: Camera%d: Did not find request id %d in list of streaming "
211              "requests", __FUNCTION__, mCameraId, requestId);
212        return BAD_VALUE;
213    }
214
215    res = mDevice->clearStreamingRequest();
216
217    if (res == OK) {
218        ALOGV("%s: Camera %d: Successfully cleared streaming request",
219              __FUNCTION__, mCameraId);
220        mStreamingRequestList.erase(it);
221    }
222
223    return res;
224}
225
226status_t CameraDeviceClient::deleteStream(int streamId) {
227    ATRACE_CALL();
228    ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
229
230    status_t res;
231    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
232
233    Mutex::Autolock icl(mBinderSerializationLock);
234
235    if (!mDevice.get()) return DEAD_OBJECT;
236
237    // Guard against trying to delete non-created streams
238    ssize_t index = NAME_NOT_FOUND;
239    for (size_t i = 0; i < mStreamMap.size(); ++i) {
240        if (streamId == mStreamMap.valueAt(i)) {
241            index = i;
242            break;
243        }
244    }
245
246    if (index == NAME_NOT_FOUND) {
247        ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream "
248              "created yet", __FUNCTION__, mCameraId, streamId);
249        return BAD_VALUE;
250    }
251
252    // Also returns BAD_VALUE if stream ID was not valid
253    res = mDevice->deleteStream(streamId);
254
255    if (res == BAD_VALUE) {
256        ALOGE("%s: Camera %d: Unexpected BAD_VALUE when deleting stream, but we"
257              " already checked and the stream ID (%d) should be valid.",
258              __FUNCTION__, mCameraId, streamId);
259    } else if (res == OK) {
260        mStreamMap.removeItemsAt(index);
261
262        ALOGV("%s: Camera %d: Successfully deleted stream ID (%d)",
263              __FUNCTION__, mCameraId, streamId);
264    }
265
266    return res;
267}
268
269status_t CameraDeviceClient::createStream(int width, int height, int format,
270                      const sp<IGraphicBufferProducer>& bufferProducer)
271{
272    ATRACE_CALL();
273    ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
274
275    status_t res;
276    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
277
278    Mutex::Autolock icl(mBinderSerializationLock);
279
280    if (!mDevice.get()) return DEAD_OBJECT;
281
282    // Don't create multiple streams for the same target surface
283    {
284        ssize_t index = mStreamMap.indexOfKey(bufferProducer->asBinder());
285        if (index != NAME_NOT_FOUND) {
286            ALOGW("%s: Camera %d: Buffer producer already has a stream for it "
287                  "(ID %d)",
288                  __FUNCTION__, mCameraId, index);
289            return ALREADY_EXISTS;
290        }
291    }
292
293    // HACK b/10949105
294    // Query consumer usage bits to set async operation mode for
295    // GLConsumer using controlledByApp parameter.
296    bool useAsync = false;
297    int32_t consumerUsage;
298    if ((res = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
299            &consumerUsage)) != OK) {
300        ALOGE("%s: Camera %d: Failed to query consumer usage", __FUNCTION__,
301              mCameraId);
302        return res;
303    }
304    if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
305        ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
306                __FUNCTION__, mCameraId);
307        useAsync = true;
308    }
309
310    sp<IBinder> binder;
311    sp<ANativeWindow> anw;
312    if (bufferProducer != 0) {
313        binder = bufferProducer->asBinder();
314        anw = new Surface(bufferProducer, useAsync);
315    }
316
317    // TODO: remove w,h,f since we are ignoring them
318
319    if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
320        ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__,
321              mCameraId);
322        return res;
323    }
324    if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
325        ALOGE("%s: Camera %d: Failed to query Surface height", __FUNCTION__,
326              mCameraId);
327        return res;
328    }
329    if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &format)) != OK) {
330        ALOGE("%s: Camera %d: Failed to query Surface format", __FUNCTION__,
331              mCameraId);
332        return res;
333    }
334
335    // FIXME: remove this override since the default format should be
336    //       IMPLEMENTATION_DEFINED. b/9487482
337    if (format >= HAL_PIXEL_FORMAT_RGBA_8888 &&
338        format <= HAL_PIXEL_FORMAT_BGRA_8888) {
339        ALOGW("%s: Camera %d: Overriding format 0x%x to IMPLEMENTATION_DEFINED",
340              __FUNCTION__, mCameraId, format);
341        format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
342    }
343
344    // TODO: add startConfigure/stopConfigure call to CameraDeviceBase
345    // this will make it so Camera3Device doesn't call configure_streams
346    // after each call, but only once we are done with all.
347
348    int streamId = -1;
349    if (format == HAL_PIXEL_FORMAT_BLOB) {
350        // JPEG buffers need to be sized for maximum possible compressed size
351        CameraMetadata staticInfo = mDevice->info();
352        camera_metadata_entry_t entry = staticInfo.find(ANDROID_JPEG_MAX_SIZE);
353        if (entry.count == 0) {
354            ALOGE("%s: Camera %d: Can't find maximum JPEG size in "
355                    "static metadata!", __FUNCTION__, mCameraId);
356            return INVALID_OPERATION;
357        }
358        int32_t maxJpegSize = entry.data.i32[0];
359        res = mDevice->createStream(anw, width, height, format, maxJpegSize,
360                &streamId);
361    } else {
362        // All other streams are a known size
363        res = mDevice->createStream(anw, width, height, format, /*size*/0,
364                &streamId);
365    }
366
367    if (res == OK) {
368        mStreamMap.add(bufferProducer->asBinder(), streamId);
369
370        ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
371              __FUNCTION__, mCameraId, streamId);
372
373        /**
374         * Set the stream transform flags to automatically
375         * rotate the camera stream for preview use cases.
376         */
377        int32_t transform = 0;
378        res = getRotationTransformLocked(&transform);
379
380        if (res != OK) {
381            // Error logged by getRotationTransformLocked.
382            return res;
383        }
384
385        res = mDevice->setStreamTransform(streamId, transform);
386        if (res != OK) {
387            ALOGE("%s: Failed to set stream transform (stream id %d)",
388                  __FUNCTION__, streamId);
389            return res;
390        }
391
392        return streamId;
393    }
394
395    return res;
396}
397
398// Create a request object from a template.
399status_t CameraDeviceClient::createDefaultRequest(int templateId,
400                                                  /*out*/
401                                                  CameraMetadata* request)
402{
403    ATRACE_CALL();
404    ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId);
405
406    status_t res;
407    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
408
409    Mutex::Autolock icl(mBinderSerializationLock);
410
411    if (!mDevice.get()) return DEAD_OBJECT;
412
413    CameraMetadata metadata;
414    if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK &&
415        request != NULL) {
416
417        request->swap(metadata);
418    }
419
420    return res;
421}
422
423status_t CameraDeviceClient::getCameraInfo(/*out*/CameraMetadata* info)
424{
425    ATRACE_CALL();
426    ALOGV("%s", __FUNCTION__);
427
428    status_t res = OK;
429
430    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
431
432    Mutex::Autolock icl(mBinderSerializationLock);
433
434    if (!mDevice.get()) return DEAD_OBJECT;
435
436    if (info != NULL) {
437        *info = mDevice->info(); // static camera metadata
438        // TODO: merge with device-specific camera metadata
439    }
440
441    return res;
442}
443
444status_t CameraDeviceClient::waitUntilIdle()
445{
446    ATRACE_CALL();
447    ALOGV("%s", __FUNCTION__);
448
449    status_t res = OK;
450    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
451
452    Mutex::Autolock icl(mBinderSerializationLock);
453
454    if (!mDevice.get()) return DEAD_OBJECT;
455
456    // FIXME: Also need check repeating burst.
457    if (!mStreamingRequestList.isEmpty()) {
458        ALOGE("%s: Camera %d: Try to waitUntilIdle when there are active streaming requests",
459              __FUNCTION__, mCameraId);
460        return INVALID_OPERATION;
461    }
462    res = mDevice->waitUntilDrained();
463    ALOGV("%s Done", __FUNCTION__);
464
465    return res;
466}
467
468status_t CameraDeviceClient::flush() {
469    ATRACE_CALL();
470    ALOGV("%s", __FUNCTION__);
471
472    status_t res = OK;
473    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
474
475    Mutex::Autolock icl(mBinderSerializationLock);
476
477    if (!mDevice.get()) return DEAD_OBJECT;
478
479    return mDevice->flush();
480}
481
482status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
483    String8 result;
484    result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
485            mCameraId,
486            getRemoteCallback()->asBinder().get(),
487            mClientPid);
488    result.append("  State: ");
489
490    // TODO: print dynamic/request section from most recent requests
491    mFrameProcessor->dump(fd, args);
492
493    return dumpDevice(fd, args);
494}
495
496
497void CameraDeviceClient::notifyError() {
498    // Thread safe. Don't bother locking.
499    sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
500
501    if (remoteCb != 0) {
502        remoteCb->onDeviceError(ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE);
503    }
504}
505
506void CameraDeviceClient::notifyIdle() {
507    // Thread safe. Don't bother locking.
508    sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
509
510    if (remoteCb != 0) {
511        remoteCb->onDeviceIdle();
512    }
513}
514
515void CameraDeviceClient::notifyShutter(int requestId,
516        nsecs_t timestamp) {
517    // Thread safe. Don't bother locking.
518    sp<ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
519    if (remoteCb != 0) {
520        remoteCb->onCaptureStarted(requestId, timestamp);
521    }
522}
523
524// TODO: refactor the code below this with IProCameraUser.
525// it's 100% copy-pasted, so lets not change it right now to make it easier.
526
527void CameraDeviceClient::detachDevice() {
528    if (mDevice == 0) return;
529
530    ALOGV("Camera %d: Stopping processors", mCameraId);
531
532    mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
533                                    FRAME_PROCESSOR_LISTENER_MAX_ID,
534                                    /*listener*/this);
535    mFrameProcessor->requestExit();
536    ALOGV("Camera %d: Waiting for threads", mCameraId);
537    mFrameProcessor->join();
538    ALOGV("Camera %d: Disconnecting device", mCameraId);
539
540    // WORKAROUND: HAL refuses to disconnect while there's streams in flight
541    {
542        mDevice->clearStreamingRequest();
543
544        status_t code;
545        if ((code = mDevice->waitUntilDrained()) != OK) {
546            ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
547                  code);
548        }
549    }
550
551    Camera2ClientBase::detachDevice();
552}
553
554/** Device-related methods */
555void CameraDeviceClient::onFrameAvailable(int32_t requestId,
556        const CameraMetadata& frame) {
557    ATRACE_CALL();
558    ALOGV("%s", __FUNCTION__);
559
560    // Thread-safe. No lock necessary.
561    sp<ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
562    if (remoteCb != NULL) {
563        ALOGV("%s: frame = %p ", __FUNCTION__, &frame);
564        remoteCb->onResultReceived(requestId, frame);
565    }
566}
567
568// TODO: move to Camera2ClientBase
569bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
570
571    const int pid = IPCThreadState::self()->getCallingPid();
572    const int selfPid = getpid();
573    camera_metadata_entry_t entry;
574
575    /**
576     * Mixin default important security values
577     * - android.led.transmit = defaulted ON
578     */
579    CameraMetadata staticInfo = mDevice->info();
580    entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS);
581    for(size_t i = 0; i < entry.count; ++i) {
582        uint8_t led = entry.data.u8[i];
583
584        switch(led) {
585            case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
586                uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
587                if (!metadata.exists(ANDROID_LED_TRANSMIT)) {
588                    metadata.update(ANDROID_LED_TRANSMIT,
589                                    &transmitDefault, 1);
590                }
591                break;
592            }
593        }
594    }
595
596    // We can do anything!
597    if (pid == selfPid) {
598        return true;
599    }
600
601    /**
602     * Permission check special fields in the request
603     * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT
604     */
605    entry = metadata.find(ANDROID_LED_TRANSMIT);
606    if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) {
607        String16 permissionString =
608            String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
609        if (!checkCallingPermission(permissionString)) {
610            const int uid = IPCThreadState::self()->getCallingUid();
611            ALOGE("Permission Denial: "
612                  "can't disable transmit LED pid=%d, uid=%d", pid, uid);
613            return false;
614        }
615    }
616
617    return true;
618}
619
620status_t CameraDeviceClient::getRotationTransformLocked(int32_t* transform) {
621    ALOGV("%s: begin", __FUNCTION__);
622
623    if (transform == NULL) {
624        ALOGW("%s: null transform", __FUNCTION__);
625        return BAD_VALUE;
626    }
627
628    *transform = 0;
629
630    const CameraMetadata& staticInfo = mDevice->info();
631    camera_metadata_ro_entry_t entry = staticInfo.find(ANDROID_SENSOR_ORIENTATION);
632    if (entry.count == 0) {
633        ALOGE("%s: Camera %d: Can't find android.sensor.orientation in "
634                "static metadata!", __FUNCTION__, mCameraId);
635        return INVALID_OPERATION;
636    }
637
638    camera_metadata_ro_entry_t entryFacing = staticInfo.find(ANDROID_LENS_FACING);
639    if (entry.count == 0) {
640        ALOGE("%s: Camera %d: Can't find android.lens.facing in "
641                "static metadata!", __FUNCTION__, mCameraId);
642        return INVALID_OPERATION;
643    }
644
645    int32_t& flags = *transform;
646
647    bool mirror = (entryFacing.data.u8[0] == ANDROID_LENS_FACING_FRONT);
648    int orientation = entry.data.i32[0];
649    if (!mirror) {
650        switch (orientation) {
651            case 0:
652                flags = 0;
653                break;
654            case 90:
655                flags = NATIVE_WINDOW_TRANSFORM_ROT_90;
656                break;
657            case 180:
658                flags = NATIVE_WINDOW_TRANSFORM_ROT_180;
659                break;
660            case 270:
661                flags = NATIVE_WINDOW_TRANSFORM_ROT_270;
662                break;
663            default:
664                ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
665                      __FUNCTION__, orientation);
666                return INVALID_OPERATION;
667        }
668    } else {
669        switch (orientation) {
670            case 0:
671                flags = HAL_TRANSFORM_FLIP_H;
672                break;
673            case 90:
674                flags = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90;
675                break;
676            case 180:
677                flags = HAL_TRANSFORM_FLIP_V;
678                break;
679            case 270:
680                flags = HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
681                break;
682            default:
683                ALOGE("%s: Invalid HAL android.sensor.orientation value: %d",
684                      __FUNCTION__, orientation);
685                return INVALID_OPERATION;
686        }
687
688    }
689
690    /**
691     * This magic flag makes surfaceflinger un-rotate the buffers
692     * to counter the extra global device UI rotation whenever the user
693     * physically rotates the device.
694     *
695     * By doing this, the camera buffer always ends up aligned
696     * with the physical camera for a "see through" effect.
697     *
698     * In essence, the buffer only gets rotated during preview use-cases.
699     * The user is still responsible to re-create streams of the proper
700     * aspect ratio, or the preview will end up looking non-uniformly
701     * stretched.
702     */
703    flags |= NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
704
705    ALOGV("%s: final transform = 0x%x", __FUNCTION__, flags);
706
707    return OK;
708}
709
710} // namespace android
711