CameraController.java revision 395bc17b71d13d97b3fd9f258fcf4d5748e66e5e
1/* 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.app; 18 19import android.content.Context; 20import android.hardware.Camera; 21import android.os.Handler; 22 23import com.android.camera.CameraDisabledException; 24import com.android.camera.debug.Log; 25import com.android.camera.util.CameraUtil; 26import com.android.ex.camera2.portability.CameraDeviceInfo; 27import com.android.ex.camera2.portability.CameraAgent; 28import com.android.ex.camera2.portability.CameraAgent.CameraExceptionCallback; 29 30/** 31 * A class which implements {@link com.android.camera.app.CameraProvider} used 32 * by {@link com.android.camera.CameraActivity}. 33 * TODO: Make this class package private. 34 */ 35public class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider { 36 private static final Log.Tag TAG = new Log.Tag("CameraController"); 37 private static final int EMPTY_REQUEST = -1; 38 private final Context mContext; 39 private CameraAgent.CameraOpenCallback mCallbackReceiver; 40 private final Handler mCallbackHandler; 41 private final CameraAgent mCameraAgent; 42 private final CameraAgent mCameraAgentNg; 43 44 /** The one for the API that is currently in use (deprecated one by default). */ 45 private CameraDeviceInfo mInfo; 46 47 private CameraAgent.CameraProxy mCameraProxy; 48 private int mRequestingCameraId = EMPTY_REQUEST; 49 50 /** 51 * Determines which of mCameraAgent and mCameraAgentNg is currently in use. 52 * <p>It's only possible to enable this if the new API is actually 53 * supported.</p> 54 */ 55 private boolean mUsingNewApi = false; 56 57 /** 58 * Constructor. 59 * 60 * @param context The {@link android.content.Context} used to check if the 61 * camera is disabled. 62 * @param handler The {@link android.os.Handler} to post the camera 63 * callbacks to. 64 * @param cameraManager Used for camera open/close. 65 * @param cameraManagerNg Used for camera open/close with the new API. If 66 * {@code null} or the same object as 67 * {@code cameraManager}, the new API will not be 68 * exposed and requests for it will get the old one. 69 */ 70 public CameraController(Context context, CameraAgent.CameraOpenCallback callbackReceiver, 71 Handler handler, CameraAgent cameraManager, CameraAgent cameraManagerNg) { 72 mContext = context; 73 mCallbackReceiver = callbackReceiver; 74 mCallbackHandler = handler; 75 mCameraAgent = cameraManager; 76 // If the new implementation is the same as the old, the 77 // CameraAgentFactory decided this device doesn't support the new API. 78 mCameraAgentNg = cameraManagerNg != cameraManager ? cameraManagerNg : null; 79 mInfo = mCameraAgent.getCameraDeviceInfo(); 80 if (mInfo == null && mCallbackReceiver != null) { 81 mCallbackReceiver.onDeviceOpenFailure(-1, "GETTING_CAMERA_INFO"); 82 } 83 } 84 85 @Override 86 public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback, 87 Handler handler) { 88 mCameraAgent.setCameraDefaultExceptionCallback(callback, handler); 89 if (mCameraAgentNg != null) { 90 mCameraAgentNg.setCameraDefaultExceptionCallback(callback, handler); 91 } 92 } 93 94 @Override 95 public CameraDeviceInfo.Characteristics getCharacteristics(int cameraId) { 96 if (mInfo == null) { 97 return null; 98 } 99 return mInfo.getCharacteristics(cameraId); 100 } 101 102 @Override 103 public int getCurrentCameraId() { 104 if (mCameraProxy != null) { 105 return mCameraProxy.getCameraId(); 106 } else { 107 Log.v(TAG, "getCurrentCameraId without an open camera... returning requested id"); 108 return mRequestingCameraId; 109 } 110 } 111 112 @Override 113 public int getNumberOfCameras() { 114 if (mInfo == null) { 115 return 0; 116 } 117 return mInfo.getNumberOfCameras(); 118 } 119 120 @Override 121 public int getFirstBackCameraId() { 122 if (mInfo == null) { 123 return -1; 124 } 125 return mInfo.getFirstBackCameraId(); 126 } 127 128 @Override 129 public int getFirstFrontCameraId() { 130 if (mInfo == null) { 131 return -1; 132 } 133 return mInfo.getFirstFrontCameraId(); 134 } 135 136 @Override 137 public boolean isFrontFacingCamera(int id) { 138 if (mInfo == null) { 139 return false; 140 } 141 if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) { 142 Log.e(TAG, "Camera info not available:" + id); 143 return false; 144 } 145 return mInfo.getCharacteristics(id).isFacingFront(); 146 } 147 148 @Override 149 public boolean isBackFacingCamera(int id) { 150 if (mInfo == null) { 151 return false; 152 } 153 if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) { 154 Log.e(TAG, "Camera info not available:" + id); 155 return false; 156 } 157 return mInfo.getCharacteristics(id).isFacingBack(); 158 } 159 160 @Override 161 public void onCameraOpened(CameraAgent.CameraProxy camera) { 162 Log.v(TAG, "onCameraOpened"); 163 if (mRequestingCameraId != camera.getCameraId()) { 164 // Not requesting any camera or not waiting for this one. 165 return; 166 } 167 mCameraProxy = camera; 168 mRequestingCameraId = EMPTY_REQUEST; 169 if (mCallbackReceiver != null) { 170 mCallbackReceiver.onCameraOpened(camera); 171 } 172 } 173 174 @Override 175 public void onCameraDisabled(int cameraId) { 176 if (mCallbackReceiver != null) { 177 mCallbackReceiver.onCameraDisabled(cameraId); 178 } 179 } 180 181 @Override 182 public void onDeviceOpenFailure(int cameraId, String info) { 183 if (mCallbackReceiver != null) { 184 mCallbackReceiver.onDeviceOpenFailure(cameraId, info); 185 } 186 } 187 188 @Override 189 public void onDeviceOpenedAlready(int cameraId, String info) { 190 if (mCallbackReceiver != null) { 191 mCallbackReceiver.onDeviceOpenedAlready(cameraId, info); 192 } 193 } 194 195 @Override 196 public void onReconnectionFailure(CameraAgent mgr, String info) { 197 if (mCallbackReceiver != null) { 198 mCallbackReceiver.onReconnectionFailure(mgr, info); 199 } 200 } 201 202 @Override 203 public void requestCamera(int id) { 204 requestCamera(id, false); 205 } 206 207 @Override 208 public void requestCamera(int id, boolean useNewApi) { 209 // Based on 210 // (mRequestingCameraId == id, mRequestingCameraId == EMPTY_REQUEST), 211 // we have (T, T), (T, F), (F, T), (F, F). 212 // (T, T): implies id == EMPTY_REQUEST. We don't allow this to happen 213 // here. Return. 214 // (F, F): A previous request hasn't been fulfilled yet. Return. 215 // (T, F): Already requested the same camera. No-op. Return. 216 // (F, T): Nothing is going on. Continue. 217 if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) { 218 return; 219 } 220 if (mInfo == null) { 221 return; 222 } 223 mRequestingCameraId = id; 224 225 // Only actually use the new API if it's supported on this device. 226 useNewApi = mCameraAgentNg != null && useNewApi; 227 CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent; 228 229 if (mCameraProxy == null) { 230 // No camera yet. 231 checkAndOpenCamera(mContext, cameraManager, id, mCallbackHandler, this); 232 } else if (mCameraProxy.getCameraId() != id || mUsingNewApi != useNewApi) { 233 // Already has camera opened, and is switching cameras and/or APIs. 234 if (mUsingNewApi) { 235 mCameraAgentNg.closeCamera(mCameraProxy, true); 236 } else { 237 mCameraAgent.closeCamera(mCameraProxy, true); 238 } 239 checkAndOpenCamera(mContext, cameraManager, id, mCallbackHandler, this); 240 } else { 241 // The same camera, just do a reconnect. 242 Log.v(TAG, "reconnecting to use the existing camera"); 243 mCameraProxy.reconnect(mCallbackHandler, this); 244 mCameraProxy = null; 245 } 246 247 mUsingNewApi = useNewApi; 248 mInfo = cameraManager.getCameraDeviceInfo(); 249 } 250 251 @Override 252 public boolean waitingForCamera() { 253 return mRequestingCameraId != EMPTY_REQUEST; 254 } 255 256 @Override 257 public void releaseCamera(int id) { 258 if (mCameraProxy == null) { 259 if (mRequestingCameraId == EMPTY_REQUEST) { 260 // Camera not requested yet. 261 Log.w(TAG, "Trying to release the camera before requesting"); 262 } 263 // Camera requested but not available yet. 264 mRequestingCameraId = EMPTY_REQUEST; 265 return; 266 } 267 if (mCameraProxy.getCameraId() != id) { 268 throw new IllegalStateException("Trying to release an unopened camera."); 269 } 270 mRequestingCameraId = EMPTY_REQUEST; 271 } 272 273 public void removeCallbackReceiver() { 274 mCallbackReceiver = null; 275 } 276 277 /** 278 * Closes the opened camera device. 279 * TODO: Make this method package private. 280 */ 281 public void closeCamera(boolean synced) { 282 if (mCameraProxy == null) { 283 Log.v(TAG, "No camera open, not closing"); 284 return; 285 } 286 Log.v(TAG, "Closing camera"); 287 mCameraProxy = null; 288 if (mUsingNewApi) { 289 mCameraAgentNg.closeCamera(mCameraProxy, synced); 290 } else { 291 mCameraAgent.closeCamera(mCameraProxy, synced); 292 } 293 mRequestingCameraId = EMPTY_REQUEST; 294 mUsingNewApi = false; 295 } 296 297 private static void checkAndOpenCamera(Context context, CameraAgent cameraManager, 298 final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) { 299 try { 300 CameraUtil.throwIfCameraDisabled(context); 301 cameraManager.openCamera(handler, cameraId, cb); 302 } catch (CameraDisabledException ex) { 303 handler.post(new Runnable() { 304 @Override 305 public void run() { 306 cb.onCameraDisabled(cameraId); 307 } 308 }); 309 } 310 } 311 312 public void setOneShotPreviewCallback(Handler handler, 313 CameraAgent.CameraPreviewDataCallback cb) { 314 mCameraProxy.setOneShotPreviewCallback(handler, cb); 315 } 316} 317