Home | History | Annotate | Download | only in stats
      1 package com.android.camera.stats;
      2 
      3 import android.graphics.Rect;
      4 import android.hardware.camera2.CaptureResult;
      5 import android.hardware.camera2.params.Face;
      6 import android.os.SystemClock;
      7 
      8 import com.google.common.annotations.VisibleForTesting;
      9 
     10 import com.android.camera.exif.ExifInterface;
     11 import com.android.camera.one.v2.camera2proxy.CaptureResultProxy;
     12 import com.android.camera.ui.TouchCoordinate;
     13 
     14 import java.util.ArrayList;
     15 import java.util.List;
     16 
     17 /**
     18  * Accumulates statistics during the lifecycle of a Capture Session. Since a
     19  * CaptureSession instance is available for the lifetime of the request and the
     20  * image processing of the said request, CaptureSessionStatsCollector is
     21  * attached to the CaptureSession so that we can collect information from both
     22  * the CaptureModule and the ImageBackend.
     23  */
     24 public class CaptureSessionStatsCollector {
     25 
     26 
     27     /** Time when capture is completed in SystemClock.elapsedRealtime(). */
     28     protected long mCaptureTimeMillis;
     29     protected final UsageStatistics mUsageStatistics;
     30 
     31     // Define all fields as Objects so that we know whether they were set or not.
     32     // A required field
     33     protected Integer mMode;
     34 
     35     // Fields with defaults, which are passed as primitives
     36     protected Boolean mIsFrontFacing = Boolean.FALSE;
     37     protected Boolean mIsHdr = Boolean.FALSE;
     38     protected Float mZoom = new Float(0.0f);
     39 
     40     // Optional fields (passed as Java Objects)
     41     protected String mFilename;
     42     protected ExifInterface mExifInterface;
     43     protected String mFlashSetting;
     44     protected Boolean mGridLinesOn;
     45     protected Float mTimerSeconds;
     46     protected TouchCoordinate mTouchCoordinate;
     47     protected Boolean mVolumeButtonShutter;
     48     protected List<Camera2FaceProxy> mFaceProxies;
     49     protected Float mLensFocusDistance;
     50     protected Rect mActiveSensorSize;
     51 
     52     /**
     53      * Constructor
     54      */
     55     public CaptureSessionStatsCollector() {
     56         mUsageStatistics = UsageStatistics.instance();
     57     }
     58 
     59     /**
     60      * Constructor for testing/dependency injection
     61      */
     62     @VisibleForTesting
     63     public CaptureSessionStatsCollector(UsageStatistics usageStatistics) {
     64         mUsageStatistics = usageStatistics;
     65     }
     66 
     67     /**
     68      * Decorate the collector when the CaptureResult becomes available, which happens sometime
     69      * after picture is taken.  In the current implementation, we query this structure for
     70      * two fields: 1) CaptureResult.STATISTICS_FACES and 2) CaptureResult.LENS_FOCUS_DISTANCE
     71      *
     72      * @param captureResult CaptureResults to be queried for capture event information
     73      */
     74     public void decorateAtTimeOfCaptureRequestAvailable(CaptureResultProxy captureResult) {
     75         Face [] facesCaptured = captureResult.get(CaptureResult.STATISTICS_FACES);
     76         if(facesCaptured == null) {
     77             mFaceProxies = null;
     78         } else {
     79             mFaceProxies = new ArrayList<>(facesCaptured.length);
     80             for (Face face : facesCaptured) {
     81                 mFaceProxies.add(Camera2FaceProxy.from(face));
     82             }
     83         }
     84 
     85         mLensFocusDistance = captureResult.get(CaptureResult.LENS_FOCUS_DISTANCE);
     86     }
     87 
     88     /**
     89      * Accumulate the information that should be available at the time of the Capture Request.
     90      * If you are unable to deliver one of these parameters, you may want to think again.
     91      *
     92      * @param mode a mode specified by eventprotos.NavigationChange.Mode
     93      * @param filename filename of image to be created
     94      * @param frontFacing whether the camera request is going to the front camera or not
     95      * @param isHDR whether the camera is HDR mode
     96      * @param zoom value of the zoom on the camera request
     97      * @param flashSetting string representing the state of the flash (KEY_FLASH_MODE)
     98      * @param gridLinesOn whether the gridlines are on the preview display
     99      * @param timerSeconds value of the countdown timer
    100      * @param touchCoordinate the last shutter touch coordinate
    101      * @param volumeButtonShutter whether the volume button was used to initialize the request.
    102      * @param activeSensorSize size of the active sensor array, to be used for the coordinate
    103      *                         space of the face array
    104      */
    105     public void decorateAtTimeCaptureRequest(
    106             final int mode,
    107             final String filename,
    108             final boolean frontFacing,
    109             final boolean isHDR,
    110             final float zoom,
    111             final String flashSetting,
    112             final boolean gridLinesOn,
    113             final float timerSeconds,
    114             final TouchCoordinate touchCoordinate,
    115             final Boolean volumeButtonShutter,
    116             final Rect activeSensorSize
    117     ) {
    118         mMode = mode;
    119         mFilename = filename;
    120         mIsFrontFacing = frontFacing;
    121         mIsHdr = isHDR;
    122         mZoom = zoom;
    123         mFlashSetting = flashSetting;
    124         mGridLinesOn = gridLinesOn;
    125         mTimerSeconds = timerSeconds;
    126         mTouchCoordinate = touchCoordinate;
    127         mVolumeButtonShutter = volumeButtonShutter;
    128         mActiveSensorSize = activeSensorSize;
    129     }
    130 
    131     /**
    132      * Accumalate the information that should be available at the time of
    133      * Write-To-Disk. If you are unable to deliver one of these parameters, you
    134      * may want to think again.
    135      *
    136      * @param exifInterface exif values to be associated with the JPEG image
    137      *            file that is being created.
    138      */
    139     public void decorateAtTimeWriteToDisk(
    140             final ExifInterface exifInterface
    141     ) {
    142         mExifInterface = exifInterface;
    143     }
    144 
    145     /**
    146      * Called when image processing time begins.
    147      */
    148     public void markProcessingTimeStart() {
    149         mCaptureTimeMillis = getElapsedRealTime();
    150     }
    151 
    152     /**
    153      * Send capture event to the UsageStatistics singleton.
    154      */
    155     public void photoCaptureDoneEvent() {
    156         Float processingTime = (getElapsedRealTime() - mCaptureTimeMillis) / 1000f;
    157         if (isValidForPhotoCaptureEvent()) {
    158             mUsageStatistics.photoCaptureDoneEvent(
    159                     mMode, mFilename, mExifInterface, mIsFrontFacing,
    160                     mIsHdr, mZoom, mFlashSetting, mGridLinesOn, mTimerSeconds,
    161                     processingTime, mTouchCoordinate, mVolumeButtonShutter,
    162                     mFaceProxies, mLensFocusDistance, mActiveSensorSize);
    163         }
    164     }
    165 
    166     /**
    167      * Returns whether all the fields in the CaptureSessionStatsCollector are set or not.
    168      */
    169     public boolean isCompleteForPhotoCaptureEvent() {
    170         return (mMode != null) &&
    171                 (mFilename != null) &&
    172                 (mExifInterface != null) &&
    173                 (mIsFrontFacing != null) &&
    174                 (mIsHdr != null) &&
    175                 (mZoom != null) &&
    176                 (mFlashSetting != null) &&
    177                 (mGridLinesOn != null) &&
    178                 (mTimerSeconds != null) &&
    179                 (mTouchCoordinate != null) &&
    180                 (mVolumeButtonShutter != null);
    181     }
    182 
    183     /**
    184      * Return whether state of collector is sufficient for PhotoCaptureEvent.
    185      *
    186      * @return whether state of collector is sufficient for PhotoCaptureEvent.
    187      */
    188     public boolean isValidForPhotoCaptureEvent() {
    189         return (mMode != null);
    190     }
    191 
    192     /**
    193      * Call to SystemClock.elapsedRealtime() that we can override for testing.
    194      */
    195     public long getElapsedRealTime() {
    196         return SystemClock.elapsedRealtime();
    197     }
    198 
    199 }
    200