Home | History | Annotate | Download | only in RenderUtils
      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 
    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 
    166     public void onStartCameraStream() {
    167         startBackgroundThread();
    168         openCamera(mWidth, mHeight);
    169     }
    170 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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