1 /* 2 * Copyright (C) 2012 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 package com.android.camera; 18 19 import static com.android.camera.Util.Assert; 20 21 import android.annotation.TargetApi; 22 import android.graphics.SurfaceTexture; 23 import android.hardware.Camera.AutoFocusCallback; 24 import android.hardware.Camera.AutoFocusMoveCallback; 25 import android.hardware.Camera.ErrorCallback; 26 import android.hardware.Camera.FaceDetectionListener; 27 import android.hardware.Camera.OnZoomChangeListener; 28 import android.hardware.Camera.Parameters; 29 import android.hardware.Camera.PictureCallback; 30 import android.hardware.Camera.PreviewCallback; 31 import android.hardware.Camera.ShutterCallback; 32 import android.os.ConditionVariable; 33 import android.os.Handler; 34 import android.os.HandlerThread; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.view.SurfaceHolder; 38 import android.util.Log; 39 40 import com.android.gallery3d.common.ApiHelper; 41 42 import java.io.IOException; 43 44 public class CameraManager { 45 private static final String TAG = "CameraManager"; 46 private static CameraManager sCameraManager = new CameraManager(); 47 48 // Thread progress signals 49 private ConditionVariable mSig = new ConditionVariable(); 50 51 private Parameters mParameters; 52 private IOException mReconnectException; 53 54 private static final int RELEASE = 1; 55 private static final int RECONNECT = 2; 56 private static final int UNLOCK = 3; 57 private static final int LOCK = 4; 58 private static final int SET_PREVIEW_TEXTURE_ASYNC = 5; 59 private static final int START_PREVIEW_ASYNC = 6; 60 private static final int STOP_PREVIEW = 7; 61 private static final int SET_PREVIEW_CALLBACK_WITH_BUFFER = 8; 62 private static final int ADD_CALLBACK_BUFFER = 9; 63 private static final int AUTO_FOCUS = 10; 64 private static final int CANCEL_AUTO_FOCUS = 11; 65 private static final int SET_AUTO_FOCUS_MOVE_CALLBACK = 12; 66 private static final int SET_DISPLAY_ORIENTATION = 13; 67 private static final int SET_ZOOM_CHANGE_LISTENER = 14; 68 private static final int SET_FACE_DETECTION_LISTENER = 15; 69 private static final int START_FACE_DETECTION = 16; 70 private static final int STOP_FACE_DETECTION = 17; 71 private static final int SET_ERROR_CALLBACK = 18; 72 private static final int SET_PARAMETERS = 19; 73 private static final int GET_PARAMETERS = 20; 74 private static final int SET_PARAMETERS_ASYNC = 21; 75 private static final int WAIT_FOR_IDLE = 22; 76 private static final int SET_PREVIEW_DISPLAY_ASYNC = 23; 77 private static final int SET_PREVIEW_CALLBACK = 24; 78 private static final int ENABLE_SHUTTER_SOUND = 25; 79 80 private Handler mCameraHandler; 81 private CameraProxy mCameraProxy; 82 private android.hardware.Camera mCamera; 83 instance()84 public static CameraManager instance() { 85 return sCameraManager; 86 } 87 CameraManager()88 private CameraManager() { 89 HandlerThread ht = new HandlerThread("Camera Handler Thread"); 90 ht.start(); 91 mCameraHandler = new CameraHandler(ht.getLooper()); 92 } 93 94 private class CameraHandler extends Handler { CameraHandler(Looper looper)95 CameraHandler(Looper looper) { 96 super(looper); 97 } 98 99 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) startFaceDetection()100 private void startFaceDetection() { 101 mCamera.startFaceDetection(); 102 } 103 104 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) stopFaceDetection()105 private void stopFaceDetection() { 106 mCamera.stopFaceDetection(); 107 } 108 109 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) setFaceDetectionListener(FaceDetectionListener listener)110 private void setFaceDetectionListener(FaceDetectionListener listener) { 111 mCamera.setFaceDetectionListener(listener); 112 } 113 114 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) setPreviewTexture(Object surfaceTexture)115 private void setPreviewTexture(Object surfaceTexture) { 116 try { 117 mCamera.setPreviewTexture((SurfaceTexture) surfaceTexture); 118 } catch(IOException e) { 119 throw new RuntimeException(e); 120 } 121 } 122 123 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN_MR1) enableShutterSound(boolean enable)124 private void enableShutterSound(boolean enable) { 125 mCamera.enableShutterSound(enable); 126 } 127 128 /* 129 * This method does not deal with the build version check. Everyone should 130 * check first before sending message to this handler. 131 */ 132 @Override handleMessage(final Message msg)133 public void handleMessage(final Message msg) { 134 try { 135 switch (msg.what) { 136 case RELEASE: 137 mCamera.release(); 138 mCamera = null; 139 mCameraProxy = null; 140 break; 141 142 case RECONNECT: 143 mReconnectException = null; 144 try { 145 mCamera.reconnect(); 146 } catch (IOException ex) { 147 mReconnectException = ex; 148 } 149 break; 150 151 case UNLOCK: 152 mCamera.unlock(); 153 break; 154 155 case LOCK: 156 mCamera.lock(); 157 break; 158 159 case SET_PREVIEW_TEXTURE_ASYNC: 160 setPreviewTexture(msg.obj); 161 return; // no need to call mSig.open() 162 163 case SET_PREVIEW_DISPLAY_ASYNC: 164 try { 165 mCamera.setPreviewDisplay((SurfaceHolder) msg.obj); 166 } catch(IOException e) { 167 throw new RuntimeException(e); 168 } 169 return; // no need to call mSig.open() 170 171 case START_PREVIEW_ASYNC: 172 mCamera.startPreview(); 173 return; // no need to call mSig.open() 174 175 case STOP_PREVIEW: 176 mCamera.stopPreview(); 177 break; 178 179 case SET_PREVIEW_CALLBACK_WITH_BUFFER: 180 mCamera.setPreviewCallbackWithBuffer( 181 (PreviewCallback) msg.obj); 182 break; 183 184 case ADD_CALLBACK_BUFFER: 185 mCamera.addCallbackBuffer((byte[]) msg.obj); 186 break; 187 188 case AUTO_FOCUS: 189 mCamera.autoFocus((AutoFocusCallback) msg.obj); 190 break; 191 192 case CANCEL_AUTO_FOCUS: 193 mCamera.cancelAutoFocus(); 194 break; 195 196 case SET_AUTO_FOCUS_MOVE_CALLBACK: 197 setAutoFocusMoveCallback(mCamera, msg.obj); 198 break; 199 200 case SET_DISPLAY_ORIENTATION: 201 mCamera.setDisplayOrientation(msg.arg1); 202 break; 203 204 case SET_ZOOM_CHANGE_LISTENER: 205 mCamera.setZoomChangeListener( 206 (OnZoomChangeListener) msg.obj); 207 break; 208 209 case SET_FACE_DETECTION_LISTENER: 210 setFaceDetectionListener((FaceDetectionListener) msg.obj); 211 break; 212 213 case START_FACE_DETECTION: 214 startFaceDetection(); 215 break; 216 217 case STOP_FACE_DETECTION: 218 stopFaceDetection(); 219 break; 220 221 case SET_ERROR_CALLBACK: 222 mCamera.setErrorCallback((ErrorCallback) msg.obj); 223 break; 224 225 case SET_PARAMETERS: 226 mCamera.setParameters((Parameters) msg.obj); 227 break; 228 229 case GET_PARAMETERS: 230 mParameters = mCamera.getParameters(); 231 break; 232 233 case SET_PARAMETERS_ASYNC: 234 mCamera.setParameters((Parameters) msg.obj); 235 return; // no need to call mSig.open() 236 237 case SET_PREVIEW_CALLBACK: 238 mCamera.setPreviewCallback((PreviewCallback) msg.obj); 239 break; 240 241 case ENABLE_SHUTTER_SOUND: 242 enableShutterSound((msg.arg1 == 1) ? true : false); 243 break; 244 245 case WAIT_FOR_IDLE: 246 // do nothing 247 break; 248 249 default: 250 throw new RuntimeException("Invalid CameraProxy message=" + msg.what); 251 } 252 } catch (RuntimeException e) { 253 if (msg.what != RELEASE && mCamera != null) { 254 try { 255 mCamera.release(); 256 } catch (Exception ex) { 257 Log.e(TAG, "Fail to release the camera."); 258 } 259 mCamera = null; 260 mCameraProxy = null; 261 } 262 throw e; 263 } 264 mSig.open(); 265 } 266 } 267 268 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) setAutoFocusMoveCallback(android.hardware.Camera camera, Object cb)269 private void setAutoFocusMoveCallback(android.hardware.Camera camera, 270 Object cb) { 271 camera.setAutoFocusMoveCallback((AutoFocusMoveCallback) cb); 272 } 273 274 // Open camera synchronously. This method is invoked in the context of a 275 // background thread. cameraOpen(int cameraId)276 CameraProxy cameraOpen(int cameraId) { 277 // Cannot open camera in mCameraHandler, otherwise all camera events 278 // will be routed to mCameraHandler looper, which in turn will call 279 // event handler like Camera.onFaceDetection, which in turn will modify 280 // UI and cause exception like this: 281 // CalledFromWrongThreadException: Only the original thread that created 282 // a view hierarchy can touch its views. 283 mCamera = android.hardware.Camera.open(cameraId); 284 if (mCamera != null) { 285 mCameraProxy = new CameraProxy(); 286 return mCameraProxy; 287 } else { 288 return null; 289 } 290 } 291 292 public class CameraProxy { CameraProxy()293 private CameraProxy() { 294 Assert(mCamera != null); 295 } 296 getCamera()297 public android.hardware.Camera getCamera() { 298 return mCamera; 299 } 300 release()301 public void release() { 302 mSig.close(); 303 mCameraHandler.sendEmptyMessage(RELEASE); 304 mSig.block(); 305 } 306 reconnect()307 public void reconnect() throws IOException { 308 mSig.close(); 309 mCameraHandler.sendEmptyMessage(RECONNECT); 310 mSig.block(); 311 if (mReconnectException != null) { 312 throw mReconnectException; 313 } 314 } 315 unlock()316 public void unlock() { 317 mSig.close(); 318 mCameraHandler.sendEmptyMessage(UNLOCK); 319 mSig.block(); 320 } 321 lock()322 public void lock() { 323 mSig.close(); 324 mCameraHandler.sendEmptyMessage(LOCK); 325 mSig.block(); 326 } 327 328 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) setPreviewTextureAsync(final SurfaceTexture surfaceTexture)329 public void setPreviewTextureAsync(final SurfaceTexture surfaceTexture) { 330 mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget(); 331 } 332 setPreviewDisplayAsync(final SurfaceHolder surfaceHolder)333 public void setPreviewDisplayAsync(final SurfaceHolder surfaceHolder) { 334 mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget(); 335 } 336 startPreviewAsync()337 public void startPreviewAsync() { 338 mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC); 339 } 340 stopPreview()341 public void stopPreview() { 342 mSig.close(); 343 mCameraHandler.sendEmptyMessage(STOP_PREVIEW); 344 mSig.block(); 345 } 346 setPreviewCallback(final PreviewCallback cb)347 public void setPreviewCallback(final PreviewCallback cb) { 348 mSig.close(); 349 mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK, cb).sendToTarget(); 350 mSig.block(); 351 } 352 setPreviewCallbackWithBuffer(final PreviewCallback cb)353 public void setPreviewCallbackWithBuffer(final PreviewCallback cb) { 354 mSig.close(); 355 mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK_WITH_BUFFER, cb).sendToTarget(); 356 mSig.block(); 357 } 358 addCallbackBuffer(byte[] callbackBuffer)359 public void addCallbackBuffer(byte[] callbackBuffer) { 360 mSig.close(); 361 mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget(); 362 mSig.block(); 363 } 364 autoFocus(AutoFocusCallback cb)365 public void autoFocus(AutoFocusCallback cb) { 366 mSig.close(); 367 mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget(); 368 mSig.block(); 369 } 370 cancelAutoFocus()371 public void cancelAutoFocus() { 372 mSig.close(); 373 mCameraHandler.sendEmptyMessage(CANCEL_AUTO_FOCUS); 374 mSig.block(); 375 } 376 377 @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) setAutoFocusMoveCallback(AutoFocusMoveCallback cb)378 public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) { 379 mSig.close(); 380 mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget(); 381 mSig.block(); 382 } 383 takePicture(final ShutterCallback shutter, final PictureCallback raw, final PictureCallback postview, final PictureCallback jpeg)384 public void takePicture(final ShutterCallback shutter, final PictureCallback raw, 385 final PictureCallback postview, final PictureCallback jpeg) { 386 mSig.close(); 387 // Too many parameters, so use post for simplicity 388 mCameraHandler.post(new Runnable() { 389 @Override 390 public void run() { 391 mCamera.takePicture(shutter, raw, postview, jpeg); 392 mSig.open(); 393 } 394 }); 395 mSig.block(); 396 } 397 takePicture2(final ShutterCallback shutter, final PictureCallback raw, final PictureCallback postview, final PictureCallback jpeg, final int cameraState, final int focusState)398 public void takePicture2(final ShutterCallback shutter, final PictureCallback raw, 399 final PictureCallback postview, final PictureCallback jpeg, 400 final int cameraState, final int focusState) { 401 mSig.close(); 402 // Too many parameters, so use post for simplicity 403 mCameraHandler.post(new Runnable() { 404 @Override 405 public void run() { 406 try { 407 mCamera.takePicture(shutter, raw, postview, jpeg); 408 } catch (RuntimeException e) { 409 Log.w(TAG, "take picture failed; cameraState:" + cameraState 410 + ", focusState:" + focusState); 411 throw e; 412 } 413 mSig.open(); 414 } 415 }); 416 mSig.block(); 417 } 418 setDisplayOrientation(int degrees)419 public void setDisplayOrientation(int degrees) { 420 mSig.close(); 421 mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0) 422 .sendToTarget(); 423 mSig.block(); 424 } 425 setZoomChangeListener(OnZoomChangeListener listener)426 public void setZoomChangeListener(OnZoomChangeListener listener) { 427 mSig.close(); 428 mCameraHandler.obtainMessage(SET_ZOOM_CHANGE_LISTENER, listener).sendToTarget(); 429 mSig.block(); 430 } 431 432 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) setFaceDetectionListener(FaceDetectionListener listener)433 public void setFaceDetectionListener(FaceDetectionListener listener) { 434 mSig.close(); 435 mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget(); 436 mSig.block(); 437 } 438 startFaceDetection()439 public void startFaceDetection() { 440 mSig.close(); 441 mCameraHandler.sendEmptyMessage(START_FACE_DETECTION); 442 mSig.block(); 443 } 444 stopFaceDetection()445 public void stopFaceDetection() { 446 mSig.close(); 447 mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION); 448 mSig.block(); 449 } 450 setErrorCallback(ErrorCallback cb)451 public void setErrorCallback(ErrorCallback cb) { 452 mSig.close(); 453 mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget(); 454 mSig.block(); 455 } 456 setParameters(Parameters params)457 public void setParameters(Parameters params) { 458 mSig.close(); 459 mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget(); 460 mSig.block(); 461 } 462 setParametersAsync(Parameters params)463 public void setParametersAsync(Parameters params) { 464 mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC); 465 mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget(); 466 } 467 getParameters()468 public Parameters getParameters() { 469 mSig.close(); 470 mCameraHandler.sendEmptyMessage(GET_PARAMETERS); 471 mSig.block(); 472 Parameters parameters = mParameters; 473 mParameters = null; 474 return parameters; 475 } 476 enableShutterSound(boolean enable)477 public void enableShutterSound(boolean enable) { 478 mSig.close(); 479 mCameraHandler.obtainMessage( 480 ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget(); 481 mSig.block(); 482 } 483 waitForIdle()484 public void waitForIdle() { 485 mSig.close(); 486 mCameraHandler.sendEmptyMessage(WAIT_FOR_IDLE); 487 mSig.block(); 488 } 489 } 490 } 491