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