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