Home | History | Annotate | Download | only in v2
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.one.v2;
     18 
     19 import android.annotation.TargetApi;
     20 import android.content.Context;
     21 import android.graphics.ImageFormat;
     22 import android.graphics.Rect;
     23 import android.hardware.camera2.CameraAccessException;
     24 import android.hardware.camera2.CameraCaptureSession;
     25 import android.hardware.camera2.CameraCharacteristics;
     26 import android.hardware.camera2.CameraDevice;
     27 import android.hardware.camera2.CameraMetadata;
     28 import android.hardware.camera2.CaptureRequest;
     29 import android.hardware.camera2.CaptureResult;
     30 import android.hardware.camera2.CaptureResult.Key;
     31 import android.hardware.camera2.TotalCaptureResult;
     32 import android.hardware.camera2.params.MeteringRectangle;
     33 import android.hardware.camera2.params.StreamConfigurationMap;
     34 import android.media.CameraProfile;
     35 import android.media.Image;
     36 import android.media.ImageReader;
     37 import android.media.MediaActionSound;
     38 import android.net.Uri;
     39 import android.os.Build;
     40 import android.os.Handler;
     41 import android.os.HandlerThread;
     42 import android.os.SystemClock;
     43 import android.support.v4.util.Pools;
     44 import android.view.Surface;
     45 
     46 import com.android.camera.CaptureModuleUtil;
     47 import com.android.camera.app.MediaSaver.OnMediaSavedListener;
     48 import com.android.camera.debug.Log;
     49 import com.android.camera.debug.Log.Tag;
     50 import com.android.camera.exif.ExifInterface;
     51 import com.android.camera.exif.ExifTag;
     52 import com.android.camera.exif.Rational;
     53 import com.android.camera.one.AbstractOneCamera;
     54 import com.android.camera.one.OneCamera;
     55 import com.android.camera.one.OneCamera.PhotoCaptureParameters.Flash;
     56 import com.android.camera.one.Settings3A;
     57 import com.android.camera.one.v2.ImageCaptureManager.ImageCaptureListener;
     58 import com.android.camera.one.v2.ImageCaptureManager.MetadataChangeListener;
     59 import com.android.camera.session.CaptureSession;
     60 import com.android.camera.util.CameraUtil;
     61 import com.android.camera.util.ConjunctionListenerMux;
     62 import com.android.camera.util.JpegUtilNative;
     63 import com.android.camera.util.Size;
     64 
     65 import java.nio.ByteBuffer;
     66 import java.util.ArrayList;
     67 import java.util.List;
     68 import java.util.concurrent.LinkedBlockingQueue;
     69 import java.util.concurrent.ThreadPoolExecutor;
     70 import java.util.concurrent.TimeUnit;
     71 import java.util.concurrent.atomic.AtomicLong;
     72 
     73 /**
     74  * {@link OneCamera} implementation directly on top of the Camera2 API with zero
     75  * shutter lag.<br>
     76  * TODO: Determine what the maximum number of full YUV capture frames is.
     77  */
     78 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     79 public class OneCameraZslImpl extends AbstractOneCamera {
     80     private static final Tag TAG = new Tag("OneCameraZslImpl2");
     81 
     82     /** Default JPEG encoding quality. */
     83     private static final int JPEG_QUALITY = CameraProfile.getJpegEncodingQualityParameter(
     84             CameraProfile.QUALITY_HIGH);
     85     /**
     86      * The maximum number of images to store in the full-size ZSL ring buffer.
     87      * <br>
     88      * TODO: Determine this number dynamically based on available memory and the
     89      * size of frames.
     90      */
     91     private static final int MAX_CAPTURE_IMAGES = 10;
     92     /**
     93      * True if zero-shutter-lag images should be captured. Some devices produce
     94      * lower-quality images for the high-frequency stream, so we may wish to
     95      * disable ZSL in that case.
     96      */
     97     private static final boolean ZSL_ENABLED = true;
     98 
     99     /**
    100      * Tags which may be used in CaptureRequests.
    101      */
    102     private static enum RequestTag {
    103         /**
    104          * Indicates that the request was explicitly sent for a single
    105          * high-quality still capture. Unlike other requests, such as the
    106          * repeating (ZSL) stream and AF/AE triggers, requests with this tag
    107          * should always be saved.
    108          */
    109         EXPLICIT_CAPTURE
    110     }
    111 
    112     /**
    113      * Set to ImageFormat.JPEG to use the hardware encoder, or
    114      * ImageFormat.YUV_420_888 to use the software encoder. No other image
    115      * formats are supported.
    116      */
    117     private static final int sCaptureImageFormat = ImageFormat.YUV_420_888;
    118     /**
    119      * Token for callbacks posted to {@link #mCameraHandler} to resume
    120      * continuous AF.
    121      */
    122     private static final String FOCUS_RESUME_CALLBACK_TOKEN = "RESUME_CONTINUOUS_AF";
    123 
    124     /** Zero weight 3A region, to reset regions per API. */
    125     /*package*/ MeteringRectangle[] ZERO_WEIGHT_3A_REGION = AutoFocusHelper.getZeroWeightRegion();
    126 
    127     /**
    128      * Thread on which high-priority camera operations, such as grabbing preview
    129      * frames for the viewfinder, are running.
    130      */
    131     private final HandlerThread mCameraThread;
    132     /** Handler of the {@link #mCameraThread}. */
    133     private final Handler mCameraHandler;
    134 
    135     /** Thread on which low-priority camera listeners are running. */
    136     private final HandlerThread mCameraListenerThread;
    137     private final Handler mCameraListenerHandler;
    138 
    139     /** The characteristics of this camera. */
    140     private final CameraCharacteristics mCharacteristics;
    141     /** The underlying Camera2 API camera device. */
    142     private final CameraDevice mDevice;
    143 
    144     /**
    145      * The aspect ratio (width/height) of the full resolution for this camera.
    146      * Usually the native aspect ratio of this camera.
    147      */
    148     private final float mFullSizeAspectRatio;
    149     /** The Camera2 API capture session currently active. */
    150     private CameraCaptureSession mCaptureSession;
    151     /** The surface onto which to render the preview. */
    152     private Surface mPreviewSurface;
    153     /** Whether closing of this device has been requested. */
    154     private volatile boolean mIsClosed = false;
    155     /** A callback that is called when the device is fully closed. */
    156     private CloseCallback mCloseCallback = null;
    157 
    158     /** Receives the normal captured images. */
    159     private final ImageReader mCaptureImageReader;
    160 
    161     /**
    162      * Maintains a buffer of images and their associated {@link CaptureResult}s.
    163      */
    164     private ImageCaptureManager mCaptureManager;
    165 
    166     /**
    167      * The sensor timestamp (which may not be relative to the system time) of
    168      * the most recently captured image.
    169      */
    170     private final AtomicLong mLastCapturedImageTimestamp = new AtomicLong(0);
    171 
    172     /** Thread pool for performing slow jpeg encoding and saving tasks. */
    173     private final ThreadPoolExecutor mImageSaverThreadPool;
    174 
    175     /** Pool of native byte buffers on which to store jpeg-encoded images. */
    176     private final Pools.SynchronizedPool<ByteBuffer> mJpegByteBufferPool = new
    177             Pools.SynchronizedPool<ByteBuffer>(64);
    178 
    179     /** Current zoom value. 1.0 is no zoom. */
    180     private float mZoomValue = 1f;
    181     /** Current crop region: set from mZoomValue. */
    182     private Rect mCropRegion;
    183     /** Current AE, AF, and AWB regions */
    184     private MeteringRectangle[] mAFRegions = ZERO_WEIGHT_3A_REGION;
    185     private MeteringRectangle[] mAERegions = ZERO_WEIGHT_3A_REGION;
    186 
    187     private MediaActionSound mMediaActionSound = new MediaActionSound();
    188 
    189     /**
    190      * Ready state (typically displayed by the UI shutter-button) depends on two
    191      * things:<br>
    192      * <ol>
    193      * <li>{@link #mCaptureManager} must be ready.</li>
    194      * <li>We must not be in the process of capturing a single, high-quality,
    195      * image.</li>
    196      * </ol>
    197      * See {@link ConjunctionListenerMux} and {@link #mReadyStateManager} for
    198      * details of how this is managed.
    199      */
    200     private static enum ReadyStateRequirement {
    201         CAPTURE_MANAGER_READY,
    202         CAPTURE_NOT_IN_PROGRESS
    203     }
    204 
    205     /**
    206      * Handles the thread-safe logic of dispatching whenever the logical AND of
    207      * these constraints changes.
    208      */
    209     private final ConjunctionListenerMux<ReadyStateRequirement>
    210             mReadyStateManager = new ConjunctionListenerMux<ReadyStateRequirement>(
    211                     ReadyStateRequirement.class, new ConjunctionListenerMux.OutputChangeListener() {
    212                             @Override
    213                         public void onOutputChange(boolean state) {
    214                             broadcastReadyState(state);
    215                         }
    216                     });
    217 
    218     /**
    219      * An {@link ImageCaptureListener} which will compress and save an image to
    220      * disk.
    221      */
    222     private class ImageCaptureTask implements ImageCaptureListener {
    223         private final PhotoCaptureParameters mParams;
    224         private final CaptureSession mSession;
    225 
    226         public ImageCaptureTask(PhotoCaptureParameters parameters,
    227                 CaptureSession session) {
    228             mParams = parameters;
    229             mSession = session;
    230         }
    231 
    232         @Override
    233         public void onImageCaptured(Image image, TotalCaptureResult
    234                 captureResult) {
    235             long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
    236 
    237             // We should only capture the image if it's more recent than the
    238             // latest one. Synchronization is necessary since this method is
    239             // called on {@link #mImageSaverThreadPool}.
    240             synchronized (mLastCapturedImageTimestamp) {
    241                 if (timestamp > mLastCapturedImageTimestamp.get()) {
    242                     mLastCapturedImageTimestamp.set(timestamp);
    243                 } else {
    244                     // There was a more recent (or identical) image which has
    245                     // begun being saved, so abort.
    246                     return;
    247                 }
    248             }
    249 
    250             mReadyStateManager.setInput(
    251                     ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS, true);
    252 
    253             mSession.startEmpty();
    254             savePicture(image, mParams, mSession);
    255             mParams.callback.onPictureTaken(mSession);
    256             Log.v(TAG, "Image saved.  Frame number = " + captureResult.getFrameNumber());
    257         }
    258     }
    259 
    260     /**
    261      * Instantiates a new camera based on Camera 2 API.
    262      *
    263      * @param device The underlying Camera 2 device.
    264      * @param characteristics The device's characteristics.
    265      * @param pictureSize the size of the final image to be taken.
    266      */
    267     OneCameraZslImpl(CameraDevice device, CameraCharacteristics characteristics, Size pictureSize) {
    268         Log.v(TAG, "Creating new OneCameraZslImpl");
    269 
    270         mDevice = device;
    271         mCharacteristics = characteristics;
    272         mFullSizeAspectRatio = calculateFullSizeAspectRatio(characteristics);
    273 
    274         mCameraThread = new HandlerThread("OneCamera2");
    275         // If this thread stalls, it will delay viewfinder frames.
    276         mCameraThread.setPriority(Thread.MAX_PRIORITY);
    277         mCameraThread.start();
    278         mCameraHandler = new Handler(mCameraThread.getLooper());
    279 
    280         mCameraListenerThread = new HandlerThread("OneCamera2-Listener");
    281         mCameraListenerThread.start();
    282         mCameraListenerHandler = new Handler(mCameraListenerThread.getLooper());
    283 
    284         // TODO: Encoding on multiple cores results in preview jank due to
    285         // excessive GC.
    286         int numEncodingCores = CameraUtil.getNumCpuCores();
    287         mImageSaverThreadPool = new ThreadPoolExecutor(numEncodingCores, numEncodingCores, 10,
    288                 TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    289 
    290         mCaptureManager = new ImageCaptureManager(MAX_CAPTURE_IMAGES, mCameraListenerHandler,
    291                 mImageSaverThreadPool);
    292         mCaptureManager.setCaptureReadyListener(new ImageCaptureManager.CaptureReadyListener() {
    293                 @Override
    294             public void onReadyStateChange(boolean capturePossible) {
    295                 mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_MANAGER_READY,
    296                         capturePossible);
    297             }
    298         });
    299 
    300         // Listen for changes to auto focus state and dispatch to
    301         // mFocusStateListener.
    302         mCaptureManager.addMetadataChangeListener(CaptureResult.CONTROL_AF_STATE,
    303                 new ImageCaptureManager.MetadataChangeListener() {
    304                 @Override
    305                     public void onImageMetadataChange(Key<?> key, Object oldValue, Object newValue,
    306                             CaptureResult result) {
    307                         mFocusStateListener.onFocusStatusUpdate(
    308                                 AutoFocusHelper.stateFromCamera2State(
    309                                         result.get(CaptureResult.CONTROL_AF_STATE)),
    310                                 result.getFrameNumber());
    311                     }
    312                 });
    313 
    314         // Allocate the image reader to store all images received from the
    315         // camera.
    316         if (pictureSize == null) {
    317             // TODO The default should be selected by the caller, and
    318             // pictureSize should never be null.
    319             pictureSize = getDefaultPictureSize();
    320         }
    321         mCaptureImageReader = ImageReader.newInstance(pictureSize.getWidth(),
    322                 pictureSize.getHeight(),
    323                 sCaptureImageFormat, MAX_CAPTURE_IMAGES);
    324 
    325         mCaptureImageReader.setOnImageAvailableListener(mCaptureManager, mCameraHandler);
    326         mMediaActionSound.load(MediaActionSound.SHUTTER_CLICK);
    327     }
    328 
    329     /**
    330      * @return The largest supported picture size.
    331      */
    332     public Size getDefaultPictureSize() {
    333         StreamConfigurationMap configs = mCharacteristics.get(
    334                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    335         android.util.Size[] supportedSizes = configs.getOutputSizes(sCaptureImageFormat);
    336 
    337         // Find the largest supported size.
    338         android.util.Size largestSupportedSize = supportedSizes[0];
    339         long largestSupportedSizePixels = largestSupportedSize.getWidth()
    340                 * largestSupportedSize.getHeight();
    341         for (int i = 0; i < supportedSizes.length; i++) {
    342             long numPixels = supportedSizes[i].getWidth() * supportedSizes[i].getHeight();
    343             if (numPixels > largestSupportedSizePixels) {
    344                 largestSupportedSize = supportedSizes[i];
    345                 largestSupportedSizePixels = numPixels;
    346             }
    347         }
    348 
    349         return new Size(largestSupportedSize.getWidth(),
    350                 largestSupportedSize.getHeight());
    351     }
    352 
    353     private void onShutterInvokeUI(final PhotoCaptureParameters params) {
    354         // Tell CaptureModule shutter has occurred so it can flash the screen.
    355         params.callback.onQuickExpose();
    356         // Play shutter click sound.
    357         mMediaActionSound.play(MediaActionSound.SHUTTER_CLICK);
    358     }
    359 
    360     /**
    361      * Take a picture.
    362      */
    363     @Override
    364     public void takePicture(final PhotoCaptureParameters params, final CaptureSession session) {
    365         params.checkSanity();
    366 
    367         mReadyStateManager.setInput(
    368                 ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS, false);
    369 
    370         boolean useZSL = ZSL_ENABLED;
    371 
    372         // We will only capture images from the zsl ring-buffer which satisfy
    373         // this constraint.
    374         ArrayList<ImageCaptureManager.CapturedImageConstraint> zslConstraints = new ArrayList<
    375                 ImageCaptureManager.CapturedImageConstraint>();
    376         zslConstraints.add(new ImageCaptureManager.CapturedImageConstraint() {
    377                 @Override
    378             public boolean satisfiesConstraint(TotalCaptureResult captureResult) {
    379                 Long timestamp = captureResult.get(CaptureResult.SENSOR_TIMESTAMP);
    380                 Integer lensState = captureResult.get(CaptureResult.LENS_STATE);
    381                 Integer flashState = captureResult.get(CaptureResult.FLASH_STATE);
    382                 Integer flashMode = captureResult.get(CaptureResult.FLASH_MODE);
    383                 Integer aeState = captureResult.get(CaptureResult.CONTROL_AE_STATE);
    384                 Integer afState = captureResult.get(CaptureResult.CONTROL_AF_STATE);
    385                 Integer awbState = captureResult.get(CaptureResult.CONTROL_AWB_STATE);
    386 
    387                 if (timestamp <= mLastCapturedImageTimestamp.get()) {
    388                     // Don't save frames older than the most
    389                     // recently-captured frame.
    390                     // TODO This technically has a race condition in which
    391                     // duplicate frames may be saved, but if a user is
    392                     // tapping at >30Hz, duplicate images may be what they
    393                     // expect.
    394                     return false;
    395                 }
    396 
    397                 if (lensState == CaptureResult.LENS_STATE_MOVING) {
    398                     // If we know the lens was moving, don't use this image.
    399                     return false;
    400                 }
    401 
    402                 if (aeState == CaptureResult.CONTROL_AE_STATE_SEARCHING
    403                         || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
    404                     return false;
    405                 }
    406                 switch (params.flashMode) {
    407                     case OFF:
    408                         break;
    409                     case ON:
    410                         if (flashState != CaptureResult.FLASH_STATE_FIRED
    411                                 || flashMode != CaptureResult.FLASH_MODE_SINGLE) {
    412                             return false;
    413                         }
    414                         break;
    415                     case AUTO:
    416                         if (aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
    417                                 && flashState != CaptureResult.FLASH_STATE_FIRED) {
    418                             return false;
    419                         }
    420                         break;
    421                 }
    422 
    423                 if (afState == CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN
    424                         || afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN) {
    425                     return false;
    426                 }
    427 
    428                 if (awbState == CaptureResult.CONTROL_AWB_STATE_SEARCHING) {
    429                     return false;
    430                 }
    431 
    432                 return true;
    433             }
    434         });
    435         // This constraint lets us capture images which have been explicitly
    436         // requested. See {@link RequestTag.EXPLICIT_CAPTURE}.
    437         ArrayList<ImageCaptureManager.CapturedImageConstraint> singleCaptureConstraint = new ArrayList<
    438                 ImageCaptureManager.CapturedImageConstraint>();
    439         singleCaptureConstraint.add(new ImageCaptureManager.CapturedImageConstraint() {
    440                 @Override
    441             public boolean satisfiesConstraint(TotalCaptureResult captureResult) {
    442                 Object tag = captureResult.getRequest().getTag();
    443                 return tag == RequestTag.EXPLICIT_CAPTURE;
    444             }
    445         });
    446 
    447         // If we can use ZSL, try to save a previously-captured frame, if an
    448         // acceptable one exists in the buffer.
    449         if (useZSL) {
    450             boolean capturedPreviousFrame = mCaptureManager.tryCaptureExistingImage(
    451                     new ImageCaptureTask(params, session), zslConstraints);
    452             if (capturedPreviousFrame) {
    453                 Log.v(TAG, "Saving previous frame");
    454                 onShutterInvokeUI(params);
    455             } else {
    456                 Log.v(TAG, "No good image Available.  Capturing next available good image.");
    457                 // If there was no good frame available in the ring buffer
    458                 // already, capture the next good image.
    459                 // TODO Disable the shutter button until this image is captured.
    460 
    461                 if (params.flashMode == Flash.ON || params.flashMode == Flash.AUTO) {
    462                     // We must issue a request for a single capture using the
    463                     // flash, including an AE precapture trigger.
    464 
    465                     // The following sets up a sequence of events which will
    466                     // occur in reverse order to the associated method
    467                     // calls:
    468                     // 1. Send a request to trigger the Auto Exposure Precapture
    469                     // 2. Wait for the AE_STATE to leave the PRECAPTURE state,
    470                     // and then send a request for a single image, with the
    471                     // appropriate flash settings.
    472                     // 3. Capture the next appropriate image, which should be
    473                     // the one we requested in (2).
    474 
    475                     mCaptureManager.captureNextImage(new ImageCaptureTask(params, session),
    476                             singleCaptureConstraint);
    477 
    478                     mCaptureManager.addMetadataChangeListener(CaptureResult.CONTROL_AE_STATE,
    479                             new MetadataChangeListener() {
    480                             @Override
    481                                 public void onImageMetadataChange(Key<?> key, Object oldValue,
    482                                         Object newValue, CaptureResult result) {
    483                                     Log.v(TAG, "AE State Changed");
    484                                     if (oldValue.equals(
    485                                             Integer.valueOf(
    486                                                     CaptureResult.CONTROL_AE_STATE_PRECAPTURE))) {
    487                                         mCaptureManager.removeMetadataChangeListener(key, this);
    488                                         sendSingleRequest(params);
    489                                         // TODO: Delay this until onCaptureStarted().
    490                                         onShutterInvokeUI(params);
    491                                     }
    492                                 }
    493                             });
    494 
    495                     sendAutoExposureTriggerRequest(params.flashMode);
    496                 } else {
    497                     // We may get here if, for example, the auto focus is in the
    498                     // middle of a scan.
    499                     // If the flash is off, we should just wait for the next
    500                     // image that arrives. This will have minimal delay since we
    501                     // do not need to send a new capture request.
    502                     mCaptureManager.captureNextImage(new ImageCaptureTask(params, session),
    503                             zslConstraints);
    504                 }
    505             }
    506         } else {
    507             // TODO If we can't save a previous frame, create a new capture
    508             // request to do what we need (e.g. flash) and call
    509             // captureNextImage().
    510             throw new UnsupportedOperationException("Non-ZSL capture not yet supported");
    511         }
    512     }
    513 
    514     @Override
    515     public void startPreview(Surface previewSurface, CaptureReadyCallback listener) {
    516         mPreviewSurface = previewSurface;
    517         setupAsync(mPreviewSurface, listener);
    518     }
    519 
    520     @Override
    521     public void setViewfinderSize(int width, int height) {
    522         throw new RuntimeException("Not implemented yet.");
    523     }
    524 
    525     @Override
    526     public boolean isFlashSupported(boolean enhanced) {
    527         throw new RuntimeException("Not implemented yet.");
    528     }
    529 
    530     @Override
    531     public boolean isSupportingEnhancedMode() {
    532         throw new RuntimeException("Not implemented yet.");
    533     }
    534 
    535     @Override
    536     public void close(CloseCallback closeCallback) {
    537         if (mIsClosed) {
    538             Log.w(TAG, "Camera is already closed.");
    539             return;
    540         }
    541         try {
    542             mCaptureSession.abortCaptures();
    543         } catch (CameraAccessException e) {
    544             Log.e(TAG, "Could not abort captures in progress.");
    545         }
    546         mIsClosed = true;
    547         mCloseCallback = closeCallback;
    548         mCameraThread.quitSafely();
    549         mDevice.close();
    550         mCaptureManager.close();
    551     }
    552 
    553     @Override
    554     public Size[] getSupportedSizes() {
    555         StreamConfigurationMap config = mCharacteristics
    556                 .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    557         return Size.convert(config.getOutputSizes(sCaptureImageFormat));
    558     }
    559 
    560     @Override
    561     public float getFullSizeAspectRatio() {
    562         return mFullSizeAspectRatio;
    563     }
    564 
    565     @Override
    566     public boolean isFrontFacing() {
    567         return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
    568                 == CameraMetadata.LENS_FACING_FRONT;
    569     }
    570 
    571     @Override
    572     public boolean isBackFacing() {
    573         return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
    574                 == CameraMetadata.LENS_FACING_BACK;
    575     }
    576 
    577     private void savePicture(Image image, final PhotoCaptureParameters captureParams,
    578             CaptureSession session) {
    579         int heading = captureParams.heading;
    580 
    581         int width = image.getWidth();
    582         int height = image.getHeight();
    583         int rotation = 0;
    584         ExifInterface exif = null;
    585 
    586         exif = new ExifInterface();
    587         // TODO: Add more exif tags here.
    588 
    589         exif.setTag(exif.buildTag(ExifInterface.TAG_PIXEL_X_DIMENSION, width));
    590         exif.setTag(exif.buildTag(ExifInterface.TAG_PIXEL_Y_DIMENSION, height));
    591 
    592         // TODO: Handle rotation correctly.
    593 
    594         // Set GPS heading direction based on sensor, if location is on.
    595         if (heading >= 0) {
    596             ExifTag directionRefTag = exif.buildTag(
    597                     ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
    598                     ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
    599             ExifTag directionTag = exif.buildTag(
    600                     ExifInterface.TAG_GPS_IMG_DIRECTION,
    601                     new Rational(heading, 1));
    602             exif.setTag(directionRefTag);
    603             exif.setTag(directionTag);
    604         }
    605 
    606         session.saveAndFinish(acquireJpegBytes(image), width, height, rotation, exif,
    607                 new OnMediaSavedListener() {
    608                 @Override
    609                     public void onMediaSaved(Uri uri) {
    610                         captureParams.callback.onPictureSaved(uri);
    611                     }
    612                 });
    613     }
    614 
    615     /**
    616      * Asynchronously sets up the capture session.
    617      *
    618      * @param previewSurface the surface onto which the preview should be
    619      *            rendered.
    620      * @param listener called when setup is completed.
    621      */
    622     private void setupAsync(final Surface previewSurface, final CaptureReadyCallback listener) {
    623         mCameraHandler.post(new Runnable() {
    624                 @Override
    625             public void run() {
    626                 setup(previewSurface, listener);
    627             }
    628         });
    629     }
    630 
    631     /**
    632      * Configures and attempts to create a capture session.
    633      *
    634      * @param previewSurface the surface onto which the preview should be
    635      *            rendered.
    636      * @param listener called when the setup is completed.
    637      */
    638     private void setup(Surface previewSurface, final CaptureReadyCallback listener) {
    639         try {
    640             if (mCaptureSession != null) {
    641                 mCaptureSession.abortCaptures();
    642                 mCaptureSession = null;
    643             }
    644             List<Surface> outputSurfaces = new ArrayList<Surface>(2);
    645             outputSurfaces.add(previewSurface);
    646             outputSurfaces.add(mCaptureImageReader.getSurface());
    647 
    648             mDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
    649                     @Override
    650                 public void onConfigureFailed(CameraCaptureSession session) {
    651                     listener.onSetupFailed();
    652                 }
    653 
    654                     @Override
    655                 public void onConfigured(CameraCaptureSession session) {
    656                     mCaptureSession = session;
    657                     mAFRegions = ZERO_WEIGHT_3A_REGION;
    658                     mAERegions = ZERO_WEIGHT_3A_REGION;
    659                     mZoomValue = 1f;
    660                     mCropRegion = cropRegionForZoom(mZoomValue);
    661                     boolean success = sendRepeatingCaptureRequest();
    662                     if (success) {
    663                         mReadyStateManager.setInput(ReadyStateRequirement.CAPTURE_NOT_IN_PROGRESS,
    664                                 true);
    665                         mReadyStateManager.notifyListeners();
    666                         listener.onReadyForCapture();
    667                     } else {
    668                         listener.onSetupFailed();
    669                     }
    670                 }
    671 
    672                     @Override
    673                 public void onClosed(CameraCaptureSession session) {
    674                     super.onClosed(session);
    675                     if (mCloseCallback != null) {
    676                         mCloseCallback.onCameraClosed();
    677                     }
    678                 }
    679             }, mCameraHandler);
    680         } catch (CameraAccessException ex) {
    681             Log.e(TAG, "Could not set up capture session", ex);
    682             listener.onSetupFailed();
    683         }
    684     }
    685 
    686     private void addRegionsToCaptureRequestBuilder(CaptureRequest.Builder builder) {
    687         builder.set(CaptureRequest.CONTROL_AE_REGIONS, mAERegions);
    688         builder.set(CaptureRequest.CONTROL_AF_REGIONS, mAFRegions);
    689         builder.set(CaptureRequest.SCALER_CROP_REGION, mCropRegion);
    690     }
    691 
    692     private void addFlashToCaptureRequestBuilder(CaptureRequest.Builder builder, Flash flashMode) {
    693         switch (flashMode) {
    694             case ON:
    695                 builder.set(CaptureRequest.CONTROL_AE_MODE,
    696                         CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
    697                 builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
    698                 break;
    699             case OFF:
    700                 builder.set(CaptureRequest.CONTROL_AE_MODE,
    701                         CaptureRequest.CONTROL_AE_MODE_ON);
    702                 builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
    703                 break;
    704             case AUTO:
    705                 builder.set(CaptureRequest.CONTROL_AE_MODE,
    706                         CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
    707                 break;
    708         }
    709     }
    710 
    711     /**
    712      * Request a stream of images.
    713      *
    714      * @return true if successful, false if there was an error submitting the
    715      *         capture request.
    716      */
    717     private boolean sendRepeatingCaptureRequest() {
    718         Log.v(TAG, "sendRepeatingCaptureRequest()");
    719         try {
    720             CaptureRequest.Builder builder;
    721             if (ZSL_ENABLED) {
    722                 builder = mDevice.
    723                         createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
    724             } else {
    725                 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    726             }
    727 
    728             builder.addTarget(mPreviewSurface);
    729 
    730             if (ZSL_ENABLED) {
    731                 builder.addTarget(mCaptureImageReader.getSurface());
    732             }
    733 
    734             builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
    735 
    736             builder.set(CaptureRequest.CONTROL_AF_MODE,
    737                     CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
    738             builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    739 
    740             builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
    741             builder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
    742 
    743             addRegionsToCaptureRequestBuilder(builder);
    744 
    745             mCaptureSession.setRepeatingRequest(builder.build(), mCaptureManager,
    746                     mCameraHandler);
    747             return true;
    748         } catch (CameraAccessException e) {
    749             if (ZSL_ENABLED) {
    750                 Log.v(TAG, "Could not execute zero-shutter-lag repeating request.", e);
    751             } else {
    752                 Log.v(TAG, "Could not execute preview request.", e);
    753             }
    754             return false;
    755         }
    756     }
    757 
    758     /**
    759      * Request a single image.
    760      *
    761      * @return true if successful, false if there was an error submitting the
    762      *         capture request.
    763      */
    764     private boolean sendSingleRequest(OneCamera.PhotoCaptureParameters params) {
    765         Log.v(TAG, "sendSingleRequest()");
    766         try {
    767             CaptureRequest.Builder builder;
    768             builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
    769 
    770             builder.addTarget(mPreviewSurface);
    771 
    772             // Always add this surface for single image capture requests.
    773             builder.addTarget(mCaptureImageReader.getSurface());
    774 
    775             builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
    776 
    777             addFlashToCaptureRequestBuilder(builder, params.flashMode);
    778             addRegionsToCaptureRequestBuilder(builder);
    779 
    780             builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
    781             builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    782 
    783             // Tag this as a special request which should be saved.
    784             builder.setTag(RequestTag.EXPLICIT_CAPTURE);
    785 
    786             if (sCaptureImageFormat == ImageFormat.JPEG) {
    787                 builder.set(CaptureRequest.JPEG_QUALITY, (byte) (JPEG_QUALITY));
    788                 builder.set(CaptureRequest.JPEG_ORIENTATION,
    789                         CameraUtil.getJpegRotation(params.orientation, mCharacteristics));
    790             }
    791 
    792             mCaptureSession.capture(builder.build(), mCaptureManager,
    793                     mCameraHandler);
    794             return true;
    795         } catch (CameraAccessException e) {
    796             Log.v(TAG, "Could not execute single still capture request.", e);
    797             return false;
    798         }
    799     }
    800 
    801     private boolean sendAutoExposureTriggerRequest(Flash flashMode) {
    802         Log.v(TAG, "sendAutoExposureTriggerRequest()");
    803         try {
    804             CaptureRequest.Builder builder;
    805             if (ZSL_ENABLED) {
    806                 builder = mDevice.
    807                         createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
    808             } else {
    809                 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    810             }
    811 
    812             builder.addTarget(mPreviewSurface);
    813 
    814             if (ZSL_ENABLED) {
    815                 builder.addTarget(mCaptureImageReader.getSurface());
    816             }
    817 
    818             builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
    819 
    820             builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
    821                     CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
    822 
    823             addRegionsToCaptureRequestBuilder(builder);
    824             addFlashToCaptureRequestBuilder(builder, flashMode);
    825 
    826             mCaptureSession.capture(builder.build(), mCaptureManager,
    827                     mCameraHandler);
    828 
    829             return true;
    830         } catch (CameraAccessException e) {
    831             Log.v(TAG, "Could not execute auto exposure trigger request.", e);
    832             return false;
    833         }
    834     }
    835 
    836     /**
    837      */
    838     private boolean sendAutoFocusTriggerRequest() {
    839         Log.v(TAG, "sendAutoFocusTriggerRequest()");
    840         try {
    841             CaptureRequest.Builder builder;
    842             if (ZSL_ENABLED) {
    843                 builder = mDevice.
    844                         createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
    845             } else {
    846                 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    847             }
    848 
    849             builder.addTarget(mPreviewSurface);
    850 
    851             if (ZSL_ENABLED) {
    852                 builder.addTarget(mCaptureImageReader.getSurface());
    853             }
    854 
    855             builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);
    856 
    857             addRegionsToCaptureRequestBuilder(builder);
    858 
    859             builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
    860             builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
    861 
    862             mCaptureSession.capture(builder.build(), mCaptureManager,
    863                     mCameraHandler);
    864 
    865             return true;
    866         } catch (CameraAccessException e) {
    867             Log.v(TAG, "Could not execute auto focus trigger request.", e);
    868             return false;
    869         }
    870     }
    871 
    872     /**
    873      * Like {@link #sendRepeatingCaptureRequest()}, but with the focus held
    874      * constant.
    875      *
    876      * @return true if successful, false if there was an error submitting the
    877      *         capture request.
    878      */
    879     private boolean sendAutoFocusHoldRequest() {
    880         Log.v(TAG, "sendAutoFocusHoldRequest()");
    881         try {
    882             CaptureRequest.Builder builder;
    883             if (ZSL_ENABLED) {
    884                 builder = mDevice.
    885                         createCaptureRequest(CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
    886             } else {
    887                 builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    888             }
    889 
    890             builder.addTarget(mPreviewSurface);
    891 
    892             if (ZSL_ENABLED) {
    893                 builder.addTarget(mCaptureImageReader.getSurface());
    894             }
    895 
    896             builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
    897 
    898             builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO);
    899             builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
    900 
    901             addRegionsToCaptureRequestBuilder(builder);
    902             // TODO: This should fire the torch, if appropriate.
    903 
    904             mCaptureSession.setRepeatingRequest(builder.build(), mCaptureManager, mCameraHandler);
    905 
    906             return true;
    907         } catch (CameraAccessException e) {
    908             Log.v(TAG, "Could not execute auto focus hold request.", e);
    909             return false;
    910         }
    911     }
    912 
    913     /**
    914      * Calculate the aspect ratio of the full size capture on this device.
    915      *
    916      * @param characteristics the characteristics of the camera device.
    917      * @return The aspect ration, in terms of width/height of the full capture
    918      *         size.
    919      */
    920     private static float calculateFullSizeAspectRatio(CameraCharacteristics characteristics) {
    921         Rect activeArraySize =
    922                 characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
    923         return ((float) activeArraySize.width()) / activeArraySize.height();
    924     }
    925 
    926     /**
    927      * Given an image reader, extracts the JPEG image bytes and then closes the
    928      * reader.
    929      *
    930      * @param img the image from which to extract jpeg bytes or compress to
    931      *            jpeg.
    932      * @return The bytes of the JPEG image. Newly allocated.
    933      */
    934     private byte[] acquireJpegBytes(Image img) {
    935         ByteBuffer buffer;
    936 
    937         if (img.getFormat() == ImageFormat.JPEG) {
    938             Image.Plane plane0 = img.getPlanes()[0];
    939             buffer = plane0.getBuffer();
    940 
    941             byte[] imageBytes = new byte[buffer.remaining()];
    942             buffer.get(imageBytes);
    943             buffer.rewind();
    944             return imageBytes;
    945         } else if (img.getFormat() == ImageFormat.YUV_420_888) {
    946             buffer = mJpegByteBufferPool.acquire();
    947             if (buffer == null) {
    948                 buffer = ByteBuffer.allocateDirect(img.getWidth() * img.getHeight() * 3);
    949             }
    950 
    951             int numBytes = JpegUtilNative.compressJpegFromYUV420Image(img, buffer, JPEG_QUALITY);
    952 
    953             if (numBytes < 0) {
    954                 throw new RuntimeException("Error compressing jpeg.");
    955             }
    956 
    957             buffer.limit(numBytes);
    958 
    959             byte[] imageBytes = new byte[buffer.remaining()];
    960             buffer.get(imageBytes);
    961 
    962             buffer.clear();
    963             mJpegByteBufferPool.release(buffer);
    964 
    965             return imageBytes;
    966         } else {
    967             throw new RuntimeException("Unsupported image format.");
    968         }
    969     }
    970 
    971     private void startAFCycle() {
    972         // Clean up any existing AF cycle's pending callbacks.
    973         mCameraHandler.removeCallbacksAndMessages(FOCUS_RESUME_CALLBACK_TOKEN);
    974 
    975         // Send a single CONTROL_AF_TRIGGER_START capture request.
    976         sendAutoFocusTriggerRequest();
    977 
    978         // Immediately send a request for a regular preview stream, but with
    979         // CONTROL_AF_MODE_AUTO set so that the focus remains constant after the
    980         // AF cycle completes.
    981         sendAutoFocusHoldRequest();
    982 
    983         // Waits Settings3A.getFocusHoldMillis() milliseconds before sending
    984         // a request for a regular preview stream to resume.
    985         mCameraHandler.postAtTime(new Runnable() {
    986                 @Override
    987             public void run() {
    988                 mAERegions = ZERO_WEIGHT_3A_REGION;
    989                 mAFRegions = ZERO_WEIGHT_3A_REGION;
    990                 sendRepeatingCaptureRequest();
    991             }
    992         }, FOCUS_RESUME_CALLBACK_TOKEN,
    993                 SystemClock.uptimeMillis() + Settings3A.getFocusHoldMillis());
    994     }
    995 
    996     /**
    997      * @see com.android.camera.one.OneCamera#triggerFocusAndMeterAtPoint(float,
    998      *      float)
    999      */
   1000     @Override
   1001     public void triggerFocusAndMeterAtPoint(float nx, float ny) {
   1002         int sensorOrientation = mCharacteristics.get(
   1003             CameraCharacteristics.SENSOR_ORIENTATION);
   1004         mAERegions = AutoFocusHelper.aeRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation);
   1005         mAFRegions = AutoFocusHelper.afRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation);
   1006 
   1007         startAFCycle();
   1008     }
   1009 
   1010     @Override
   1011     public Size pickPreviewSize(Size pictureSize, Context context) {
   1012         if (pictureSize == null) {
   1013             // TODO The default should be selected by the caller, and
   1014             // pictureSize should never be null.
   1015             pictureSize = getDefaultPictureSize();
   1016         }
   1017         float pictureAspectRatio = pictureSize.getWidth() / (float) pictureSize.getHeight();
   1018         return CaptureModuleUtil.getOptimalPreviewSize(context, getSupportedSizes(),
   1019                 pictureAspectRatio);
   1020     }
   1021 
   1022     @Override
   1023     public float getMaxZoom() {
   1024         return mCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
   1025     }
   1026 
   1027     @Override
   1028     public void setZoom(float zoom) {
   1029         mZoomValue = zoom;
   1030         mCropRegion = cropRegionForZoom(zoom);
   1031         sendRepeatingCaptureRequest();
   1032     }
   1033 
   1034     private Rect cropRegionForZoom(float zoom) {
   1035         return AutoFocusHelper.cropRegionForZoom(mCharacteristics, zoom);
   1036     }
   1037 }
   1038