blob: 00fe905a906c832a90de3fee4903e32a67fb0f66 [file] [log] [blame]
Angus Kong9ef99252013-07-18 18:04:19 -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
17package com.android.camera;
18
Angus Kongb50b5cb2013-08-09 14:55:20 -070019import static com.android.camera.util.CameraUtil.Assert;
Angus Kong9ef99252013-07-18 18:04:19 -070020
Sascha Haeberling8e963a52013-08-06 11:43:02 -070021import java.io.IOException;
22
Angus Kong9ef99252013-07-18 18:04:19 -070023import android.annotation.TargetApi;
24import android.graphics.SurfaceTexture;
25import android.hardware.Camera;
26import android.hardware.Camera.AutoFocusCallback;
27import android.hardware.Camera.AutoFocusMoveCallback;
28import android.hardware.Camera.ErrorCallback;
29import android.hardware.Camera.FaceDetectionListener;
30import android.hardware.Camera.OnZoomChangeListener;
31import android.hardware.Camera.Parameters;
32import android.hardware.Camera.PictureCallback;
33import android.hardware.Camera.PreviewCallback;
34import android.hardware.Camera.ShutterCallback;
35import android.os.Handler;
36import android.os.HandlerThread;
37import android.os.Looper;
38import android.os.Message;
39import android.util.Log;
40import android.view.SurfaceHolder;
41
Angus Kongb50b5cb2013-08-09 14:55:20 -070042import com.android.camera.util.ApiHelper;
Angus Kong9ef99252013-07-18 18:04:19 -070043
44/**
45 * A class to implement {@link CameraManager} of the Android camera framework.
46 */
47class AndroidCameraManagerImpl implements CameraManager {
48 private static final String TAG = "CAM_" +
49 AndroidCameraManagerImpl.class.getSimpleName();
50
51 private Parameters mParameters;
52 private boolean mParametersIsDirty;
53 private IOException mReconnectIOException;
54
55 /* Messages used in CameraHandler. */
56 // Camera initialization/finalization
57 private static final int OPEN_CAMERA = 1;
58 private static final int RELEASE = 2;
59 private static final int RECONNECT = 3;
60 private static final int UNLOCK = 4;
61 private static final int LOCK = 5;
62 // Preview
63 private static final int SET_PREVIEW_TEXTURE_ASYNC = 101;
64 private static final int START_PREVIEW_ASYNC = 102;
65 private static final int STOP_PREVIEW = 103;
66 private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 104;
67 private static final int ADD_CALLBACK_BUFFER = 105;
68 private static final int SET_PREVIEW_DISPLAY_ASYNC = 106;
69 private static final int SET_PREVIEW_CALLBACK = 107;
70 // Parameters
71 private static final int SET_PARAMETERS = 201;
72 private static final int GET_PARAMETERS = 202;
73 private static final int REFRESH_PARAMETERS = 203;
74 // Focus, Zoom
75 private static final int AUTO_FOCUS = 301;
76 private static final int CANCEL_AUTO_FOCUS = 302;
77 private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 303;
78 private static final int SET_ZOOM_CHANGE_LISTENER = 304;
79 // Face detection
80 private static final int SET_FACE_DETECTION_LISTENER = 461;
81 private static final int START_FACE_DETECTION = 462;
82 private static final int STOP_FACE_DETECTION = 463;
83 private static final int SET_ERROR_CALLBACK = 464;
84 // Presentation
85 private static final int ENABLE_SHUTTER_SOUND = 501;
86 private static final int SET_DISPLAY_ORIENTATION = 502;
87
88 private CameraHandler mCameraHandler;
89 private android.hardware.Camera mCamera;
90
91 // Used to retain a copy of Parameters for setting parameters.
92 private Parameters mParamsToSet;
93
94 AndroidCameraManagerImpl() {
95 HandlerThread ht = new HandlerThread("Camera Handler Thread");
96 ht.start();
97 mCameraHandler = new CameraHandler(ht.getLooper());
98 }
99
100 private class CameraHandler extends Handler {
101 CameraHandler(Looper looper) {
102 super(looper);
103 }
104
105 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
106 private void startFaceDetection() {
107 mCamera.startFaceDetection();
108 }
109
110 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
111 private void stopFaceDetection() {
112 mCamera.stopFaceDetection();
113 }
114
115 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
116 private void setFaceDetectionListener(FaceDetectionListener listener) {
117 mCamera.setFaceDetectionListener(listener);
118 }
119
120 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
121 private void setPreviewTexture(Object surfaceTexture) {
122 try {
123 mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture);
124 } catch (IOException e) {
125 throw new RuntimeException(e);
126 }
127 }
128
129 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN_MR1)
130 private void enableShutterSound(boolean enable) {
131 mCamera.enableShutterSound(enable);
132 }
133
134 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
135 private void setAutoFocusMoveCallback(
136 android.hardware.Camera camera, Object cb) {
137 camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb);
138 }
139
140 public void requestTakePicture(
141 final ShutterCallback shutter,
142 final PictureCallback raw,
143 final PictureCallback postView,
144 final PictureCallback jpeg) {
145 post(new Runnable() {
146 @Override
147 public void run() {
148 try {
149 mCamera.takePicture(shutter, raw, postView, jpeg);
150 } catch (RuntimeException e) {
151 // TODO: output camera state and focus state for debugging.
152 Log.e(TAG, "take picture failed.");
153 throw e;
154 }
155 }
156 });
157 }
158
159 /**
160 * Waits for all the {@code Message} and {@code Runnable} currently in the queue
161 * are processed.
162 *
163 * @return {@code false} if the wait was interrupted, {@code true} otherwise.
164 */
165 public boolean waitDone() {
166 final Object waitDoneLock = new Object();
167 final Runnable unlockRunnable = new Runnable() {
168 @Override
169 public void run() {
170 synchronized (waitDoneLock) {
171 waitDoneLock.notifyAll();
172 }
173 }
174 };
175
176 synchronized (waitDoneLock) {
177 mCameraHandler.post(unlockRunnable);
178 try {
179 waitDoneLock.wait();
180 } catch (InterruptedException ex) {
181 Log.v(TAG, "waitDone interrupted");
182 return false;
183 }
184 }
185 return true;
186 }
187
188 /**
189 * This method does not deal with the API level check. Everyone should
190 * check first for supported operations before sending message to this handler.
191 */
192 @Override
193 public void handleMessage(final Message msg) {
194 try {
195 switch (msg.what) {
196 case OPEN_CAMERA:
Angus Kong6d29a642013-07-31 12:46:54 -0700197 mCamera = android.hardware.Camera.open(msg.arg1);
Angus Kong9ef99252013-07-18 18:04:19 -0700198 if (mCamera != null) {
199 mParametersIsDirty = true;
200
201 // Get a instance of Camera.Parameters for later use.
202 if (mParamsToSet == null) {
203 mParamsToSet = mCamera.getParameters();
204 }
205 }
206 return;
207
208 case RELEASE:
209 mCamera.release();
210 mCamera = null;
211 return;
212
213 case RECONNECT:
214 mReconnectIOException = null;
215 try {
216 mCamera.reconnect();
217 } catch (IOException ex) {
218 mReconnectIOException = ex;
219 }
220 return;
221
222 case UNLOCK:
223 mCamera.unlock();
224 return;
225
226 case LOCK:
227 mCamera.lock();
228 return;
229
230 case SET_PREVIEW_TEXTURE_ASYNC:
231 setPreviewTexture(msg.obj);
232 return;
233
234 case SET_PREVIEW_DISPLAY_ASYNC:
235 try {
236 mCamera.setPreviewDisplay((SurfaceHolder) msg.obj);
237 } catch (IOException e) {
238 throw new RuntimeException(e);
239 }
240 return;
241
242 case START_PREVIEW_ASYNC:
243 mCamera.startPreview();
244 return;
245
246 case STOP_PREVIEW:
247 mCamera.stopPreview();
248 return;
249
250 case SET_PREVIEW_CALLBACK_WITH_BUFFER:
251 mCamera.setPreviewCallbackWithBuffer(
252 (PreviewCallback) msg.obj);
253 return;
254
255 case ADD_CALLBACK_BUFFER:
256 mCamera.addCallbackBuffer((byte[]) msg.obj);
257 return;
258
259 case AUTO_FOCUS:
260 mCamera.autoFocus((AutoFocusCallback) msg.obj);
261 return;
262
263 case CANCEL_AUTO_FOCUS:
264 mCamera.cancelAutoFocus();
265 return;
266
267 case SET_AUTO_FOCUS_MOVE_CALLBACK:
268 setAutoFocusMoveCallback(mCamera, msg.obj);
269 return;
270
271 case SET_DISPLAY_ORIENTATION:
272 mCamera.setDisplayOrientation(msg.arg1);
273 return;
274
275 case SET_ZOOM_CHANGE_LISTENER:
276 mCamera.setZoomChangeListener(
277 (OnZoomChangeListener) msg.obj);
278 return;
279
280 case SET_FACE_DETECTION_LISTENER:
281 setFaceDetectionListener((FaceDetectionListener) msg.obj);
282 return;
283
284 case START_FACE_DETECTION:
285 startFaceDetection();
286 return;
287
288 case STOP_FACE_DETECTION:
289 stopFaceDetection();
290 return;
291
292 case SET_ERROR_CALLBACK:
293 mCamera.setErrorCallback((ErrorCallback) msg.obj);
294 return;
295
296 case SET_PARAMETERS:
297 mParametersIsDirty = true;
298 mParamsToSet.unflatten((String) msg.obj);
299 mCamera.setParameters(mParamsToSet);
300 return;
301
302 case GET_PARAMETERS:
303 if (mParametersIsDirty) {
304 mParameters = mCamera.getParameters();
305 mParametersIsDirty = false;
306 }
307 return;
308
309 case SET_PREVIEW_CALLBACK:
310 mCamera.setPreviewCallback((PreviewCallback) msg.obj);
311 return;
312
313 case ENABLE_SHUTTER_SOUND:
314 enableShutterSound((msg.arg1 == 1) ? true : false);
315 return;
316
317 case REFRESH_PARAMETERS:
318 mParametersIsDirty = true;
319 return;
320
321 default:
322 throw new RuntimeException("Invalid CameraProxy message=" + msg.what);
323 }
324 } catch (RuntimeException e) {
325 if (msg.what != RELEASE && mCamera != null) {
326 try {
327 mCamera.release();
328 } catch (Exception ex) {
329 Log.e(TAG, "Fail to release the camera.");
330 }
331 mCamera = null;
332 }
333 throw e;
334 }
335 }
336 }
337
338 @Override
339 public CameraManager.CameraProxy cameraOpen(int cameraId) {
340 mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0).sendToTarget();
341 mCameraHandler.waitDone();
342 if (mCamera != null) {
343 return new AndroidCameraProxyImpl();
344 } else {
345 return null;
346 }
347 }
348
349 /**
350 * A class which implements {@link CameraManager.CameraProxy} and
351 * camera handler thread.
352 */
353 public class AndroidCameraProxyImpl implements CameraManager.CameraProxy {
354
355 private AndroidCameraProxyImpl() {
356 Assert(mCamera != null);
357 }
358
359 @Override
360 public android.hardware.Camera getCamera() {
361 return mCamera;
362 }
363
364 @Override
365 public void release() {
366 // release() must be synchronous so we know exactly when the camera
367 // is released and can continue on.
368 mCameraHandler.sendEmptyMessage(RELEASE);
369 mCameraHandler.waitDone();
370 }
371
372 @Override
373 public void reconnect() throws IOException {
374 mCameraHandler.sendEmptyMessage(RECONNECT);
375 mCameraHandler.waitDone();
376 if (mReconnectIOException != null) {
377 throw mReconnectIOException;
378 }
379 }
380
381 @Override
382 public void unlock() {
383 mCameraHandler.sendEmptyMessage(UNLOCK);
384 mCameraHandler.waitDone();
385 }
386
387 @Override
388 public void lock() {
389 mCameraHandler.sendEmptyMessage(LOCK);
390 }
391
392 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
393 @Override
Angus Kong9e765522013-07-31 14:05:20 -0700394 public void setPreviewTexture(SurfaceTexture surfaceTexture) {
Angus Kong9ef99252013-07-18 18:04:19 -0700395 mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget();
396 }
397
398 @Override
Angus Kong9e765522013-07-31 14:05:20 -0700399 public void setPreviewDisplay(SurfaceHolder surfaceHolder) {
Angus Kong9ef99252013-07-18 18:04:19 -0700400 mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget();
401 }
402
403 @Override
404 public void startPreview() {
405 mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC);
406 }
407
408 @Override
409 public void stopPreview() {
410 mCameraHandler.sendEmptyMessage(STOP_PREVIEW);
411 mCameraHandler.waitDone();
412 }
413
414 @Override
415 public void setPreviewDataCallback(
Angus Kong9e765522013-07-31 14:05:20 -0700416 Handler handler, CameraPreviewDataCallback cb) {
Angus Kong9ef99252013-07-18 18:04:19 -0700417 mCameraHandler.obtainMessage(
418 SET_PREVIEW_CALLBACK,
Angus Kong9e765522013-07-31 14:05:20 -0700419 PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
Angus Kong9ef99252013-07-18 18:04:19 -0700420 }
421
422 @Override
423 public void setPreviewDataCallbackWithBuffer(
Angus Kong9e765522013-07-31 14:05:20 -0700424 Handler handler, CameraPreviewDataCallback cb) {
Angus Kong9ef99252013-07-18 18:04:19 -0700425 mCameraHandler.obtainMessage(
426 SET_PREVIEW_CALLBACK_WITH_BUFFER,
Angus Kong9e765522013-07-31 14:05:20 -0700427 PreviewCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
Angus Kong9ef99252013-07-18 18:04:19 -0700428 }
429
430 @Override
431 public void addCallbackBuffer(byte[] callbackBuffer) {
432 mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget();
433 }
434
435 @Override
436 public void autoFocus(Handler handler, CameraAFCallback cb) {
437 mCameraHandler.obtainMessage(
438 AUTO_FOCUS,
Angus Kong9e765522013-07-31 14:05:20 -0700439 AFCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
Angus Kong9ef99252013-07-18 18:04:19 -0700440 }
441
442 @Override
443 public void cancelAutoFocus() {
444 mCameraHandler.removeMessages(AUTO_FOCUS);
445 mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS);
446 }
447
448 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
449 @Override
450 public void setAutoFocusMoveCallback(
Angus Kong9e765522013-07-31 14:05:20 -0700451 Handler handler, CameraAFMoveCallback cb) {
Angus Kong9ef99252013-07-18 18:04:19 -0700452 mCameraHandler.obtainMessage(
453 SET_AUTO_FOCUS_MOVE_CALLBACK,
Angus Kong9e765522013-07-31 14:05:20 -0700454 AFMoveCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
Angus Kong9ef99252013-07-18 18:04:19 -0700455 }
456
457 @Override
458 public void takePicture(
Angus Kong9e765522013-07-31 14:05:20 -0700459 Handler handler,
460 CameraShutterCallback shutter,
461 CameraPictureCallback raw,
462 CameraPictureCallback post,
463 CameraPictureCallback jpeg) {
Angus Kong9ef99252013-07-18 18:04:19 -0700464 mCameraHandler.requestTakePicture(
Angus Kong9e765522013-07-31 14:05:20 -0700465 ShutterCallbackForward.getNewInstance(handler, this, shutter),
466 PictureCallbackForward.getNewInstance(handler, this, raw),
467 PictureCallbackForward.getNewInstance(handler, this, post),
468 PictureCallbackForward.getNewInstance(handler, this, jpeg));
Angus Kong9ef99252013-07-18 18:04:19 -0700469 }
470
471 @Override
472 public void setDisplayOrientation(int degrees) {
473 mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0)
474 .sendToTarget();
475 }
476
477 @Override
478 public void setZoomChangeListener(OnZoomChangeListener listener) {
479 mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget();
480 }
481
482 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH)
Angus Kong9e765522013-07-31 14:05:20 -0700483 public void setFaceDetectionCallback(
484 Handler handler, CameraFaceDetectionCallback cb) {
485 mCameraHandler.obtainMessage(
486 SET_FACE_DETECTION_LISTENER,
487 FaceDetectionCallbackForward.getNewInstance(handler, this, cb)).sendToTarget();
Angus Kong9ef99252013-07-18 18:04:19 -0700488 }
489
490 @Override
491 public void startFaceDetection() {
492 mCameraHandler.sendEmptyMessage(START_FACE_DETECTION);
493 }
494
495 @Override
496 public void stopFaceDetection() {
497 mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION);
498 }
499
500 @Override
501 public void setErrorCallback(ErrorCallback cb) {
502 mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget();
503 }
504
505 @Override
506 public void setParameters(Parameters params) {
507 if (params == null) {
508 Log.v(TAG, "null parameters in setParameters()");
509 return;
510 }
511 mCameraHandler.obtainMessage(SET_PARAMETERS, params.flatten())
512 .sendToTarget();
513 }
514
515 @Override
516 public Parameters getParameters() {
517 mCameraHandler.sendEmptyMessage(GET_PARAMETERS);
518 mCameraHandler.waitDone();
519 return mParameters;
520 }
521
522 @Override
523 public void refreshParameters() {
524 mCameraHandler.sendEmptyMessage(REFRESH_PARAMETERS);
525 }
526
527 @Override
528 public void enableShutterSound(boolean enable) {
529 mCameraHandler.obtainMessage(
530 ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget();
531 }
532 }
533
534 /**
535 * A helper class to forward AutoFocusCallback to another thread.
536 */
537 private static class AFCallbackForward implements AutoFocusCallback {
538 private final Handler mHandler;
539 private final CameraProxy mCamera;
540 private final CameraAFCallback mCallback;
541
542 /**
Angus Kong9e765522013-07-31 14:05:20 -0700543 * Returns a new instance of {@link AFCallbackForward}.
Angus Kong9ef99252013-07-18 18:04:19 -0700544 *
545 * @param handler The handler in which the callback will be invoked in.
546 * @param camera The {@link CameraProxy} which the callback is from.
547 * @param cb The callback to be invoked.
548 * @return The instance of the {@link AFCallbackForward},
Angus Kong9e765522013-07-31 14:05:20 -0700549 * or null if any parameter is null.
Angus Kong9ef99252013-07-18 18:04:19 -0700550 */
Angus Kong9e765522013-07-31 14:05:20 -0700551 public static AFCallbackForward getNewInstance(
Angus Kong9ef99252013-07-18 18:04:19 -0700552 Handler handler, CameraProxy camera, CameraAFCallback cb) {
553 if (handler == null || camera == null || cb == null) return null;
554 return new AFCallbackForward(handler, camera, cb);
555 }
556
557 private AFCallbackForward(
558 Handler h, CameraProxy camera, CameraAFCallback cb) {
559 mHandler = h;
560 mCamera = camera;
561 mCallback = cb;
562 }
563
564 @Override
565 public void onAutoFocus(final boolean b, Camera camera) {
566 mHandler.post(new Runnable() {
567 @Override
568 public void run() {
569 mCallback.onAutoFocus(b, mCamera);
570 }
571 });
572 }
573 }
574
575 /** A helper class to forward AutoFocusMoveCallback to another thread. */
576 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN)
577 private static class AFMoveCallbackForward implements AutoFocusMoveCallback {
578 private final Handler mHandler;
579 private final CameraAFMoveCallback mCallback;
580 private final CameraProxy mCamera;
581
582 /**
Angus Kong9e765522013-07-31 14:05:20 -0700583 * Returns a new instance of {@link AFMoveCallbackForward}.
Angus Kong9ef99252013-07-18 18:04:19 -0700584 *
585 * @param handler The handler in which the callback will be invoked in.
586 * @param camera The {@link CameraProxy} which the callback is from.
587 * @param cb The callback to be invoked.
588 * @return The instance of the {@link AFMoveCallbackForward},
Angus Kong9e765522013-07-31 14:05:20 -0700589 * or null if any parameter is null.
Angus Kong9ef99252013-07-18 18:04:19 -0700590 */
Angus Kong9e765522013-07-31 14:05:20 -0700591 public static AFMoveCallbackForward getNewInstance(
Angus Kong9ef99252013-07-18 18:04:19 -0700592 Handler handler, CameraProxy camera, CameraAFMoveCallback cb) {
593 if (handler == null || camera == null || cb == null) return null;
594 return new AFMoveCallbackForward(handler, camera, cb);
595 }
596
597 private AFMoveCallbackForward(
598 Handler h, CameraProxy camera, CameraAFMoveCallback cb) {
599 mHandler = h;
600 mCamera = camera;
601 mCallback = cb;
602 }
603
604 @Override
605 public void onAutoFocusMoving(
606 final boolean moving, android.hardware.Camera camera) {
607 mHandler.post(new Runnable() {
608 @Override
609 public void run() {
610 mCallback.onAutoFocusMoving(moving, mCamera);
611 }
612 });
613 }
614 }
615
616 /**
617 * A helper class to forward ShutterCallback to to another thread.
618 */
619 private static class ShutterCallbackForward implements ShutterCallback {
620 private final Handler mHandler;
621 private final CameraShutterCallback mCallback;
622 private final CameraProxy mCamera;
623
624 /**
Angus Kong9e765522013-07-31 14:05:20 -0700625 * Returns a new instance of {@link ShutterCallbackForward}.
Angus Kong9ef99252013-07-18 18:04:19 -0700626 *
627 * @param handler The handler in which the callback will be invoked in.
628 * @param camera The {@link CameraProxy} which the callback is from.
629 * @param cb The callback to be invoked.
630 * @return The instance of the {@link ShutterCallbackForward},
Angus Kong9e765522013-07-31 14:05:20 -0700631 * or null if any parameter is null.
Angus Kong9ef99252013-07-18 18:04:19 -0700632 */
Angus Kong9e765522013-07-31 14:05:20 -0700633 public static ShutterCallbackForward getNewInstance(
Angus Kong9ef99252013-07-18 18:04:19 -0700634 Handler handler, CameraProxy camera, CameraShutterCallback cb) {
635 if (handler == null || camera == null || cb == null) return null;
636 return new ShutterCallbackForward(handler, camera, cb);
637 }
638
639 private ShutterCallbackForward(
640 Handler h, CameraProxy camera, CameraShutterCallback cb) {
641 mHandler = h;
642 mCamera = camera;
643 mCallback = cb;
644 }
645
646 @Override
647 public void onShutter() {
648 mHandler.post(new Runnable() {
649 @Override
650 public void run() {
651 mCallback.onShutter(mCamera);
652 }
653 });
654 }
655 }
656
657 /**
658 * A helper class to forward PictureCallback to another thread.
659 */
660 private static class PictureCallbackForward implements PictureCallback {
661 private final Handler mHandler;
662 private final CameraPictureCallback mCallback;
663 private final CameraProxy mCamera;
664
665 /**
Angus Kong9e765522013-07-31 14:05:20 -0700666 * Returns a new instance of {@link PictureCallbackForward}.
Angus Kong9ef99252013-07-18 18:04:19 -0700667 *
668 * @param handler The handler in which the callback will be invoked in.
669 * @param camera The {@link CameraProxy} which the callback is from.
670 * @param cb The callback to be invoked.
671 * @return The instance of the {@link PictureCallbackForward},
Angus Kong9e765522013-07-31 14:05:20 -0700672 * or null if any parameters is null.
Angus Kong9ef99252013-07-18 18:04:19 -0700673 */
Angus Kong9e765522013-07-31 14:05:20 -0700674 public static PictureCallbackForward getNewInstance(
Angus Kong9ef99252013-07-18 18:04:19 -0700675 Handler handler, CameraProxy camera, CameraPictureCallback cb) {
676 if (handler == null || camera == null || cb == null) return null;
677 return new PictureCallbackForward(handler, camera, cb);
678 }
679
680 private PictureCallbackForward(
681 Handler h, CameraProxy camera, CameraPictureCallback cb) {
682 mHandler = h;
683 mCamera = camera;
684 mCallback = cb;
685 }
686
687 @Override
688 public void onPictureTaken(
689 final byte[] data, android.hardware.Camera camera) {
690 mHandler.post(new Runnable() {
691 @Override
692 public void run() {
693 mCallback.onPictureTaken(data, mCamera);
694 }
695 });
696 }
697 }
698
699 /**
700 * A helper class to forward PreviewCallback to another thread.
701 */
702 private static class PreviewCallbackForward implements PreviewCallback {
703 private final Handler mHandler;
704 private final CameraPreviewDataCallback mCallback;
705 private final CameraProxy mCamera;
706
707 /**
Angus Kong9e765522013-07-31 14:05:20 -0700708 * Returns a new instance of {@link PreviewCallbackForward}.
Angus Kong9ef99252013-07-18 18:04:19 -0700709 *
710 * @param handler The handler in which the callback will be invoked in.
711 * @param camera The {@link CameraProxy} which the callback is from.
712 * @param cb The callback to be invoked.
Angus Kong9e765522013-07-31 14:05:20 -0700713 * @return The instance of the {@link PreviewCallbackForward},
714 * or null if any parameters is null.
Angus Kong9ef99252013-07-18 18:04:19 -0700715 */
Angus Kong9e765522013-07-31 14:05:20 -0700716 public static PreviewCallbackForward getNewInstance(
Angus Kong9ef99252013-07-18 18:04:19 -0700717 Handler handler, CameraProxy camera, CameraPreviewDataCallback cb) {
718 if (handler == null || camera == null || cb == null) return null;
719 return new PreviewCallbackForward(handler, camera, cb);
720 }
721
722 private PreviewCallbackForward(
723 Handler h, CameraProxy camera, CameraPreviewDataCallback cb) {
724 mHandler = h;
725 mCamera = camera;
726 mCallback = cb;
727 }
728
729 @Override
730 public void onPreviewFrame(
731 final byte[] data, android.hardware.Camera camera) {
732 mHandler.post(new Runnable() {
733 @Override
734 public void run() {
735 mCallback.onPreviewFrame(data, mCamera);
736 }
737 });
738 }
739 }
Angus Kong9e765522013-07-31 14:05:20 -0700740
741 private static class FaceDetectionCallbackForward implements FaceDetectionListener {
742 private final Handler mHandler;
743 private final CameraFaceDetectionCallback mCallback;
744 private final CameraProxy mCamera;
745
746 /**
747 * Returns a new instance of {@link FaceDetectionCallbackForward}.
748 *
749 * @param handler The handler in which the callback will be invoked in.
750 * @param camera The {@link CameraProxy} which the callback is from.
751 * @param cb The callback to be invoked.
752 * @return The instance of the {@link FaceDetectionCallbackForward},
753 * or null if any parameter is null.
754 */
755 public static FaceDetectionCallbackForward getNewInstance(
756 Handler handler, CameraProxy camera, CameraFaceDetectionCallback cb) {
757 if (handler == null || camera == null || cb == null) return null;
758 return new FaceDetectionCallbackForward(handler, camera, cb);
759 }
760
761 private FaceDetectionCallbackForward(
762 Handler h, CameraProxy camera, CameraFaceDetectionCallback cb) {
763 mHandler = h;
764 mCamera = camera;
765 mCallback = cb;
766 }
767
768 @Override
769 public void onFaceDetection(
770 final Camera.Face[] faces, Camera camera) {
771 mHandler.post(new Runnable() {
772 @Override
773 public void run() {
774 mCallback.onFaceDetection(faces, mCamera);
775 }
776 });
777 }
778 }
Angus Kong9ef99252013-07-18 18:04:19 -0700779}