1 /* 2 * Copyright (C) 2015 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.device; 18 19 import android.annotation.TargetApi; 20 import android.hardware.camera2.CameraAccessException; 21 import android.hardware.camera2.CameraDevice; 22 import android.hardware.camera2.CameraManager; 23 import android.os.Build.VERSION_CODES; 24 import android.os.Handler; 25 26 import com.android.camera.async.HandlerFactory; 27 import com.android.camera.async.Lifetime; 28 import com.android.camera.debug.Log.Tag; 29 import com.android.camera.debug.Logger; 30 31 import java.util.concurrent.Executor; 32 33 import javax.annotation.ParametersAreNonnullByDefault; 34 35 /** 36 * Set of device actions for opening and closing a single Camera2 device. 37 */ 38 @TargetApi(VERSION_CODES.LOLLIPOP) 39 @ParametersAreNonnullByDefault 40 public class Camera2Actions implements SingleDeviceActions<CameraDevice> { 41 private static final Tag TAG = new Tag("Camera2Act"); 42 43 private final CameraDeviceKey mId; 44 private final CameraManager mCameraManager; 45 private final HandlerFactory mHandlerFactory; 46 private final Executor mBackgroundExecutor; 47 private final Logger mLogger; 48 Camera2Actions(CameraDeviceKey id, CameraManager cameraManager, Executor backgroundExecutor, HandlerFactory handlerFactory, Logger.Factory logFactory)49 public Camera2Actions(CameraDeviceKey id, 50 CameraManager cameraManager, 51 Executor backgroundExecutor, 52 HandlerFactory handlerFactory, 53 Logger.Factory logFactory) { 54 mId = id; 55 mCameraManager = cameraManager; 56 mBackgroundExecutor = backgroundExecutor; 57 mHandlerFactory = handlerFactory; 58 mLogger = logFactory.create(TAG); 59 mLogger.d("Created Camera2Request"); 60 } 61 62 @Override executeOpen(SingleDeviceOpenListener<CameraDevice> openListener, Lifetime deviceLifetime)63 public void executeOpen(SingleDeviceOpenListener<CameraDevice> openListener, 64 Lifetime deviceLifetime) throws UnsupportedOperationException { 65 mLogger.i("executeOpen(id: " + mId.getCameraId() + ")"); 66 mBackgroundExecutor.execute(new OpenCameraRunnable(mCameraManager, 67 mId.getCameraId().getValue(), 68 // TODO THIS IS BAD. If there are multiple requests to open, 69 // we don't want to add the handler to the lifetime until after 70 // the camera device is opened or the camera could be opened with 71 // an invalid thread. 72 mHandlerFactory.create(deviceLifetime, "Camera2 Lifetime"), 73 openListener, mLogger)); 74 } 75 76 @Override executeClose(SingleDeviceCloseListener closeListener, CameraDevice device)77 public void executeClose(SingleDeviceCloseListener closeListener, CameraDevice device) 78 throws UnsupportedOperationException { 79 mLogger.i("executeClose(" + device.getId() + ")"); 80 mBackgroundExecutor.execute(new CloseCameraRunnable(device, closeListener, mLogger)); 81 } 82 83 /** 84 * Internal runnable that executes a CameraManager openCamera call. 85 */ 86 private static class OpenCameraRunnable implements Runnable { 87 private final SingleDeviceOpenListener<CameraDevice> mOpenListener; 88 private final String mCameraId; 89 private final Handler mHandler; 90 private final CameraManager mCameraManager; 91 private final Logger mLogger; 92 OpenCameraRunnable(CameraManager cameraManager, String cameraId, Handler handler, SingleDeviceOpenListener<CameraDevice> openListener, Logger logger)93 public OpenCameraRunnable(CameraManager cameraManager, String cameraId, 94 Handler handler, SingleDeviceOpenListener<CameraDevice> openListener, 95 Logger logger) { 96 mCameraManager = cameraManager; 97 mCameraId = cameraId; 98 mHandler = handler; 99 mOpenListener = openListener; 100 mLogger = logger; 101 } 102 103 @Override run()104 public void run() { 105 try { 106 mLogger.i("mCameraManager.openCamera(id: " + mCameraId + ")"); 107 mCameraManager.openCamera(mCameraId, new OpenCameraStateCallback(mOpenListener, 108 mLogger), mHandler); 109 } catch (CameraAccessException | SecurityException | IllegalArgumentException e) { 110 mLogger.e("There was a problem opening camera " + mCameraId, e); 111 mOpenListener.onDeviceOpenException(e); 112 } 113 } 114 } 115 116 /** 117 * Internal runnable that executes a close on a cameraDevice. 118 */ 119 private static class CloseCameraRunnable implements Runnable { 120 private final SingleDeviceCloseListener mCloseListener; 121 private final CameraDevice mCameraDevice; 122 private final Logger mLogger; 123 CloseCameraRunnable(CameraDevice cameraDevice, SingleDeviceCloseListener closeListener, Logger logger)124 public CloseCameraRunnable(CameraDevice cameraDevice, 125 SingleDeviceCloseListener closeListener, 126 Logger logger) { 127 mCameraDevice = cameraDevice; 128 mCloseListener = closeListener; 129 mLogger = logger; 130 } 131 132 @Override run()133 public void run() { 134 try { 135 mLogger.i("mCameraDevice.close(id: " + mCameraDevice.getId() + ")"); 136 mCameraDevice.close(); 137 mCloseListener.onDeviceClosed(); 138 } catch (Exception e) { 139 mLogger.e("Closing the camera produced an exception!", e); 140 mCloseListener.onDeviceClosingException(e); 141 } 142 } 143 } 144 145 /** 146 * Internal callback that provides a camera device to a future. 147 */ 148 private static class OpenCameraStateCallback extends CameraDevice.StateCallback { 149 private final SingleDeviceOpenListener<CameraDevice> mOpenListener; 150 private final Logger mLogger; 151 private boolean mHasBeenCalled = false; 152 OpenCameraStateCallback(SingleDeviceOpenListener<CameraDevice> openListener, Logger logger)153 public OpenCameraStateCallback(SingleDeviceOpenListener<CameraDevice> openListener, 154 Logger logger) { 155 mOpenListener = openListener; 156 mLogger = logger; 157 } 158 159 @Override onOpened(CameraDevice cameraDevice)160 public void onOpened(CameraDevice cameraDevice) { 161 if (!called()) { 162 mLogger.i("onOpened(id: " + cameraDevice.getId() + ")"); 163 mOpenListener.onDeviceOpened(cameraDevice); 164 } 165 } 166 167 @Override onClosed(CameraDevice cameraDevice)168 public void onClosed(CameraDevice cameraDevice) { 169 if (!called()) { 170 mLogger.w("onClosed(id: " + cameraDevice.getId() + ")"); 171 mOpenListener.onDeviceOpenException(cameraDevice); 172 } 173 } 174 175 @Override onDisconnected(CameraDevice cameraDevice)176 public void onDisconnected(CameraDevice cameraDevice) { 177 if (!called()) { 178 mLogger.w("onDisconnected(id: " + cameraDevice.getId() + ")"); 179 mOpenListener.onDeviceOpenException(cameraDevice); 180 } 181 } 182 183 @Override onError(CameraDevice cameraDevice, int errorId)184 public void onError(CameraDevice cameraDevice, int errorId) { 185 if (!called()) { 186 mLogger.e("onError(id: " + cameraDevice.getId() 187 + ", errorId: " + errorId + ")"); 188 mOpenListener.onDeviceOpenException(new CameraOpenException(errorId)); 189 } 190 } 191 called()192 private boolean called() { 193 boolean result = mHasBeenCalled; 194 if (!mHasBeenCalled) { 195 mHasBeenCalled = true; 196 } else { 197 mLogger.v("Callback was re-executed."); 198 } 199 200 return result; 201 } 202 } 203 } 204