1 /* 2 * Copyright (C) 2014 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.one.v2; 18 19 import android.annotation.TargetApi; 20 import android.content.Context; 21 import android.hardware.camera2.CameraAccessException; 22 import android.hardware.camera2.CameraCharacteristics; 23 import android.hardware.camera2.CameraDevice; 24 import android.hardware.camera2.CameraManager; 25 import android.os.Build; 26 import android.os.Handler; 27 import android.util.DisplayMetrics; 28 29 import com.android.camera.FatalErrorHandler; 30 import com.android.camera.SoundPlayer; 31 import com.android.camera.async.MainThread; 32 import com.android.camera.burst.BurstFacade; 33 import com.android.camera.debug.Log; 34 import com.android.camera.debug.Log.Tag; 35 import com.android.camera.device.ActiveCameraDeviceTracker; 36 import com.android.camera.device.CameraId; 37 import com.android.camera.one.OneCamera; 38 import com.android.camera.one.OneCamera.OpenCallback; 39 import com.android.camera.one.OneCameraAccessException; 40 import com.android.camera.one.OneCameraCaptureSetting; 41 import com.android.camera.one.OneCameraOpener; 42 import com.android.camera.one.config.OneCameraFeatureConfig; 43 import com.android.camera.one.v2.photo.ImageRotationCalculator; 44 import com.android.camera.util.AndroidServices; 45 import com.android.camera.util.ApiHelper; 46 import com.google.common.base.Optional; 47 48 /** 49 * The {@link com.android.camera.one.OneCameraOpener} implementation on top of Camera2 API. 50 */ 51 @TargetApi(Build.VERSION_CODES.LOLLIPOP) 52 public class Camera2OneCameraOpenerImpl implements OneCameraOpener { 53 private static final Tag TAG = new Tag("OneCamera1Opnr"); 54 55 private final Context mContext; 56 private final OneCameraFeatureConfig mFeatureConfig; 57 private final ActiveCameraDeviceTracker mActiveCameraDeviceTracker; 58 private final CameraManager mCameraManager; 59 private final DisplayMetrics mDisplayMetrics; 60 create( OneCameraFeatureConfig featureConfig, Context context, ActiveCameraDeviceTracker activeCameraDeviceTracker, DisplayMetrics displayMetrics)61 public static Optional<OneCameraOpener> create( 62 OneCameraFeatureConfig featureConfig, 63 Context context, 64 ActiveCameraDeviceTracker activeCameraDeviceTracker, 65 DisplayMetrics displayMetrics) { 66 if (!ApiHelper.HAS_CAMERA_2_API) { 67 return Optional.absent(); 68 } 69 CameraManager cameraManager; 70 try { 71 cameraManager = AndroidServices.instance().provideCameraManager(); 72 } catch (IllegalStateException ex) { 73 Log.e(TAG, "camera2.CameraManager is not available."); 74 return Optional.absent(); 75 } 76 OneCameraOpener oneCameraOpener = new Camera2OneCameraOpenerImpl( 77 featureConfig, 78 context, 79 cameraManager, 80 activeCameraDeviceTracker, 81 displayMetrics); 82 return Optional.of(oneCameraOpener); 83 } 84 85 /** 86 * Instantiates a new {@link com.android.camera.one.OneCameraOpener} for Camera2 API. 87 * 88 * @param cameraManager the underlying Camera2 camera manager. 89 */ Camera2OneCameraOpenerImpl(OneCameraFeatureConfig featureConfig, Context context, CameraManager cameraManager, ActiveCameraDeviceTracker activeCameraDeviceTracker, DisplayMetrics displayMetrics)90 public Camera2OneCameraOpenerImpl(OneCameraFeatureConfig featureConfig, 91 Context context, 92 CameraManager cameraManager, 93 ActiveCameraDeviceTracker activeCameraDeviceTracker, 94 DisplayMetrics displayMetrics) { 95 mFeatureConfig = featureConfig; 96 mContext = context; 97 mCameraManager = cameraManager; 98 mActiveCameraDeviceTracker = activeCameraDeviceTracker; 99 mDisplayMetrics = displayMetrics; 100 } 101 102 @Override open( final CameraId cameraKey, final OneCameraCaptureSetting captureSetting, final Handler handler, final MainThread mainThread, final ImageRotationCalculator imageRotationCalculator, final BurstFacade burstController, final SoundPlayer soundPlayer, final OpenCallback openCallback, final FatalErrorHandler fatalErrorHandler)103 public void open( 104 final CameraId cameraKey, 105 final OneCameraCaptureSetting captureSetting, 106 final Handler handler, 107 final MainThread mainThread, 108 final ImageRotationCalculator imageRotationCalculator, 109 final BurstFacade burstController, 110 final SoundPlayer soundPlayer, 111 final OpenCallback openCallback, 112 final FatalErrorHandler fatalErrorHandler) { 113 try { 114 Log.i(TAG, "Opening Camera: " + cameraKey); 115 116 mActiveCameraDeviceTracker.onCameraOpening(cameraKey); 117 118 mCameraManager.openCamera(cameraKey.getValue(), new CameraDevice.StateCallback() { 119 // We may get multiple calls to StateCallback, but only the 120 // first callback indicates the status of the camera-opening 121 // operation. For example, we may receive onOpened() and later 122 // onClosed(), but only the first should be relayed to 123 // openCallback. 124 private boolean isFirstCallback = true; 125 126 @Override 127 public void onDisconnected(CameraDevice device) { 128 if (isFirstCallback) { 129 isFirstCallback = false; 130 // If the camera is disconnected before it is opened 131 // then we must call close. 132 device.close(); 133 openCallback.onCameraClosed(); 134 } else { 135 // Disconnected during active session 136 openCallback.onCameraInterrupted(); 137 } 138 } 139 140 @Override 141 public void onClosed(CameraDevice device) { 142 if (isFirstCallback) { 143 isFirstCallback = false; 144 openCallback.onCameraClosed(); 145 } 146 } 147 148 @Override 149 public void onError(CameraDevice device, int error) { 150 if (error == CameraDevice.StateCallback.ERROR_CAMERA_IN_USE) { 151 // Tolerate ERROR_CAMERA_IN_USE for split-screen. 152 isFirstCallback = false; 153 device.close(); 154 openCallback.onCameraInUse(); 155 } else if (isFirstCallback) { 156 isFirstCallback = false; 157 device.close(); 158 openCallback.onFailure(); 159 } else { 160 // Ensures we handle the case where an error occurs 161 // after the camera has been opened. 162 fatalErrorHandler.onGenericCameraAccessFailure(); 163 } 164 } 165 166 @Override 167 public void onOpened(CameraDevice device) { 168 if (isFirstCallback) { 169 isFirstCallback = false; 170 try { 171 CameraCharacteristics characteristics = mCameraManager 172 .getCameraCharacteristics(device.getId()); 173 // TODO: Set boolean based on whether HDR+ is 174 // enabled. 175 OneCamera oneCamera = OneCameraCreator.create( 176 device, 177 characteristics, 178 mFeatureConfig, 179 captureSetting, 180 mDisplayMetrics, 181 mContext, 182 mainThread, 183 imageRotationCalculator, 184 burstController, 185 soundPlayer, fatalErrorHandler); 186 187 if (oneCamera != null) { 188 openCallback.onCameraOpened(oneCamera); 189 } else { 190 Log.d(TAG, "Could not construct a OneCamera object!"); 191 openCallback.onFailure(); 192 } 193 } catch (CameraAccessException e) { 194 Log.d(TAG, "Could not get camera characteristics", e); 195 openCallback.onFailure(); 196 } catch (OneCameraAccessException e) { 197 Log.d(TAG, "Could not create OneCamera", e); 198 openCallback.onFailure(); 199 } 200 } 201 } 202 }, handler); 203 } catch (CameraAccessException ex) { 204 Log.e(TAG, "Could not open camera. " + ex.getMessage()); 205 handler.post(new Runnable() { 206 @Override 207 public void run() { 208 if (ex.getReason() == CameraAccessException.CAMERA_IN_USE) { 209 openCallback.onCameraInUse(); 210 } else { 211 openCallback.onFailure(); 212 } 213 } 214 }); 215 } catch (UnsupportedOperationException ex) { 216 Log.e(TAG, "Could not open camera. " + ex.getMessage()); 217 handler.post(new Runnable() { 218 @Override 219 public void run() { 220 openCallback.onFailure(); 221 } 222 }); 223 } catch (SecurityException ex) { 224 fatalErrorHandler.onCameraDisabledFailure(); 225 } 226 } 227 } 228