Home | History | Annotate | Download | only in portability
      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.ex.camera2.portability;
     18 
     19 import android.annotation.TargetApi;
     20 import android.content.Context;
     21 import android.graphics.ImageFormat;
     22 import android.graphics.Matrix;
     23 import android.graphics.Rect;
     24 import android.graphics.RectF;
     25 import android.graphics.SurfaceTexture;
     26 import android.hardware.camera2.CameraAccessException;
     27 import android.hardware.camera2.CameraCaptureSession;
     28 import android.hardware.camera2.CameraCharacteristics;
     29 import android.hardware.camera2.CameraDevice;
     30 import android.hardware.camera2.CameraManager;
     31 import android.hardware.camera2.CaptureFailure;
     32 import android.hardware.camera2.CaptureRequest;
     33 import android.hardware.camera2.CaptureResult;
     34 import android.hardware.camera2.TotalCaptureResult;
     35 import android.hardware.camera2.params.MeteringRectangle;
     36 import android.media.Image;
     37 import android.media.ImageReader;
     38 import android.media.MediaActionSound;
     39 import android.os.Build;
     40 import android.os.Handler;
     41 import android.os.HandlerThread;
     42 import android.os.Looper;
     43 import android.os.Message;
     44 import android.view.Surface;
     45 
     46 import com.android.ex.camera2.portability.debug.Log;
     47 import com.android.ex.camera2.utils.Camera2RequestSettingsSet;
     48 
     49 import java.nio.ByteBuffer;
     50 import java.util.ArrayList;
     51 import java.util.Arrays;
     52 import java.util.HashSet;
     53 import java.util.List;
     54 import java.util.Set;
     55 
     56 /**
     57  * A class to implement {@link CameraAgent} of the Android camera2 framework.
     58  */
     59 class AndroidCamera2AgentImpl extends CameraAgent {
     60     private static final Log.Tag TAG = new Log.Tag("AndCam2AgntImp");
     61 
     62     private final Camera2Handler mCameraHandler;
     63     private final HandlerThread mCameraHandlerThread;
     64     private final CameraStateHolder mCameraState;
     65     private final DispatchThread mDispatchThread;
     66     private final CameraManager mCameraManager;
     67     private final MediaActionSound mNoisemaker;
     68     private CameraExceptionHandler mExceptionHandler;
     69 
     70     /**
     71      * Number of camera devices.  The length of {@code mCameraDevices} does not reveal this
     72      * information because that list may contain since-invalidated indices.
     73      */
     74     private int mNumCameraDevices;
     75 
     76     /**
     77      * Transformation between integral camera indices and the {@link java.lang.String} indices used
     78      * by the underlying API.  Note that devices may disappear because they've been disconnected or
     79      * have otherwise gone offline.  Because we need to keep the meanings of whatever indices we
     80      * expose stable, we cannot simply remove them in such a case; instead, we insert {@code null}s
     81      * to invalidate any such indices.  Whenever new devices appear, they are appended to the end of
     82      * the list, and thereby assigned the lowest index that has never yet been used.
     83      */
     84     private final List<String> mCameraDevices;
     85 
     86     AndroidCamera2AgentImpl(Context context) {
     87         mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread");
     88         mCameraHandlerThread.start();
     89         mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper());
     90         mExceptionHandler = new CameraExceptionHandler(mCameraHandler);
     91         mCameraState = new AndroidCamera2StateHolder();
     92         mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread);
     93         mDispatchThread.start();
     94         mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
     95         mNoisemaker = new MediaActionSound();
     96         mNoisemaker.load(MediaActionSound.SHUTTER_CLICK);
     97 
     98         mNumCameraDevices = 0;
     99         mCameraDevices = new ArrayList<String>();
    100         updateCameraDevices();
    101     }
    102 
    103     /**
    104      * Updates the camera device index assignments stored in {@link mCameraDevices}, without
    105      * reappropriating any currently-assigned index.
    106      * @return Whether the operation was successful
    107      */
    108     private boolean updateCameraDevices() {
    109         try {
    110             String[] currentCameraDevices = mCameraManager.getCameraIdList();
    111             Set<String> currentSet = new HashSet<String>(Arrays.asList(currentCameraDevices));
    112 
    113             // Invalidate the indices assigned to any camera devices that are no longer present
    114             for (int index = 0; index < mCameraDevices.size(); ++index) {
    115                 if (!currentSet.contains(mCameraDevices.get(index))) {
    116                     mCameraDevices.set(index, null);
    117                     --mNumCameraDevices;
    118                 }
    119             }
    120 
    121             // Assign fresh indices to any new camera devices
    122             currentSet.removeAll(mCameraDevices); // The devices we didn't know about
    123             for (String device : currentCameraDevices) {
    124                 if (currentSet.contains(device)) {
    125                     mCameraDevices.add(device);
    126                     ++mNumCameraDevices;
    127                 }
    128             }
    129 
    130             return true;
    131         } catch (CameraAccessException ex) {
    132             Log.e(TAG, "Could not get device listing from camera subsystem", ex);
    133             return false;
    134         }
    135     }
    136 
    137     // TODO: Implement
    138     @Override
    139     public void recycle() {}
    140 
    141     // TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs
    142     @Override
    143     public CameraDeviceInfo getCameraDeviceInfo() {
    144         updateCameraDevices();
    145         return new AndroidCamera2DeviceInfo(mCameraManager, mCameraDevices.toArray(new String[0]),
    146                 mNumCameraDevices);
    147     }
    148 
    149     @Override
    150     protected Handler getCameraHandler() {
    151         return mCameraHandler;
    152     }
    153 
    154     @Override
    155     protected DispatchThread getDispatchThread() {
    156         return mDispatchThread;
    157     }
    158 
    159     @Override
    160     protected CameraStateHolder getCameraState() {
    161         return mCameraState;
    162     }
    163 
    164     @Override
    165     protected CameraExceptionHandler getCameraExceptionHandler() {
    166         return mExceptionHandler;
    167     }
    168 
    169     @Override
    170     public void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler) {
    171         mExceptionHandler = exceptionHandler;
    172     }
    173 
    174     private static abstract class CaptureAvailableListener
    175             extends CameraCaptureSession.CaptureCallback
    176             implements ImageReader.OnImageAvailableListener {};
    177 
    178     private class Camera2Handler extends HistoryHandler {
    179         // Caller-provided when leaving CAMERA_UNOPENED state:
    180         private CameraOpenCallback mOpenCallback;
    181         private int mCameraIndex;
    182         private String mCameraId;
    183         private int mCancelAfPending = 0;
    184 
    185         // Available in CAMERA_UNCONFIGURED state and above:
    186         private CameraDevice mCamera;
    187         private AndroidCamera2ProxyImpl mCameraProxy;
    188         private Camera2RequestSettingsSet mPersistentSettings;
    189         private Rect mActiveArray;
    190         private boolean mLegacyDevice;
    191 
    192         // Available in CAMERA_CONFIGURED state and above:
    193         private Size mPreviewSize;
    194         private Size mPhotoSize;
    195 
    196         // Available in PREVIEW_READY state and above:
    197         private SurfaceTexture mPreviewTexture;
    198         private Surface mPreviewSurface;
    199         private CameraCaptureSession mSession;
    200         private ImageReader mCaptureReader;
    201 
    202         // Available from the beginning of PREVIEW_ACTIVE until the first preview frame arrives:
    203         private CameraStartPreviewCallback mOneshotPreviewingCallback;
    204 
    205         // Available in FOCUS_LOCKED between AF trigger receipt and whenever the lens stops moving:
    206         private CameraAFCallback mOneshotAfCallback;
    207 
    208         // Available when taking picture between AE trigger receipt and autoexposure convergence
    209         private CaptureAvailableListener mOneshotCaptureCallback;
    210 
    211         // Available whenever setAutoFocusMoveCallback() was last invoked with a non-null argument:
    212         private CameraAFMoveCallback mPassiveAfCallback;
    213 
    214         // Gets reset on every state change
    215         private int mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE;
    216 
    217         Camera2Handler(Looper looper) {
    218             super(looper);
    219         }
    220 
    221         @Override
    222         public void handleMessage(final Message msg) {
    223             super.handleMessage(msg);
    224             Log.v(TAG, "handleMessage - action = '" + CameraActions.stringify(msg.what) + "'");
    225             int cameraAction = msg.what;
    226             try {
    227                 switch (cameraAction) {
    228                     case CameraActions.OPEN_CAMERA:
    229                     case CameraActions.RECONNECT: {
    230                         CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
    231                         int cameraIndex = msg.arg1;
    232 
    233                         if (mCameraState.getState() > AndroidCamera2StateHolder.CAMERA_UNOPENED) {
    234                             openCallback.onDeviceOpenedAlready(cameraIndex,
    235                                     generateHistoryString(cameraIndex));
    236                             break;
    237                         }
    238 
    239                         mOpenCallback = openCallback;
    240                         mCameraIndex = cameraIndex;
    241                         mCameraId = mCameraDevices.get(mCameraIndex);
    242                         Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API",
    243                                 cameraIndex, mCameraId));
    244 
    245                         if (mCameraId == null) {
    246                             mOpenCallback.onCameraDisabled(msg.arg1);
    247                             break;
    248                         }
    249                         mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, this);
    250 
    251                         break;
    252                     }
    253 
    254                     case CameraActions.RELEASE: {
    255                         if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) {
    256                             Log.w(TAG, "Ignoring release at inappropriate time");
    257                             break;
    258                         }
    259 
    260                         if (mSession != null) {
    261                             closePreviewSession();
    262                             mSession = null;
    263                         }
    264                         if (mCamera != null) {
    265                             mCamera.close();
    266                             mCamera = null;
    267                         }
    268                         mCameraProxy = null;
    269                         mPersistentSettings = null;
    270                         mActiveArray = null;
    271                         if (mPreviewSurface != null) {
    272                             mPreviewSurface.release();
    273                             mPreviewSurface = null;
    274                         }
    275                         mPreviewTexture = null;
    276                         if (mCaptureReader != null) {
    277                             mCaptureReader.close();
    278                             mCaptureReader = null;
    279                         }
    280                         mPreviewSize = null;
    281                         mPhotoSize = null;
    282                         mCameraIndex = 0;
    283                         mCameraId = null;
    284                         changeState(AndroidCamera2StateHolder.CAMERA_UNOPENED);
    285                         break;
    286                     }
    287 
    288                     /*case CameraActions.UNLOCK: {
    289                         break;
    290                     }
    291 
    292                     case CameraActions.LOCK: {
    293                         break;
    294                     }*/
    295 
    296                     case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: {
    297                         setPreviewTexture((SurfaceTexture) msg.obj);
    298                         break;
    299                     }
    300 
    301                     case CameraActions.START_PREVIEW_ASYNC: {
    302                         if (mCameraState.getState() !=
    303                                         AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
    304                             // TODO: Provide better feedback here?
    305                             Log.w(TAG, "Refusing to start preview at inappropriate time");
    306                             break;
    307                         }
    308 
    309                         mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj;
    310                         changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
    311                         try {
    312                             mSession.setRepeatingRequest(
    313                                     mPersistentSettings.createRequest(mCamera,
    314                                             CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface),
    315                                     /*listener*/mCameraResultStateCallback, /*handler*/this);
    316                         } catch(CameraAccessException ex) {
    317                             Log.w(TAG, "Unable to start preview", ex);
    318                             changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
    319                         }
    320                         break;
    321                     }
    322 
    323                     // FIXME: We need to tear down the CameraCaptureSession here
    324                     // (and unlock the CameraSettings object from our
    325                     // CameraProxy) so that the preview/photo sizes can be
    326                     // changed again while no preview is running.
    327                     case CameraActions.STOP_PREVIEW: {
    328                         if (mCameraState.getState() <
    329                                         AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
    330                             Log.w(TAG, "Refusing to stop preview at inappropriate time");
    331                             break;
    332                         }
    333 
    334                         mSession.stopRepeating();
    335                         changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
    336                         break;
    337                     }
    338 
    339                     /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: {
    340                         break;
    341                     }
    342 
    343                     case CameraActions.ADD_CALLBACK_BUFFER: {
    344                         break;
    345                     }
    346 
    347                     case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: {
    348                         break;
    349                     }
    350 
    351                     case CameraActions.SET_PREVIEW_CALLBACK: {
    352                         break;
    353                     }
    354 
    355                     case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: {
    356                         break;
    357                     }
    358 
    359                     case CameraActions.SET_PARAMETERS: {
    360                         break;
    361                     }
    362 
    363                     case CameraActions.GET_PARAMETERS: {
    364                         break;
    365                     }
    366 
    367                     case CameraActions.REFRESH_PARAMETERS: {
    368                         break;
    369                     }*/
    370 
    371                     case CameraActions.APPLY_SETTINGS: {
    372                         AndroidCamera2Settings settings = (AndroidCamera2Settings) msg.obj;
    373                         applyToRequest(settings);
    374                         break;
    375                     }
    376 
    377                     case CameraActions.AUTO_FOCUS: {
    378                         if (mCancelAfPending > 0) {
    379                             Log.v(TAG, "handleMessage - Ignored AUTO_FOCUS because there was "
    380                                     + mCancelAfPending + " pending CANCEL_AUTO_FOCUS messages");
    381                             break; // ignore AF because a CANCEL_AF is queued after this
    382                         }
    383                         // We only support locking the focus while a preview is being displayed.
    384                         // However, it can be requested multiple times in succession; the effect of
    385                         // the subsequent invocations is determined by the focus mode defined in the
    386                         // provided CameraSettings object. In passive (CONTINUOUS_*) mode, the
    387                         // duplicate requests are no-ops and leave the lens locked at its current
    388                         // position, but in active (AUTO) mode, they perform another scan and lock
    389                         // once that is finished. In any manual focus mode, this call is a no-op,
    390                         // and most notably, this is the only case where the callback isn't invoked.
    391                         if (mCameraState.getState() <
    392                                         AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
    393                             Log.w(TAG, "Ignoring attempt to autofocus without preview");
    394                             break;
    395                         }
    396 
    397                         // The earliest we can reliably tell whether the autofocus has locked in
    398                         // response to our latest request is when our one-time capture progresses.
    399                         // However, it will probably take longer than that, so once that happens,
    400                         // just start checking the repeating preview requests as they complete.
    401                         final CameraAFCallback callback = (CameraAFCallback) msg.obj;
    402                         CameraCaptureSession.CaptureCallback deferredCallbackSetter =
    403                                 new CameraCaptureSession.CaptureCallback() {
    404                             private boolean mAlreadyDispatched = false;
    405 
    406                             @Override
    407                             public void onCaptureProgressed(CameraCaptureSession session,
    408                                                             CaptureRequest request,
    409                                                             CaptureResult result) {
    410                                 checkAfState(result);
    411                             }
    412 
    413                             @Override
    414                             public void onCaptureCompleted(CameraCaptureSession session,
    415                                                            CaptureRequest request,
    416                                                            TotalCaptureResult result) {
    417                                 checkAfState(result);
    418                             }
    419 
    420                             private void checkAfState(CaptureResult result) {
    421                                 if (result.get(CaptureResult.CONTROL_AF_STATE) != null &&
    422                                         !mAlreadyDispatched) {
    423                                     // Now our mCameraResultStateCallback will invoke the callback
    424                                     // the first time it finds the focus motor to be locked.
    425                                     mAlreadyDispatched = true;
    426                                     mOneshotAfCallback = callback;
    427                                     // This is an optimization: check the AF state of this frame
    428                                     // instead of simply waiting for the next.
    429                                     mCameraResultStateCallback.monitorControlStates(result);
    430                                 }
    431                             }
    432 
    433                             @Override
    434                             public void onCaptureFailed(CameraCaptureSession session,
    435                                                         CaptureRequest request,
    436                                                         CaptureFailure failure) {
    437                                 Log.e(TAG, "Focusing failed with reason " + failure.getReason());
    438                                 callback.onAutoFocus(false, mCameraProxy);
    439                             }};
    440 
    441                         // Send a one-time capture to trigger the camera driver to lock focus.
    442                         changeState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
    443                         Camera2RequestSettingsSet trigger =
    444                                 new Camera2RequestSettingsSet(mPersistentSettings);
    445                         trigger.set(CaptureRequest.CONTROL_AF_TRIGGER,
    446                                 CaptureRequest.CONTROL_AF_TRIGGER_START);
    447                         try {
    448                             mSession.capture(
    449                                     trigger.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW,
    450                                             mPreviewSurface),
    451                                     /*listener*/deferredCallbackSetter, /*handler*/ this);
    452                         } catch(CameraAccessException ex) {
    453                             Log.e(TAG, "Unable to lock autofocus", ex);
    454                             changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
    455                         }
    456                         break;
    457                     }
    458 
    459                     case CameraActions.CANCEL_AUTO_FOCUS: {
    460                         // Ignore all AFs that were already queued until we see
    461                         // a CANCEL_AUTO_FOCUS_FINISH
    462                         mCancelAfPending++;
    463                         // Why would you want to unlock the lens if it isn't already locked?
    464                         if (mCameraState.getState() <
    465                                 AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
    466                             Log.w(TAG, "Ignoring attempt to release focus lock without preview");
    467                             break;
    468                         }
    469 
    470                         // Send a one-time capture to trigger the camera driver to resume scanning.
    471                         changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
    472                         Camera2RequestSettingsSet cancel =
    473                                 new Camera2RequestSettingsSet(mPersistentSettings);
    474                         cancel.set(CaptureRequest.CONTROL_AF_TRIGGER,
    475                                 CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
    476                         try {
    477                             mSession.capture(
    478                                     cancel.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW,
    479                                             mPreviewSurface),
    480                                     /*listener*/null, /*handler*/this);
    481                         } catch(CameraAccessException ex) {
    482                             Log.e(TAG, "Unable to cancel autofocus", ex);
    483                             changeState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
    484                         }
    485                         break;
    486                     }
    487 
    488                     case CameraActions.CANCEL_AUTO_FOCUS_FINISH: {
    489                         // Stop ignoring AUTO_FOCUS messages unless there are additional
    490                         // CANCEL_AUTO_FOCUSes that were added
    491                         mCancelAfPending--;
    492                         break;
    493                     }
    494 
    495                     case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: {
    496                         mPassiveAfCallback = (CameraAFMoveCallback) msg.obj;
    497                         break;
    498                     }
    499 
    500                     /*case CameraActions.SET_ZOOM_CHANGE_LISTENER: {
    501                         break;
    502                     }
    503 
    504                     case CameraActions.SET_FACE_DETECTION_LISTENER: {
    505                         break;
    506                     }
    507 
    508                     case CameraActions.START_FACE_DETECTION: {
    509                         break;
    510                     }
    511 
    512                     case CameraActions.STOP_FACE_DETECTION: {
    513                         break;
    514                     }
    515 
    516                     case CameraActions.SET_ERROR_CALLBACK: {
    517                         break;
    518                     }
    519 
    520                     case CameraActions.ENABLE_SHUTTER_SOUND: {
    521                         break;
    522                     }*/
    523 
    524                     case CameraActions.SET_DISPLAY_ORIENTATION: {
    525                         // Only set the JPEG capture orientation if requested to do so; otherwise,
    526                         // capture in the sensor's physical orientation. (e.g., JPEG rotation is
    527                         // necessary in auto-rotate mode.
    528                         mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg2 > 0 ?
    529                                 mCameraProxy.getCharacteristics().getJpegOrientation(msg.arg1) : 0);
    530                         break;
    531                     }
    532 
    533                     case CameraActions.SET_JPEG_ORIENTATION: {
    534                         mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg1);
    535                         break;
    536                     }
    537 
    538                     case CameraActions.CAPTURE_PHOTO: {
    539                         if (mCameraState.getState() <
    540                                         AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
    541                             Log.e(TAG, "Photos may only be taken when a preview is active");
    542                             break;
    543                         }
    544                         if (mCameraState.getState() !=
    545                                 AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED) {
    546                             Log.w(TAG, "Taking a (likely blurry) photo without the lens locked");
    547                         }
    548 
    549                         final CaptureAvailableListener listener =
    550                                 (CaptureAvailableListener) msg.obj;
    551                         if (mLegacyDevice ||
    552                                 (mCurrentAeState == CaptureResult.CONTROL_AE_STATE_CONVERGED &&
    553                                 !mPersistentSettings.matches(CaptureRequest.CONTROL_AE_MODE,
    554                                         CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH) &&
    555                                 !mPersistentSettings.matches(CaptureRequest.FLASH_MODE,
    556                                         CaptureRequest.FLASH_MODE_SINGLE)))
    557                                 {
    558                             // Legacy devices don't support the precapture state keys and instead
    559                             // perform autoexposure convergence automatically upon capture.
    560 
    561                             // On other devices, as long as it has already converged, it determined
    562                             // that flash was not required, and we're not going to invalidate the
    563                             // current exposure levels by forcing the force on, we can save
    564                             // significant capture time by not forcing a recalculation.
    565                             Log.i(TAG, "Skipping pre-capture autoexposure convergence");
    566                             mCaptureReader.setOnImageAvailableListener(listener, /*handler*/this);
    567                             try {
    568                                 mSession.capture(
    569                                         mPersistentSettings.createRequest(mCamera,
    570                                                 CameraDevice.TEMPLATE_STILL_CAPTURE,
    571                                                 mCaptureReader.getSurface()),
    572                                         listener, /*handler*/this);
    573                             } catch (CameraAccessException ex) {
    574                                 Log.e(TAG, "Unable to initiate immediate capture", ex);
    575                             }
    576                         } else {
    577                             // We need to let AE converge before capturing. Once our one-time
    578                             // trigger capture has made it into the pipeline, we'll start checking
    579                             // for the completion of that convergence, capturing when that happens.
    580                             Log.i(TAG, "Forcing pre-capture autoexposure convergence");
    581                             CameraCaptureSession.CaptureCallback deferredCallbackSetter =
    582                                     new CameraCaptureSession.CaptureCallback() {
    583                                 private boolean mAlreadyDispatched = false;
    584 
    585                                 @Override
    586                                 public void onCaptureProgressed(CameraCaptureSession session,
    587                                                                 CaptureRequest request,
    588                                                                 CaptureResult result) {
    589                                     checkAeState(result);
    590                                 }
    591 
    592                                 @Override
    593                                 public void onCaptureCompleted(CameraCaptureSession session,
    594                                                                CaptureRequest request,
    595                                                                TotalCaptureResult result) {
    596                                     checkAeState(result);
    597                                 }
    598 
    599                                 private void checkAeState(CaptureResult result) {
    600                                     if (result.get(CaptureResult.CONTROL_AE_STATE) != null &&
    601                                             !mAlreadyDispatched) {
    602                                         // Now our mCameraResultStateCallback will invoke the
    603                                         // callback once the autoexposure routine has converged.
    604                                         mAlreadyDispatched = true;
    605                                         mOneshotCaptureCallback = listener;
    606                                         // This is an optimization: check the AE state of this frame
    607                                         // instead of simply waiting for the next.
    608                                         mCameraResultStateCallback.monitorControlStates(result);
    609                                     }
    610                                 }
    611 
    612                                 @Override
    613                                 public void onCaptureFailed(CameraCaptureSession session,
    614                                                             CaptureRequest request,
    615                                                             CaptureFailure failure) {
    616                                     Log.e(TAG, "Autoexposure and capture failed with reason " +
    617                                             failure.getReason());
    618                                     // TODO: Make an error callback?
    619                                 }};
    620 
    621                             // Set a one-time capture to trigger the camera driver's autoexposure:
    622                             Camera2RequestSettingsSet expose =
    623                                     new Camera2RequestSettingsSet(mPersistentSettings);
    624                             expose.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
    625                                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
    626                             try {
    627                                 mSession.capture(
    628                                         expose.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW,
    629                                                 mPreviewSurface),
    630                                         /*listener*/deferredCallbackSetter, /*handler*/this);
    631                             } catch (CameraAccessException ex) {
    632                                 Log.e(TAG, "Unable to run autoexposure and perform capture", ex);
    633                             }
    634                         }
    635                         break;
    636                     }
    637 
    638                     default: {
    639                         // TODO: Rephrase once everything has been implemented
    640                         throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what);
    641                     }
    642                 }
    643             } catch (final Exception ex) {
    644                 if (cameraAction != CameraActions.RELEASE && mCamera != null) {
    645                     // TODO: Handle this better
    646                     mCamera.close();
    647                     mCamera = null;
    648                 } else if (mCamera == null) {
    649                     if (cameraAction == CameraActions.OPEN_CAMERA) {
    650                         if (mOpenCallback != null) {
    651                             mOpenCallback.onDeviceOpenFailure(mCameraIndex,
    652                                     generateHistoryString(mCameraIndex));
    653                         }
    654                     } else {
    655                         Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null");
    656                     }
    657                     return;
    658                 }
    659 
    660                 if (ex instanceof RuntimeException) {
    661                     String commandHistory = generateHistoryString(Integer.parseInt(mCameraId));
    662                     mExceptionHandler.onCameraException((RuntimeException) ex, commandHistory,
    663                             cameraAction, mCameraState.getState());
    664                 }
    665             } finally {
    666                 WaitDoneBundle.unblockSyncWaiters(msg);
    667             }
    668         }
    669 
    670         public CameraSettings buildSettings(AndroidCamera2Capabilities caps) {
    671             try {
    672                 return new AndroidCamera2Settings(mCamera, CameraDevice.TEMPLATE_PREVIEW,
    673                         mActiveArray, mPreviewSize, mPhotoSize);
    674             } catch (CameraAccessException ex) {
    675                 Log.e(TAG, "Unable to query camera device to build settings representation");
    676                 return null;
    677             }
    678         }
    679 
    680         /**
    681          * Simply propagates settings from provided {@link CameraSettings}
    682          * object to our {@link CaptureRequest.Builder} for use in captures.
    683          * <p>Most conversions to match the API 2 formats are performed by
    684          * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise
    685          * any final adjustments are done here before updating the builder.</p>
    686          *
    687          * @param settings The new/updated settings
    688          */
    689         private void applyToRequest(AndroidCamera2Settings settings) {
    690             // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect
    691 
    692             mPersistentSettings.union(settings.getRequestSettings());
    693             mPreviewSize = settings.getCurrentPreviewSize();
    694             mPhotoSize = settings.getCurrentPhotoSize();
    695 
    696             if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
    697                 // If we're already previewing, reflect most settings immediately
    698                 try {
    699                     mSession.setRepeatingRequest(
    700                             mPersistentSettings.createRequest(mCamera,
    701                                     CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface),
    702                             /*listener*/mCameraResultStateCallback, /*handler*/this);
    703                 } catch (CameraAccessException ex) {
    704                     Log.e(TAG, "Failed to apply updated request settings", ex);
    705                 }
    706             } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
    707                 // If we're already ready to preview, this doesn't regress our state
    708                 changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
    709             }
    710         }
    711 
    712         private void setPreviewTexture(SurfaceTexture surfaceTexture) {
    713             // TODO: Must be called after providing a .*Settings populated with sizes
    714             // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures!
    715 
    716             // TODO: Handle this error condition with a callback or exception
    717             if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) {
    718                 Log.w(TAG, "Ignoring texture setting at inappropriate time");
    719                 return;
    720             }
    721 
    722             // Avoid initializing another capture session unless we absolutely have to
    723             if (surfaceTexture == mPreviewTexture) {
    724                 Log.i(TAG, "Optimizing out redundant preview texture setting");
    725                 return;
    726             }
    727 
    728             if (mSession != null) {
    729                 closePreviewSession();
    730             }
    731 
    732             mPreviewTexture = surfaceTexture;
    733             surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height());
    734 
    735             if (mPreviewSurface != null) {
    736                 mPreviewSurface.release();
    737             }
    738             mPreviewSurface = new Surface(surfaceTexture);
    739 
    740             if (mCaptureReader != null) {
    741                 mCaptureReader.close();
    742             }
    743             mCaptureReader = ImageReader.newInstance(
    744                     mPhotoSize.width(), mPhotoSize.height(), ImageFormat.JPEG, 1);
    745 
    746             try {
    747                 mCamera.createCaptureSession(
    748                         Arrays.asList(mPreviewSurface, mCaptureReader.getSurface()),
    749                         mCameraPreviewStateCallback, this);
    750             } catch (CameraAccessException ex) {
    751                 Log.e(TAG, "Failed to create camera capture session", ex);
    752             }
    753         }
    754 
    755         private void closePreviewSession() {
    756             try {
    757                 mSession.abortCaptures();
    758                 mSession = null;
    759             } catch (CameraAccessException ex) {
    760                 Log.e(TAG, "Failed to close existing camera capture session", ex);
    761             }
    762             changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
    763         }
    764 
    765         private void changeState(int newState) {
    766             if (mCameraState.getState() != newState) {
    767                 mCameraState.setState(newState);
    768                 if (newState < AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
    769                     mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE;
    770                     mCameraResultStateCallback.resetState();
    771                 }
    772             }
    773         }
    774 
    775         // This callback monitors our connection to and disconnection from camera devices.
    776         private CameraDevice.StateCallback mCameraDeviceStateCallback =
    777                 new CameraDevice.StateCallback() {
    778             @Override
    779             public void onOpened(CameraDevice camera) {
    780                 mCamera = camera;
    781                 if (mOpenCallback != null) {
    782                     try {
    783                         CameraCharacteristics props =
    784                                 mCameraManager.getCameraCharacteristics(mCameraId);
    785                         CameraDeviceInfo.Characteristics characteristics =
    786                                 getCameraDeviceInfo().getCharacteristics(mCameraIndex);
    787                         mCameraProxy = new AndroidCamera2ProxyImpl(AndroidCamera2AgentImpl.this,
    788                                 mCameraIndex, mCamera, characteristics, props);
    789                         mPersistentSettings = new Camera2RequestSettingsSet();
    790                         mActiveArray =
    791                                 props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    792                         mLegacyDevice =
    793                                 props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
    794                                         CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
    795                         changeState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED);
    796                         mOpenCallback.onCameraOpened(mCameraProxy);
    797                     } catch (CameraAccessException ex) {
    798                         mOpenCallback.onDeviceOpenFailure(mCameraIndex,
    799                                 generateHistoryString(mCameraIndex));
    800                     }
    801                 }
    802             }
    803 
    804             @Override
    805             public void onDisconnected(CameraDevice camera) {
    806                 Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected");
    807             }
    808 
    809             @Override
    810             public void onError(CameraDevice camera, int error) {
    811                 Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" +
    812                         error + '\'');
    813                 if (mOpenCallback != null) {
    814                     mOpenCallback.onDeviceOpenFailure(mCameraIndex,
    815                             generateHistoryString(mCameraIndex));
    816                 }
    817             }};
    818 
    819         // This callback monitors our camera session (i.e. our transition into and out of preview).
    820         private CameraCaptureSession.StateCallback mCameraPreviewStateCallback =
    821                 new CameraCaptureSession.StateCallback() {
    822             @Override
    823             public void onConfigured(CameraCaptureSession session) {
    824                 mSession = session;
    825                 changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
    826             }
    827 
    828             @Override
    829             public void onConfigureFailed(CameraCaptureSession session) {
    830                 // TODO: Invoke a callback
    831                 Log.e(TAG, "Failed to configure the camera for capture");
    832             }
    833 
    834             @Override
    835             public void onActive(CameraCaptureSession session) {
    836                 if (mOneshotPreviewingCallback != null) {
    837                     // The session is up and processing preview requests. Inform the caller.
    838                     mOneshotPreviewingCallback.onPreviewStarted();
    839                     mOneshotPreviewingCallback = null;
    840                 }
    841             }};
    842 
    843         private abstract class CameraResultStateCallback
    844                 extends CameraCaptureSession.CaptureCallback {
    845             public abstract void monitorControlStates(CaptureResult result);
    846 
    847             public abstract void resetState();
    848         }
    849 
    850         // This callback monitors requested captures and notifies any relevant callbacks.
    851         private CameraResultStateCallback mCameraResultStateCallback =
    852                 new CameraResultStateCallback() {
    853             private int mLastAfState = -1;
    854             private long mLastAfFrameNumber = -1;
    855             private long mLastAeFrameNumber = -1;
    856 
    857             @Override
    858             public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
    859                                             CaptureResult result) {
    860                 monitorControlStates(result);
    861             }
    862 
    863             @Override
    864             public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
    865                                            TotalCaptureResult result) {
    866                 monitorControlStates(result);
    867             }
    868 
    869             @Override
    870             public void monitorControlStates(CaptureResult result) {
    871                 Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE);
    872                 if (afStateMaybe != null) {
    873                     int afState = afStateMaybe;
    874                     // Since we handle both partial and total results for multiple frames here, we
    875                     // might get the final callbacks for an earlier frame after receiving one or
    876                     // more that correspond to the next one. To prevent our data from oscillating,
    877                     // we never consider AF states that are older than the last one we've seen.
    878                     if (result.getFrameNumber() > mLastAfFrameNumber) {
    879                         boolean afStateChanged = afState != mLastAfState;
    880                         mLastAfState = afState;
    881                         mLastAfFrameNumber = result.getFrameNumber();
    882 
    883                         switch (afState) {
    884                             case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
    885                             case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
    886                             case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: {
    887                                 if (afStateChanged && mPassiveAfCallback != null) {
    888                                     // A CameraAFMoveCallback is attached. If we just started to
    889                                     // scan, the motor is moving; otherwise, it has settled.
    890                                     mPassiveAfCallback.onAutoFocusMoving(
    891                                             afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN,
    892                                             mCameraProxy);
    893                                 }
    894                                 break;
    895                             }
    896 
    897                             case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
    898                             case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: {
    899                                 // This check must be made regardless of whether the focus state has
    900                                 // changed recently to avoid infinite waiting during autoFocus()
    901                                 // when the algorithm has already either converged or failed to.
    902                                 if (mOneshotAfCallback != null) {
    903                                     // A call to autoFocus() was just made to request a focus lock.
    904                                     // Notify the caller that the lens is now indefinitely fixed,
    905                                     // and report whether the image we're stuck with is in focus.
    906                                     mOneshotAfCallback.onAutoFocus(
    907                                             afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
    908                                             mCameraProxy);
    909                                     mOneshotAfCallback = null;
    910                                 }
    911                                 break;
    912                             }
    913                         }
    914                     }
    915                 }
    916 
    917                 Integer aeStateMaybe = result.get(CaptureResult.CONTROL_AE_STATE);
    918                 if (aeStateMaybe != null) {
    919                     int aeState = aeStateMaybe;
    920                     // Since we handle both partial and total results for multiple frames here, we
    921                     // might get the final callbacks for an earlier frame after receiving one or
    922                     // more that correspond to the next one. To prevent our data from oscillating,
    923                     // we never consider AE states that are older than the last one we've seen.
    924                     if (result.getFrameNumber() > mLastAeFrameNumber) {
    925                         mCurrentAeState = aeStateMaybe;
    926                         mLastAeFrameNumber = result.getFrameNumber();
    927 
    928                         switch (aeState) {
    929                             case CaptureResult.CONTROL_AE_STATE_CONVERGED:
    930                             case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED:
    931                             case CaptureResult.CONTROL_AE_STATE_LOCKED: {
    932                                 // This check must be made regardless of whether the exposure state
    933                                 // has changed recently to avoid infinite waiting during
    934                                 // takePicture() when the algorithm has already converged.
    935                                 if (mOneshotCaptureCallback != null) {
    936                                     // A call to takePicture() was just made, and autoexposure
    937                                     // converged so it's time to initiate the capture!
    938                                     mCaptureReader.setOnImageAvailableListener(
    939                                             /*listener*/mOneshotCaptureCallback,
    940                                             /*handler*/Camera2Handler.this);
    941                                     try {
    942                                         mSession.capture(
    943                                                 mPersistentSettings.createRequest(mCamera,
    944                                                         CameraDevice.TEMPLATE_STILL_CAPTURE,
    945                                                         mCaptureReader.getSurface()),
    946                                                 /*callback*/mOneshotCaptureCallback,
    947                                                 /*handler*/Camera2Handler.this);
    948                                     } catch (CameraAccessException ex) {
    949                                         Log.e(TAG, "Unable to initiate capture", ex);
    950                                     } finally {
    951                                         mOneshotCaptureCallback = null;
    952                                     }
    953                                 }
    954                                 break;
    955                             }
    956                         }
    957                     }
    958                 }
    959             }
    960 
    961             @Override
    962             public void resetState() {
    963                 mLastAfState = -1;
    964                 mLastAfFrameNumber = -1;
    965                 mLastAeFrameNumber = -1;
    966             }
    967 
    968             @Override
    969             public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
    970                                         CaptureFailure failure) {
    971                 Log.e(TAG, "Capture attempt failed with reason " + failure.getReason());
    972             }};
    973     }
    974 
    975     private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy {
    976         private final AndroidCamera2AgentImpl mCameraAgent;
    977         private final int mCameraIndex;
    978         private final CameraDevice mCamera;
    979         private final CameraDeviceInfo.Characteristics mCharacteristics;
    980         private final AndroidCamera2Capabilities mCapabilities;
    981         private CameraSettings mLastSettings;
    982         private boolean mShutterSoundEnabled;
    983 
    984         public AndroidCamera2ProxyImpl(
    985                 AndroidCamera2AgentImpl agent,
    986                 int cameraIndex,
    987                 CameraDevice camera,
    988                 CameraDeviceInfo.Characteristics characteristics,
    989                 CameraCharacteristics properties) {
    990             mCameraAgent = agent;
    991             mCameraIndex = cameraIndex;
    992             mCamera = camera;
    993             mCharacteristics = characteristics;
    994             mCapabilities = new AndroidCamera2Capabilities(properties);
    995             mLastSettings = null;
    996             mShutterSoundEnabled = true;
    997         }
    998 
    999         // TODO: Implement
   1000         @Override
   1001         public android.hardware.Camera getCamera() { return null; }
   1002 
   1003         @Override
   1004         public int getCameraId() {
   1005             return mCameraIndex;
   1006         }
   1007 
   1008         @Override
   1009         public CameraDeviceInfo.Characteristics getCharacteristics() {
   1010             return mCharacteristics;
   1011         }
   1012 
   1013         @Override
   1014         public CameraCapabilities getCapabilities() {
   1015             return mCapabilities;
   1016         }
   1017 
   1018         public CameraAgent getAgent() {
   1019             return mCameraAgent;
   1020         }
   1021 
   1022         private AndroidCamera2Capabilities getSpecializedCapabilities() {
   1023             return mCapabilities;
   1024         }
   1025 
   1026         // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
   1027         // explanation on the STOP_PREVIEW case in the handler.
   1028         @Override
   1029         public void setPreviewTexture(SurfaceTexture surfaceTexture) {
   1030             // Once the Surface has been selected, we configure the session and
   1031             // are no longer able to change the sizes.
   1032             getSettings().setSizesLocked(true);
   1033             super.setPreviewTexture(surfaceTexture);
   1034         }
   1035 
   1036         // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
   1037         // explanation on the STOP_PREVIEW case in the handler.
   1038         @Override
   1039         public void setPreviewTextureSync(SurfaceTexture surfaceTexture) {
   1040             // Once the Surface has been selected, we configure the session and
   1041             // are no longer able to change the sizes.
   1042             getSettings().setSizesLocked(true);
   1043             super.setPreviewTexture(surfaceTexture);
   1044         }
   1045 
   1046         // TODO: Implement
   1047         @Override
   1048         public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
   1049 
   1050         // TODO: Implement
   1051         @Override
   1052         public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {}
   1053 
   1054         // TODO: Implement
   1055         @Override
   1056         public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)
   1057                 {}
   1058 
   1059         // TODO: Implement
   1060         public void addCallbackBuffer(final byte[] callbackBuffer) {}
   1061 
   1062         @Override
   1063         public void autoFocus(final Handler handler, final CameraAFCallback cb) {
   1064             try {
   1065                 mDispatchThread.runJob(new Runnable() {
   1066                     @Override
   1067                     public void run() {
   1068                         CameraAFCallback cbForward = null;
   1069                         if (cb != null) {
   1070                             cbForward = new CameraAFCallback() {
   1071                                 @Override
   1072                                 public void onAutoFocus(final boolean focused,
   1073                                                         final CameraProxy camera) {
   1074                                     handler.post(new Runnable() {
   1075                                         @Override
   1076                                         public void run() {
   1077                                             cb.onAutoFocus(focused, camera);
   1078                                         }
   1079                                     });
   1080                                 }
   1081                             };
   1082                         }
   1083 
   1084                         mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
   1085                                 AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
   1086                         mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward)
   1087                                 .sendToTarget();
   1088                     }
   1089                 });
   1090             } catch (RuntimeException ex) {
   1091                 mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex);
   1092             }
   1093         }
   1094 
   1095         @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
   1096         @Override
   1097         public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) {
   1098             try {
   1099                 mDispatchThread.runJob(new Runnable() {
   1100                     @Override
   1101                     public void run() {
   1102                         CameraAFMoveCallback cbForward = null;
   1103                         if (cb != null) {
   1104                             cbForward = new CameraAFMoveCallback() {
   1105                                 @Override
   1106                                 public void onAutoFocusMoving(final boolean moving,
   1107                                                               final CameraProxy camera) {
   1108                                     handler.post(new Runnable() {
   1109                                         @Override
   1110                                         public void run() {
   1111                                             cb.onAutoFocusMoving(moving, camera);
   1112                                         }
   1113                                     });
   1114                                 }
   1115                             };
   1116                         }
   1117 
   1118                         mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK,
   1119                                 cbForward).sendToTarget();
   1120                     }
   1121                 });
   1122             } catch (RuntimeException ex) {
   1123                 mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex);
   1124             }
   1125         }
   1126 
   1127         @Override
   1128         public void takePicture(final Handler handler,
   1129                                 final CameraShutterCallback shutter,
   1130                                 CameraPictureCallback raw,
   1131                                 CameraPictureCallback postview,
   1132                                 final CameraPictureCallback jpeg) {
   1133             // TODO: We never call raw or postview
   1134             final CaptureAvailableListener picListener =
   1135                     new CaptureAvailableListener() {
   1136                 @Override
   1137                 public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
   1138                                              long timestamp, long frameNumber) {
   1139                     if (shutter != null) {
   1140                         handler.post(new Runnable() {
   1141                             @Override
   1142                             public void run() {
   1143                                 if (mShutterSoundEnabled) {
   1144                                     mNoisemaker.play(MediaActionSound.SHUTTER_CLICK);
   1145                                 }
   1146                                 shutter.onShutter(AndroidCamera2ProxyImpl.this);
   1147                             }});
   1148                     }
   1149                 }
   1150 
   1151                 @Override
   1152                 public void onImageAvailable(ImageReader reader) {
   1153                     try (Image image = reader.acquireNextImage()) {
   1154                         if (jpeg != null) {
   1155                             ByteBuffer buffer = image.getPlanes()[0].getBuffer();
   1156                             final byte[] pixels = new byte[buffer.remaining()];
   1157                             buffer.get(pixels);
   1158                             handler.post(new Runnable() {
   1159                                 @Override
   1160                                 public void run() {
   1161                                     jpeg.onPictureTaken(pixels, AndroidCamera2ProxyImpl.this);
   1162                                 }});
   1163                         }
   1164                     }
   1165                 }};
   1166             try {
   1167                 mDispatchThread.runJob(new Runnable() {
   1168                     @Override
   1169                     public void run() {
   1170                         // Wait until PREVIEW_ACTIVE or better
   1171                         mCameraState.waitForStates(
   1172                                 ~(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE - 1));
   1173                         mCameraHandler.obtainMessage(CameraActions.CAPTURE_PHOTO, picListener)
   1174                                 .sendToTarget();
   1175                     }
   1176                 });
   1177             } catch (RuntimeException ex) {
   1178                 mCameraAgent.getCameraExceptionHandler().onDispatchThreadException(ex);
   1179             }
   1180         }
   1181 
   1182         // TODO: Implement
   1183         @Override
   1184         public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {}
   1185 
   1186         // TODO: Implement
   1187         @Override
   1188         public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback)
   1189                 {}
   1190 
   1191         // TODO: Remove this method override once we handle this message
   1192         @Override
   1193         public void startFaceDetection() {}
   1194 
   1195         // TODO: Remove this method override once we handle this message
   1196         @Override
   1197         public void stopFaceDetection() {}
   1198 
   1199         // TODO: Implement
   1200         @Override
   1201         public void setParameters(android.hardware.Camera.Parameters params) {}
   1202 
   1203         // TODO: Implement
   1204         @Override
   1205         public android.hardware.Camera.Parameters getParameters() { return null; }
   1206 
   1207         @Override
   1208         public CameraSettings getSettings() {
   1209             if (mLastSettings == null) {
   1210                 mLastSettings = mCameraHandler.buildSettings(mCapabilities);
   1211             }
   1212             return mLastSettings;
   1213         }
   1214 
   1215         @Override
   1216         public boolean applySettings(CameraSettings settings) {
   1217             if (settings == null) {
   1218                 Log.w(TAG, "null parameters in applySettings()");
   1219                 return false;
   1220             }
   1221             if (!(settings instanceof AndroidCamera2Settings)) {
   1222                 Log.e(TAG, "Provided settings not compatible with the backing framework API");
   1223                 return false;
   1224             }
   1225 
   1226             // Wait for any state that isn't OPENED
   1227             if (applySettingsHelper(settings, ~AndroidCamera2StateHolder.CAMERA_UNOPENED)) {
   1228                 mLastSettings = settings;
   1229                 return true;
   1230             }
   1231             return false;
   1232         }
   1233 
   1234         @Override
   1235         public void enableShutterSound(boolean enable) {
   1236             mShutterSoundEnabled = enable;
   1237         }
   1238 
   1239         // TODO: Implement
   1240         @Override
   1241         public String dumpDeviceSettings() { return null; }
   1242 
   1243         @Override
   1244         public Handler getCameraHandler() {
   1245             return AndroidCamera2AgentImpl.this.getCameraHandler();
   1246         }
   1247 
   1248         @Override
   1249         public DispatchThread getDispatchThread() {
   1250             return AndroidCamera2AgentImpl.this.getDispatchThread();
   1251         }
   1252 
   1253         @Override
   1254         public CameraStateHolder getCameraState() {
   1255             return mCameraState;
   1256         }
   1257     }
   1258 
   1259     /** A linear state machine: each state entails all the states below it. */
   1260     private static class AndroidCamera2StateHolder extends CameraStateHolder {
   1261         // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() ->
   1262         //             autoFocus() -> takePicture()
   1263         // States are mutually exclusive, but must be separate bits so that they can be used with
   1264         // the StateHolder#waitForStates() and StateHolder#waitToAvoidStates() methods.
   1265         // Do not set the state to be a combination of these values!
   1266         /* Camera states */
   1267         /** No camera device is opened. */
   1268         public static final int CAMERA_UNOPENED = 1 << 0;
   1269         /** A camera is opened, but no settings have been provided. */
   1270         public static final int CAMERA_UNCONFIGURED = 1 << 1;
   1271         /** The open camera has been configured by providing it with settings. */
   1272         public static final int CAMERA_CONFIGURED = 1 << 2;
   1273         /** A capture session is ready to stream a preview, but still has no repeating request. */
   1274         public static final int CAMERA_PREVIEW_READY = 1 << 3;
   1275         /** A preview is currently being streamed. */
   1276         public static final int CAMERA_PREVIEW_ACTIVE = 1 << 4;
   1277         /** The lens is locked on a particular region. */
   1278         public static final int CAMERA_FOCUS_LOCKED = 1 << 5;
   1279 
   1280         public AndroidCamera2StateHolder() {
   1281             this(CAMERA_UNOPENED);
   1282         }
   1283 
   1284         public AndroidCamera2StateHolder(int state) {
   1285             super(state);
   1286         }
   1287     }
   1288 
   1289     private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo {
   1290         private final CameraManager mCameraManager;
   1291         private final String[] mCameraIds;
   1292         private final int mNumberOfCameras;
   1293         private final int mFirstBackCameraId;
   1294         private final int mFirstFrontCameraId;
   1295 
   1296         public AndroidCamera2DeviceInfo(CameraManager cameraManager,
   1297                                         String[] cameraIds, int numberOfCameras) {
   1298             mCameraManager = cameraManager;
   1299             mCameraIds = cameraIds;
   1300             mNumberOfCameras = numberOfCameras;
   1301 
   1302             int firstBackId = NO_DEVICE;
   1303             int firstFrontId = NO_DEVICE;
   1304             for (int id = 0; id < cameraIds.length; ++id) {
   1305                 try {
   1306                     int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id])
   1307                             .get(CameraCharacteristics.LENS_FACING);
   1308                     if (firstBackId == NO_DEVICE &&
   1309                             lensDirection == CameraCharacteristics.LENS_FACING_BACK) {
   1310                         firstBackId = id;
   1311                     }
   1312                     if (firstFrontId == NO_DEVICE &&
   1313                             lensDirection == CameraCharacteristics.LENS_FACING_FRONT) {
   1314                         firstFrontId = id;
   1315                     }
   1316                 } catch (CameraAccessException ex) {
   1317                     Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex);
   1318                 }
   1319             }
   1320             mFirstBackCameraId = firstBackId;
   1321             mFirstFrontCameraId = firstFrontId;
   1322         }
   1323 
   1324         @Override
   1325         public Characteristics getCharacteristics(int cameraId) {
   1326             String actualId = mCameraIds[cameraId];
   1327             try {
   1328                 CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId);
   1329                 return new AndroidCharacteristics2(info);
   1330             } catch (CameraAccessException ex) {
   1331                 return null;
   1332             }
   1333         }
   1334 
   1335         @Override
   1336         public int getNumberOfCameras() {
   1337             return mNumberOfCameras;
   1338         }
   1339 
   1340         @Override
   1341         public int getFirstBackCameraId() {
   1342             return mFirstBackCameraId;
   1343         }
   1344 
   1345         @Override
   1346         public int getFirstFrontCameraId() {
   1347             return mFirstFrontCameraId;
   1348         }
   1349 
   1350         private static class AndroidCharacteristics2 extends Characteristics {
   1351             private CameraCharacteristics mCameraInfo;
   1352 
   1353             AndroidCharacteristics2(CameraCharacteristics cameraInfo) {
   1354                 mCameraInfo = cameraInfo;
   1355             }
   1356 
   1357             @Override
   1358             public boolean isFacingBack() {
   1359                 return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
   1360                         .equals(CameraCharacteristics.LENS_FACING_BACK);
   1361             }
   1362 
   1363             @Override
   1364             public boolean isFacingFront() {
   1365                 return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
   1366                         .equals(CameraCharacteristics.LENS_FACING_FRONT);
   1367             }
   1368 
   1369             @Override
   1370             public int getSensorOrientation() {
   1371                 return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION);
   1372             }
   1373 
   1374             @Override
   1375             public Matrix getPreviewTransform(int currentDisplayOrientation,
   1376                                               RectF surfaceDimensions,
   1377                                               RectF desiredBounds) {
   1378                 if (!orientationIsValid(currentDisplayOrientation)) {
   1379                     return new Matrix();
   1380                 }
   1381 
   1382                 // The system transparently transforms the image to fill the surface
   1383                 // when the device is in its natural orientation. We rotate the
   1384                 // coordinates of the rectangle's corners to be relative to the
   1385                 // original image, instead of to the current screen orientation.
   1386                 float[] surfacePolygon = rotate(convertRectToPoly(surfaceDimensions),
   1387                         2 * currentDisplayOrientation / 90);
   1388                 float[] desiredPolygon = convertRectToPoly(desiredBounds);
   1389 
   1390                 Matrix transform = new Matrix();
   1391                 // Use polygons instead of rectangles so that rotation will be
   1392                 // calculated, since that is not done by the new camera API.
   1393                 transform.setPolyToPoly(surfacePolygon, 0, desiredPolygon, 0, 4);
   1394                 return transform;
   1395             }
   1396 
   1397             @Override
   1398             public boolean canDisableShutterSound() {
   1399                 return true;
   1400             }
   1401 
   1402             private static float[] convertRectToPoly(RectF rf) {
   1403                 return new float[] {rf.left, rf.top, rf.right, rf.top,
   1404                         rf.right, rf.bottom, rf.left, rf.bottom};
   1405             }
   1406 
   1407             private static float[] rotate(float[] arr, int times) {
   1408                 if (times < 0) {
   1409                     times = times % arr.length + arr.length;
   1410                 }
   1411 
   1412                 float[] res = new float[arr.length];
   1413                 for (int offset = 0; offset < arr.length; ++offset) {
   1414                     res[offset] = arr[(times + offset) % arr.length];
   1415                 }
   1416                 return res;
   1417             }
   1418         }
   1419     }
   1420 }
   1421