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