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 84 public static CameraManager instance() { 85 return sCameraManager; 86 } 87 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 { 95 CameraHandler(Looper looper) { 96 super(looper); 97 } 98 99 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) 100 private void startFaceDetection() { 101 mCamera.startFaceDetection(); 102 } 103 104 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) 105 private void stopFaceDetection() { 106 mCamera.stopFaceDetection(); 107 } 108 109 @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) 110 private void setFaceDetectionListener(FaceDetectionListener listener) { 111 mCamera.setFaceDetectionListener(listener); 112 } 113 114 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 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) 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 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) 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. 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 { 293 private CameraProxy() { 294 Assert(mCamera != null); 295 } 296 297 public android.hardware.Camera getCamera() { 298 return mCamera; 299 } 300 301 public void release() { 302 mSig.close(); 303 mCameraHandler.sendEmptyMessage(RELEASE); 304 mSig.block(); 305 } 306 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 316 public void unlock() { 317 mSig.close(); 318 mCameraHandler.sendEmptyMessage(UNLOCK); 319 mSig.block(); 320 } 321 322 public void lock() { 323 mSig.close(); 324 mCameraHandler.sendEmptyMessage(LOCK); 325 mSig.block(); 326 } 327 328 @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 329 public void setPreviewTextureAsync(final SurfaceTexture surfaceTexture) { 330 mCameraHandler.obtainMessage(SET_PREVIEW_TEXTURE_ASYNC, surfaceTexture).sendToTarget(); 331 } 332 333 public void setPreviewDisplayAsync(final SurfaceHolder surfaceHolder) { 334 mCameraHandler.obtainMessage(SET_PREVIEW_DISPLAY_ASYNC, surfaceHolder).sendToTarget(); 335 } 336 337 public void startPreviewAsync() { 338 mCameraHandler.sendEmptyMessage(START_PREVIEW_ASYNC); 339 } 340 341 public void stopPreview() { 342 mSig.close(); 343 mCameraHandler.sendEmptyMessage(STOP_PREVIEW); 344 mSig.block(); 345 } 346 347 public void setPreviewCallback(final PreviewCallback cb) { 348 mSig.close(); 349 mCameraHandler.obtainMessage(SET_PREVIEW_CALLBACK, cb).sendToTarget(); 350 mSig.block(); 351 } 352 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 359 public void addCallbackBuffer(byte[] callbackBuffer) { 360 mSig.close(); 361 mCameraHandler.obtainMessage(ADD_CALLBACK_BUFFER, callbackBuffer).sendToTarget(); 362 mSig.block(); 363 } 364 365 public void autoFocus(AutoFocusCallback cb) { 366 mSig.close(); 367 mCameraHandler.obtainMessage(AUTO_FOCUS, cb).sendToTarget(); 368 mSig.block(); 369 } 370 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) 378 public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) { 379 mSig.close(); 380 mCameraHandler.obtainMessage(SET_AUTO_FOCUS_MOVE_CALLBACK, cb).sendToTarget(); 381 mSig.block(); 382 } 383 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 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 419 public void setDisplayOrientation(int degrees) { 420 mSig.close(); 421 mCameraHandler.obtainMessage(SET_DISPLAY_ORIENTATION, degrees, 0) 422 .sendToTarget(); 423 mSig.block(); 424 } 425 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) 433 public void setFaceDetectionListener(FaceDetectionListener listener) { 434 mSig.close(); 435 mCameraHandler.obtainMessage(SET_FACE_DETECTION_LISTENER, listener).sendToTarget(); 436 mSig.block(); 437 } 438 439 public void startFaceDetection() { 440 mSig.close(); 441 mCameraHandler.sendEmptyMessage(START_FACE_DETECTION); 442 mSig.block(); 443 } 444 445 public void stopFaceDetection() { 446 mSig.close(); 447 mCameraHandler.sendEmptyMessage(STOP_FACE_DETECTION); 448 mSig.block(); 449 } 450 451 public void setErrorCallback(ErrorCallback cb) { 452 mSig.close(); 453 mCameraHandler.obtainMessage(SET_ERROR_CALLBACK, cb).sendToTarget(); 454 mSig.block(); 455 } 456 457 public void setParameters(Parameters params) { 458 mSig.close(); 459 mCameraHandler.obtainMessage(SET_PARAMETERS, params).sendToTarget(); 460 mSig.block(); 461 } 462 463 public void setParametersAsync(Parameters params) { 464 mCameraHandler.removeMessages(SET_PARAMETERS_ASYNC); 465 mCameraHandler.obtainMessage(SET_PARAMETERS_ASYNC, params).sendToTarget(); 466 } 467 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 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 484 public void waitForIdle() { 485 mSig.close(); 486 mCameraHandler.sendEmptyMessage(WAIT_FOR_IDLE); 487 mSig.block(); 488 } 489 } 490 } 491