1 /* 2 * Copyright 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.cts.verifier.sensors.sixdof.Renderer.RenderUtils; 18 19 import android.annotation.TargetApi; 20 import android.content.Context; 21 import android.content.pm.ActivityInfo; 22 import android.content.res.Configuration; 23 import android.content.res.Resources; 24 import android.graphics.SurfaceTexture; 25 import android.hardware.camera2.CameraAccessException; 26 import android.hardware.camera2.CameraCaptureSession; 27 import android.hardware.camera2.CameraCharacteristics; 28 import android.hardware.camera2.CameraDevice; 29 import android.hardware.camera2.CameraManager; 30 import android.hardware.camera2.CaptureRequest; 31 import android.hardware.camera2.CaptureResult; 32 import android.hardware.camera2.TotalCaptureResult; 33 import android.os.Handler; 34 import android.os.HandlerThread; 35 import android.util.Log; 36 import android.util.Size; 37 import android.view.Display; 38 import android.view.Surface; 39 import android.view.WindowManager; 40 41 import java.util.Arrays; 42 import java.util.concurrent.Semaphore; 43 import java.util.concurrent.TimeUnit; 44 45 @TargetApi(21) 46 public class CameraStreamManager { 47 48 private Context mContext; 49 private SurfaceTexture mSurfaceTextureToStreamTo; 50 private int mWidth; 51 private int mHeight; 52 53 /** 54 * Tag for the {@link Log}. 55 */ 56 private static final String TAG = "Camera2BasicFragment"; 57 58 /** 59 * ID of the current {@link CameraDevice}. 60 */ 61 private static final String CAMERA_ID = "0"; 62 63 /** 64 * A {@link CameraCaptureSession } for camera preview. 65 */ 66 private CameraCaptureSession mCaptureSession; 67 68 /** 69 * A reference to the opened {@link CameraDevice}. 70 */ 71 private CameraDevice mCameraDevice; 72 73 /** 74 * The {@link android.util.Size} of camera preview. 75 */ 76 private Size mPreviewSize; 77 78 /** 79 * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state. 80 */ 81 private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { 82 83 @Override 84 public void onOpened(CameraDevice cameraDevice) { 85 // This method is called when the camera is opened. We start camera preview here. 86 mCameraOpenCloseLock.release(); 87 mCameraDevice = cameraDevice; 88 createCameraPreviewSession(); 89 } 90 91 @Override 92 public void onDisconnected(CameraDevice cameraDevice) { 93 mCameraOpenCloseLock.release(); 94 cameraDevice.close(); 95 mCameraDevice = null; 96 } 97 98 @Override 99 public void onError(CameraDevice cameraDevice, int error) { 100 mCameraOpenCloseLock.release(); 101 cameraDevice.close(); 102 mCameraDevice = null; 103 Log.e(TAG, "onError " + error); 104 } 105 106 }; 107 108 /** 109 * An additional thread for running tasks that shouldn't block the UI. 110 */ 111 private HandlerThread mBackgroundThread; 112 113 /** 114 * A {@link Handler} for running tasks in the background. 115 */ 116 private Handler mBackgroundHandler; 117 118 /** 119 * {@link CaptureRequest.Builder} for the camera preview 120 */ 121 private CaptureRequest.Builder mPreviewRequestBuilder; 122 123 /** 124 * {@link CaptureRequest} generated by {@link #mPreviewRequestBuilder} 125 */ 126 private CaptureRequest mPreviewRequest; 127 128 /** 129 * A {@link Semaphore} to prevent the app from exiting before closing the camera. 130 */ 131 private Semaphore mCameraOpenCloseLock = new Semaphore(1); 132 133 /** 134 * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture. 135 */ 136 /** 137 * A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture. 138 */ 139 private CameraCaptureSession.CaptureCallback mCaptureCallback 140 = new CameraCaptureSession.CaptureCallback() { 141 142 @Override 143 public void onCaptureProgressed(CameraCaptureSession session, 144 CaptureRequest request, 145 CaptureResult partialResult) { 146 // Don't need to do anything here. 147 } 148 149 @Override 150 public void onCaptureCompleted(CameraCaptureSession session, 151 CaptureRequest request, 152 TotalCaptureResult result) { 153 // Don't need to do anything here. 154 } 155 156 }; 157 CameraStreamManager(Context context, SurfaceTexture textureToStreamTo, int width, int height)158 public CameraStreamManager(Context context, SurfaceTexture textureToStreamTo, 159 int width, int height) { 160 mContext = context; 161 mSurfaceTextureToStreamTo = textureToStreamTo; 162 mWidth = width; 163 mHeight = height; 164 } 165 onStartCameraStream()166 public void onStartCameraStream() { 167 startBackgroundThread(); 168 openCamera(mWidth, mHeight); 169 } 170 onStopCameraStream()171 public void onStopCameraStream() { 172 closeCamera(); 173 stopBackgroundThread(); 174 } 175 176 /** 177 * Sets up member variables related to camera. 178 * 179 * @param width The width of available size for camera preview 180 * @param height The height of available size for camera preview 181 */ setUpCameraOutputs(int width, int height)182 private void setUpCameraOutputs(int width, int height) { 183 // Danger, W.R.! Attempting to use too large a preview size could exceed the camera 184 // bus' bandwidth limitation, resulting in gorgeous previews but the storage of 185 // garbage capture data. 186 mPreviewSize = new Size(width, height); 187 } 188 189 /** 190 * Opens the camera specified by {@link CameraStreamManager#CAMERA_ID}. 191 */ openCamera(int width, int height)192 private void openCamera(int width, int height) { 193 setUpCameraOutputs(width, height); 194 CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE); 195 try { 196 if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { 197 throw new RuntimeException("Time out waiting to lock camera opening."); 198 } 199 manager.openCamera(CAMERA_ID, mStateCallback, mBackgroundHandler); 200 } catch (CameraAccessException e) { 201 e.printStackTrace(); 202 } catch (InterruptedException e) { 203 throw new RuntimeException("Interrupted while trying to lock camera opening.", e); 204 } 205 } 206 207 /** 208 * Closes the current {@link CameraDevice}. 209 */ closeCamera()210 private void closeCamera() { 211 try { 212 mCameraOpenCloseLock.acquire(); 213 if (null != mCaptureSession) { 214 mCaptureSession.close(); 215 mCaptureSession = null; 216 } 217 if (null != mCameraDevice) { 218 mCameraDevice.close(); 219 mCameraDevice = null; 220 } 221 } catch (InterruptedException e) { 222 throw new RuntimeException("Interrupted while trying to lock camera closing.", e); 223 } finally { 224 mCameraOpenCloseLock.release(); 225 } 226 } 227 228 /** 229 * Starts a background thread and its {@link Handler}. 230 */ startBackgroundThread()231 private void startBackgroundThread() { 232 mBackgroundThread = new HandlerThread("CameraBackground"); 233 mBackgroundThread.start(); 234 mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); 235 } 236 237 /** 238 * Stops the background thread and its {@link Handler}. 239 */ stopBackgroundThread()240 private void stopBackgroundThread() { 241 if (mBackgroundThread != null) { 242 mBackgroundThread.quitSafely(); 243 try { 244 mBackgroundThread.join(); 245 mBackgroundThread = null; 246 mBackgroundHandler = null; 247 } catch (InterruptedException e) { 248 e.printStackTrace(); 249 } 250 } 251 } 252 253 /** 254 * Creates a new {@link CameraCaptureSession} for camera preview. 255 */ createCameraPreviewSession()256 private void createCameraPreviewSession() { 257 try { 258 assert mSurfaceTextureToStreamTo != null; 259 260 // We configure the size of default buffer to be the size of camera preview we want. 261 mSurfaceTextureToStreamTo.setDefaultBufferSize(mPreviewSize.getWidth(), 262 mPreviewSize.getHeight()); 263 264 // This is the output Surface we need to start preview. 265 Surface surface = new Surface(mSurfaceTextureToStreamTo); 266 267 // We set up a CaptureRequest.Builder with the output Surface. 268 mPreviewRequestBuilder 269 = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 270 mPreviewRequestBuilder.addTarget(surface); 271 272 // Here, we create a CameraCaptureSession for camera preview. 273 mCameraDevice.createCaptureSession(Arrays.asList(surface), 274 new CameraCaptureSession.StateCallback() { 275 276 @Override 277 public void onConfigured(CameraCaptureSession cameraCaptureSession) { 278 // The camera is already closed. 279 if (null == mCameraDevice) { 280 return; 281 } 282 283 // When the session is ready, we start displaying the preview. 284 mCaptureSession = cameraCaptureSession; 285 try { 286 // Auto focus should be continuous for camera preview. 287 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, 288 CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); 289 290 // Finally, we start displaying the camera preview. 291 mPreviewRequest = mPreviewRequestBuilder.build(); 292 mCaptureSession.setRepeatingRequest(mPreviewRequest, 293 mCaptureCallback, mBackgroundHandler); 294 } catch (CameraAccessException e) { 295 e.printStackTrace(); 296 } 297 } 298 299 @Override 300 public void onConfigureFailed( 301 CameraCaptureSession cameraCaptureSession) { 302 Log.e(TAG, "Camera configuration failed."); 303 } 304 }, null 305 ); 306 } catch (CameraAccessException e) { 307 e.printStackTrace(); 308 } 309 } 310 getRotation(Context context, int deviceRotation)311 public static int getRotation(Context context, int deviceRotation) { 312 // Get offset from the RGB camera. 313 CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 314 CameraCharacteristics characteristics = null; 315 try { 316 characteristics = manager.getCameraCharacteristics(CAMERA_ID + ""); 317 } catch (CameraAccessException e) { 318 e.printStackTrace(); 319 } 320 int toOrientate = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); 321 322 // Add RGB offset to current device rotation. 323 return toOrientate + deviceRotation; 324 } 325 } 326