1f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling/*
2f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * Copyright (C) 2014 The Android Open Source Project
3f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling *
4f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License");
5f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * you may not use this file except in compliance with the License.
6f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * You may obtain a copy of the License at
7f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling *
8f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling *      http://www.apache.org/licenses/LICENSE-2.0
9f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling *
10f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * Unless required by applicable law or agreed to in writing, software
11f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS,
12f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * See the License for the specific language governing permissions and
14f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * limitations under the License.
15f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling */
16f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
17f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingpackage com.android.camera.one.v2;
18f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
19cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberlingimport android.content.Context;
20f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.graphics.ImageFormat;
21f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.graphics.Rect;
22f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.CameraAccessException;
23f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.CameraCaptureSession;
24f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.CameraCharacteristics;
25f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.CameraDevice;
26f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.CameraMetadata;
27f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.CaptureRequest;
2830ffce08f511fbed4cf18daa743778b541583351Andy Huibersimport android.hardware.camera2.CaptureResult;
2930ffce08f511fbed4cf18daa743778b541583351Andy Huibersimport android.hardware.camera2.TotalCaptureResult;
3030ffce08f511fbed4cf18daa743778b541583351Andy Huibersimport android.hardware.camera2.params.MeteringRectangle;
31f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.hardware.camera2.params.StreamConfigurationMap;
32f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.media.Image;
33f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.media.ImageReader;
3457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport android.net.Uri;
35f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.os.Handler;
36f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.os.HandlerThread;
3730ffce08f511fbed4cf18daa743778b541583351Andy Huibersimport android.os.SystemClock;
38f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport android.view.Surface;
39f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
40cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberlingimport com.android.camera.CaptureModuleUtil;
4157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport com.android.camera.Exif;
4257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport com.android.camera.app.MediaSaver.OnMediaSavedListener;
4399a37d89f92cb0ad60cd57169c4845560ad0ffacAndy Huibersimport com.android.camera.debug.DebugPropertyHelper;
44f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport com.android.camera.debug.Log;
45f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport com.android.camera.debug.Log.Tag;
4657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport com.android.camera.exif.ExifInterface;
4757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport com.android.camera.exif.ExifTag;
4857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport com.android.camera.exif.Rational;
49f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport com.android.camera.one.AbstractOneCamera;
50f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport com.android.camera.one.OneCamera;
51b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibersimport com.android.camera.one.Settings3A;
52f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport com.android.camera.session.CaptureSession;
5330ffce08f511fbed4cf18daa743778b541583351Andy Huibersimport com.android.camera.util.CameraUtil;
5451163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberlingimport com.android.camera.util.CaptureDataSerializer;
55967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallimport com.android.camera.util.JpegUtilNative;
56967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lallimport com.android.camera.util.Size;
57f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
5851163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberlingimport java.io.File;
5957bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberlingimport java.io.IOException;
60f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport java.nio.ByteBuffer;
61f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport java.util.ArrayList;
62f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport java.util.LinkedList;
63f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingimport java.util.List;
64f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
65f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling/**
66f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling * {@link OneCamera} implementation directly on top of the Camera2 API.
67f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling */
68f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberlingpublic class OneCameraImpl extends AbstractOneCamera {
69f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
70f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** Captures that are requested but haven't completed yet. */
71f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private static class InFlightCapture {
7257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        final PhotoCaptureParameters parameters;
73f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        final CaptureSession session;
74f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
7557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        public InFlightCapture(PhotoCaptureParameters parameters,
76f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                CaptureSession session) {
7757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            this.parameters = parameters;
78f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            this.session = session;
79f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        }
80f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
81f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
82f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private static final Tag TAG = new Tag("OneCameraImpl2");
8330ffce08f511fbed4cf18daa743778b541583351Andy Huibers
8499a37d89f92cb0ad60cd57169c4845560ad0ffacAndy Huibers    /** If true, will write data about each capture request to disk. */
8599a37d89f92cb0ad60cd57169c4845560ad0ffacAndy Huibers    private static final boolean DEBUG_WRITE_CAPTURE_DATA = DebugPropertyHelper.writeCaptureData();
8699a37d89f92cb0ad60cd57169c4845560ad0ffacAndy Huibers    /** If true, will log per-frame AF info. */
8762b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers    private static final boolean DEBUG_FOCUS_LOG = DebugPropertyHelper.showFrameDebugLog();
8830ffce08f511fbed4cf18daa743778b541583351Andy Huibers
89f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** Default JPEG encoding quality. */
90f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private static final Byte JPEG_QUALITY = 90;
91f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
92967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall    /**
93967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall     * Set to ImageFormat.JPEG, to use the hardware encoder, or
9451163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling     * ImageFormat.YUV_420_888 to use the software encoder. No other image
9551163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling     * formats are supported.
96967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall     */
97967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall    private static final int sCaptureImageFormat = ImageFormat.YUV_420_888;
98967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
9930ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Duration to hold after manual focus tap. */
100b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers    private static final int FOCUS_HOLD_MILLIS = Settings3A.getFocusHoldMillis();
10134ac0609e30601fe2ce9b2338a173d7740ab3f82Andy Huibers    /** Zero weight 3A region, to reset regions per API. */
102527706e2957fe26f301d991d86d4359ab433408dAndy Huibers    MeteringRectangle[] ZERO_WEIGHT_3A_REGION = AutoFocusHelper.getZeroWeightRegion();
10330ffce08f511fbed4cf18daa743778b541583351Andy Huibers
10430ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
10530ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * CaptureRequest tags.
10630ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * <ul>
10730ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * <li>{@link #PRESHOT_TRIGGERED_AF}</li>
10830ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * <li>{@link #CAPTURE}</li>
10930ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * </ul>
11030ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
11130ffce08f511fbed4cf18daa743778b541583351Andy Huibers    public static enum RequestTag {
11230ffce08f511fbed4cf18daa743778b541583351Andy Huibers        /** Request that is part of a pre shot trigger. */
11330ffce08f511fbed4cf18daa743778b541583351Andy Huibers        PRESHOT_TRIGGERED_AF,
11430ffce08f511fbed4cf18daa743778b541583351Andy Huibers        /** Capture request (purely for logging). */
11526b3334755ffccc039249005435d5cc598d0689eAndy Huibers        CAPTURE,
11626b3334755ffccc039249005435d5cc598d0689eAndy Huibers        /** Tap to focus (purely for logging). */
11726b3334755ffccc039249005435d5cc598d0689eAndy Huibers        TAP_TO_FOCUS
11830ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
11930ffce08f511fbed4cf18daa743778b541583351Andy Huibers
12030ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Current CONTROL_AF_MODE request to Camera2 API. */
12126b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private int mControlAFMode = CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
12230ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Last OneCamera.AutoFocusState reported. */
12330ffce08f511fbed4cf18daa743778b541583351Andy Huibers    private AutoFocusState mLastResultAFState = AutoFocusState.INACTIVE;
12430ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Flag to take a picture when the lens is stopped. */
12530ffce08f511fbed4cf18daa743778b541583351Andy Huibers    private boolean mTakePictureWhenLensIsStopped = false;
12630ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Takes a (delayed) picture with appropriate parameters. */
12730ffce08f511fbed4cf18daa743778b541583351Andy Huibers    private Runnable mTakePictureRunnable;
12817d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers    /** Keep PictureCallback for last requested capture. */
12917d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers    private PictureCallback mLastPictureCallback = null;
13030ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Last time takePicture() was called in uptimeMillis. */
13130ffce08f511fbed4cf18daa743778b541583351Andy Huibers    private long mTakePictureStartMillis;
13230ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /** Runnable that returns to CONTROL_AF_MODE = AF_CONTINUOUS_PICTURE. */
13351163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling    private final Runnable mReturnToContinuousAFRunnable = new Runnable() {
13430ffce08f511fbed4cf18daa743778b541583351Andy Huibers        @Override
13530ffce08f511fbed4cf18daa743778b541583351Andy Huibers        public void run() {
136b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers            mAFRegions = ZERO_WEIGHT_3A_REGION;
137b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers            mAERegions = ZERO_WEIGHT_3A_REGION;
13826b3334755ffccc039249005435d5cc598d0689eAndy Huibers            mControlAFMode = CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE;
13926b3334755ffccc039249005435d5cc598d0689eAndy Huibers            repeatingPreview(null);
14030ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
14130ffce08f511fbed4cf18daa743778b541583351Andy Huibers    };
14230ffce08f511fbed4cf18daa743778b541583351Andy Huibers
14351163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling    /** Current zoom value. 1.0 is no zoom. */
14426b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private float mZoomValue = 1f;
14526b3334755ffccc039249005435d5cc598d0689eAndy Huibers    /** Current crop region: set from mZoomValue. */
14626b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private Rect mCropRegion;
147b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers    /** Current AF and AE regions */
148b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers    private MeteringRectangle[] mAFRegions = ZERO_WEIGHT_3A_REGION;
149b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers    private MeteringRectangle[] mAERegions = ZERO_WEIGHT_3A_REGION;
150b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers    /** Last frame for which CONTROL_AF_STATE was received. */
151b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers    private long mLastControlAfStateFrameNumber = 0;
15230ffce08f511fbed4cf18daa743778b541583351Andy Huibers
15330ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
15430ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * Common listener for preview frame metadata.
15530ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
15676215c98a9a11d87b5ce9d2b4198654c2b8bbddfAlan Newberger    private final CameraCaptureSession.CaptureCallback mAutoFocusStateListener = new
15776215c98a9a11d87b5ce9d2b4198654c2b8bbddfAlan Newberger            CameraCaptureSession.CaptureCallback() {
15817d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers                @Override
15917d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers                public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
160dd38b94c6f21b528f0de706a69d853f24a9c9561Eino-Ville Talvala                                             long timestamp, long frameNumber) {
16117d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers                    if (request.getTag() == RequestTag.CAPTURE && mLastPictureCallback != null) {
16217d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers                        mLastPictureCallback.onQuickExpose();
16317d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers                    }
16417d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers                }
16517d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers
16630ffce08f511fbed4cf18daa743778b541583351Andy Huibers                // AF state information is sometimes available 1 frame before
16730ffce08f511fbed4cf18daa743778b541583351Andy Huibers                // onCaptureCompleted(), so we take advantage of that.
16830ffce08f511fbed4cf18daa743778b541583351Andy Huibers                @Override
16951163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                public void onCaptureProgressed(CameraCaptureSession session,
17051163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                        CaptureRequest request,
17151163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                        CaptureResult partialResult) {
172b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    autofocusStateChangeDispatcher(partialResult);
17330ffce08f511fbed4cf18daa743778b541583351Andy Huibers                    super.onCaptureProgressed(session, request, partialResult);
17430ffce08f511fbed4cf18daa743778b541583351Andy Huibers                }
17551163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling
17630ffce08f511fbed4cf18daa743778b541583351Andy Huibers                @Override
17751163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                public void onCaptureCompleted(CameraCaptureSession session,
17851163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                        CaptureRequest request,
17951163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                        TotalCaptureResult result) {
180b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    autofocusStateChangeDispatcher(result);
181b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    // This checks for a HAL implementation error where TotalCaptureResult
182b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    // is missing CONTROL_AF_STATE.  This should not happen.
183b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    if (result.get(CaptureResult.CONTROL_AF_STATE) == null) {
184b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                        AutoFocusHelper.checkControlAfState(result);
18530ffce08f511fbed4cf18daa743778b541583351Andy Huibers                    }
18699a37d89f92cb0ad60cd57169c4845560ad0ffacAndy Huibers                    if (DEBUG_FOCUS_LOG) {
18703e17a62b43e58c8da5cd6ee23fd0809a82ee448Andy Huibers                        AutoFocusHelper.logExtraFocusInfo(result);
18899a37d89f92cb0ad60cd57169c4845560ad0ffacAndy Huibers                    }
18930ffce08f511fbed4cf18daa743778b541583351Andy Huibers                    super.onCaptureCompleted(session, request, result);
19030ffce08f511fbed4cf18daa743778b541583351Andy Huibers                }
19130ffce08f511fbed4cf18daa743778b541583351Andy Huibers            };
192f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** Thread on which the camera operations are running. */
193f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private final HandlerThread mCameraThread;
194f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** Handler of the {@link #mCameraThread}. */
195f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private final Handler mCameraHandler;
196f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** The characteristics of this camera. */
197f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private final CameraCharacteristics mCharacteristics;
198f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** The underlying Camera2 API camera device. */
199f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private final CameraDevice mDevice;
20057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
201f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
202f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * The aspect ratio (width/height) of the full resolution for this camera.
203f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * Usually the native aspect ratio of this camera.
204f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
2059cefdd495332719d987ffb942742ec602793d8d4Jiawen Chen    private final float mFullSizeAspectRatio;
206f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** The Camera2 API capture session currently active. */
207f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private CameraCaptureSession mCaptureSession;
208f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** The surface onto which to render the preview. */
209f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private Surface mPreviewSurface;
210f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
211f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * A queue of capture requests that have been requested but are not done
212f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * yet.
213f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
21457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    private final LinkedList<InFlightCapture> mCaptureQueue =
21557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            new LinkedList<InFlightCapture>();
216f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** Whether closing of this device has been requested. */
217f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private volatile boolean mIsClosed = false;
218f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /** A callback that is called when the device is fully closed. */
219f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private CloseCallback mCloseCallback = null;
220f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
221967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall    /** Receives the normal captured images. */
222967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall    private final ImageReader mCaptureImageReader;
223967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall    ImageReader.OnImageAvailableListener mCaptureImageListener =
224f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            new ImageReader.OnImageAvailableListener() {
225f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                @Override
226f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                public void onImageAvailable(ImageReader reader) {
22757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                    InFlightCapture capture = mCaptureQueue.remove();
22857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
22951163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                    // Since this is not an HDR+ session, we will just save the
23051163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                    // result.
23157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                    capture.session.startEmpty();
232f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    byte[] imageBytes = acquireJpegBytesAndClose(reader);
23330ffce08f511fbed4cf18daa743778b541583351Andy Huibers                    // TODO: The savePicture call here seems to block UI thread.
23457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                    savePicture(imageBytes, capture.parameters, capture.session);
235e3ad4352a23ddb21350d356e0947905d1e635911Sascha Haeberling                    broadcastReadyState(true);
23657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                    capture.parameters.callback.onPictureTaken(capture.session);
237f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                }
238f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            };
239f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
240f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
241f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * Instantiates a new camera based on Camera 2 API.
242f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *
243f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param device The underlying Camera 2 device.
244f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param characteristics The device's characteristics.
24557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling     * @param pictureSize the size of the final image to be taken.
246f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
247f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    OneCameraImpl(CameraDevice device, CameraCharacteristics characteristics, Size pictureSize) {
248f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mDevice = device;
249f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCharacteristics = characteristics;
250f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mFullSizeAspectRatio = calculateFullSizeAspectRatio(characteristics);
251f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
252f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCameraThread = new HandlerThread("OneCamera2");
253f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCameraThread.start();
254f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCameraHandler = new Handler(mCameraThread.getLooper());
255f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
25651163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling        mCaptureImageReader = ImageReader.newInstance(pictureSize.getWidth(),
25751163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                pictureSize.getHeight(),
258967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall                sCaptureImageFormat, 2);
259967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        mCaptureImageReader.setOnImageAvailableListener(mCaptureImageListener, mCameraHandler);
260f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        Log.d(TAG, "New Camera2 based OneCameraImpl created.");
261f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
262f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
26330ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
26430ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * Take picture, initiating an auto focus scan if needed.
26530ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
266f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
26730ffce08f511fbed4cf18daa743778b541583351Andy Huibers    public void takePicture(final PhotoCaptureParameters params, final CaptureSession session) {
268b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // Do not do anything when a picture is already requested.
269b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        if (mTakePictureWhenLensIsStopped) {
27030ffce08f511fbed4cf18daa743778b541583351Andy Huibers            return;
27130ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
27230ffce08f511fbed4cf18daa743778b541583351Andy Huibers
273b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // Not ready until the picture comes back.
274e3ad4352a23ddb21350d356e0947905d1e635911Sascha Haeberling        broadcastReadyState(false);
275e3ad4352a23ddb21350d356e0947905d1e635911Sascha Haeberling
27630ffce08f511fbed4cf18daa743778b541583351Andy Huibers        mTakePictureRunnable = new Runnable() {
27730ffce08f511fbed4cf18daa743778b541583351Andy Huibers            @Override
27830ffce08f511fbed4cf18daa743778b541583351Andy Huibers            public void run() {
27930ffce08f511fbed4cf18daa743778b541583351Andy Huibers                takePictureNow(params, session);
28030ffce08f511fbed4cf18daa743778b541583351Andy Huibers            }
28130ffce08f511fbed4cf18daa743778b541583351Andy Huibers        };
28217d9084e38e64f06a9d411d64fe3c2739d299cdaAndy Huibers        mLastPictureCallback = params.callback;
28330ffce08f511fbed4cf18daa743778b541583351Andy Huibers        mTakePictureStartMillis = SystemClock.uptimeMillis();
28430ffce08f511fbed4cf18daa743778b541583351Andy Huibers
285b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // This class implements a very simple version of AF, which
286b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // only delays capture if the lens is scanning.
287b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        if (mLastResultAFState == AutoFocusState.ACTIVE_SCAN) {
28830ffce08f511fbed4cf18daa743778b541583351Andy Huibers            Log.v(TAG, "Waiting until scan is done before taking shot.");
28930ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mTakePictureWhenLensIsStopped = true;
29030ffce08f511fbed4cf18daa743778b541583351Andy Huibers        } else {
291b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers            // We could do CONTROL_AF_TRIGGER_START and wait until lens locks,
292b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers            // but this would slow down the capture.
29330ffce08f511fbed4cf18daa743778b541583351Andy Huibers            takePictureNow(params, session);
29430ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
29530ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
29630ffce08f511fbed4cf18daa743778b541583351Andy Huibers
29730ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
29851163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling     * Take picture immediately. Parameters passed through from takePicture().
29930ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
30030ffce08f511fbed4cf18daa743778b541583351Andy Huibers    public void takePictureNow(PhotoCaptureParameters params, CaptureSession session) {
30130ffce08f511fbed4cf18daa743778b541583351Andy Huibers        long dt = SystemClock.uptimeMillis() - mTakePictureStartMillis;
30230ffce08f511fbed4cf18daa743778b541583351Andy Huibers        Log.v(TAG, "Taking shot with extra AF delay of " + dt + " ms.");
30357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        // This will throw a RuntimeException, if parameters are not sane.
30457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        params.checkSanity();
305f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        try {
30630ffce08f511fbed4cf18daa743778b541583351Andy Huibers            // JPEG capture.
307f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            CaptureRequest.Builder builder = mDevice
308f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    .createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
30930ffce08f511fbed4cf18daa743778b541583351Andy Huibers            builder.setTag(RequestTag.CAPTURE);
31026b3334755ffccc039249005435d5cc598d0689eAndy Huibers            addBaselineCaptureKeysToRequest(builder);
311967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
312967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            if (sCaptureImageFormat == ImageFormat.JPEG) {
313967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall                builder.set(CaptureRequest.JPEG_QUALITY, JPEG_QUALITY);
314a2dd9ea5ba031128b9f0aa3852ff59991dd3008cSascha Haeberling                builder.set(CaptureRequest.JPEG_ORIENTATION,
315a2dd9ea5ba031128b9f0aa3852ff59991dd3008cSascha Haeberling                        CameraUtil.getJpegRotation(params.orientation, mCharacteristics));
316967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            }
317967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
318f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            builder.addTarget(mPreviewSurface);
319967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            builder.addTarget(mCaptureImageReader.getSurface());
3200cf4a02c13a7710dc9b26ac39bea15a95ac48bafSascha Haeberling            CaptureRequest request = builder.build();
32151163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling
32251163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling            if (DEBUG_WRITE_CAPTURE_DATA) {
32351163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                final String debugDataDir = makeDebugDir(params.debugDataFolder,
32451163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                        "normal_capture_debug");
32551163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                Log.i(TAG, "Writing capture data to: " + debugDataDir);
32651163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                CaptureDataSerializer.toFile("Normal Capture", request, new File(debugDataDir,
32751163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling                        "capture.txt"));
32851163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling            }
32951163540604bcb1deabfde4d83c54a86114cefd0Sascha Haeberling
33030ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mCaptureSession.capture(request, mAutoFocusStateListener, mCameraHandler);
331f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        } catch (CameraAccessException e) {
332967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            Log.e(TAG, "Could not access camera for still image capture.");
333e3ad4352a23ddb21350d356e0947905d1e635911Sascha Haeberling            broadcastReadyState(true);
334f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            params.callback.onPictureTakenFailed();
335f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            return;
336f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        }
33757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        mCaptureQueue.add(new InFlightCapture(params, session));
338f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
339f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
340f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
341f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    public void startPreview(Surface previewSurface, CaptureReadyCallback listener) {
342f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mPreviewSurface = previewSurface;
343f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        setupAsync(mPreviewSurface, listener);
344f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
345f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
346f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
3479cefdd495332719d987ffb942742ec602793d8d4Jiawen Chen    public void setViewfinderSize(int width, int height) {
348f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        throw new RuntimeException("Not implemented yet.");
349f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
350f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
351f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
352f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    public boolean isFlashSupported(boolean enhanced) {
353f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        throw new RuntimeException("Not implemented yet.");
354f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
355f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
356f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
357f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    public boolean isSupportingEnhancedMode() {
358f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        throw new RuntimeException("Not implemented yet.");
359f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
360f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
361f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
362f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    public void close(CloseCallback closeCallback) {
363f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        if (mIsClosed) {
364f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            Log.w(TAG, "Camera is already closed.");
365f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            return;
366f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        }
36730ffce08f511fbed4cf18daa743778b541583351Andy Huibers        try {
36830ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mCaptureSession.abortCaptures();
36930ffce08f511fbed4cf18daa743778b541583351Andy Huibers        } catch (CameraAccessException e) {
37030ffce08f511fbed4cf18daa743778b541583351Andy Huibers            Log.e(TAG, "Could not abort captures in progress.");
37130ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
372f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mIsClosed = true;
373f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCloseCallback = closeCallback;
374f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCameraThread.quitSafely();
375f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mDevice.close();
376f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
377f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
378f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
379f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    public Size[] getSupportedSizes() {
380f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        StreamConfigurationMap config = mCharacteristics
381f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
382967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        return Size.convert(config.getOutputSizes(sCaptureImageFormat));
383f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
384f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
385f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    @Override
3869cefdd495332719d987ffb942742ec602793d8d4Jiawen Chen    public float getFullSizeAspectRatio() {
387f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        return mFullSizeAspectRatio;
388f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
389f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
39057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    @Override
39157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    public boolean isFrontFacing() {
39257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
39357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                == CameraMetadata.LENS_FACING_FRONT;
39457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    }
39557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
39657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    @Override
39757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    public boolean isBackFacing() {
39857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        return mCharacteristics.get(CameraCharacteristics.LENS_FACING)
39957bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                == CameraMetadata.LENS_FACING_BACK;
40057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    }
40157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
40257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    private void savePicture(byte[] jpegData, final PhotoCaptureParameters captureParams,
40357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            CaptureSession session) {
40457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        int heading = captureParams.heading;
40557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        int width = 0;
40657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        int height = 0;
40757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        int rotation = 0;
40857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        ExifInterface exif = null;
40957bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        try {
41057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            exif = new ExifInterface();
41157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            exif.readExif(jpegData);
41257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
41357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            Integer w = exif.getTagIntValue(ExifInterface.TAG_PIXEL_X_DIMENSION);
41457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            width = (w == null) ? width : w;
41557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            Integer h = exif.getTagIntValue(ExifInterface.TAG_PIXEL_Y_DIMENSION);
41657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            height = (h == null) ? height : h;
41757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
41857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            // Get image rotation from EXIF.
41957bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            rotation = Exif.getOrientation(exif);
42057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
42157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            // Set GPS heading direction based on sensor, if location is on.
42257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            if (heading >= 0) {
42357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                ExifTag directionRefTag = exif.buildTag(
42457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                        ExifInterface.TAG_GPS_IMG_DIRECTION_REF,
42557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                        ExifInterface.GpsTrackRef.MAGNETIC_DIRECTION);
42657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                ExifTag directionTag = exif.buildTag(
42757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                        ExifInterface.TAG_GPS_IMG_DIRECTION,
42857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                        new Rational(heading, 1));
42957bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                exif.setTag(directionRefTag);
43057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                exif.setTag(directionTag);
43157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            }
43257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        } catch (IOException e) {
43357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            Log.w(TAG, "Could not read exif from gcam jpeg", e);
43457bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            exif = null;
43557bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        }
43657bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        session.saveAndFinish(jpegData, width, height, rotation, exif, new OnMediaSavedListener() {
43757bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            @Override
43857bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            public void onMediaSaved(Uri uri) {
43957bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling                captureParams.callback.onPictureSaved(uri);
44057bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling            }
44157bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling        });
44257bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling    }
44357bcd92f39d85427102f30be2c749c4a7bd4be96Sascha Haeberling
444f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
445f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * Asynchronously sets up the capture session.
446f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *
447f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param previewSurface the surface onto which the preview should be
448f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *            rendered.
449f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param listener called when setup is completed.
450f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
451f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private void setupAsync(final Surface previewSurface, final CaptureReadyCallback listener) {
452f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        mCameraHandler.post(new Runnable() {
453f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            @Override
454f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            public void run() {
455f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                setup(previewSurface, listener);
456f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            }
457f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        });
458f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
459f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
460f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
461f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * Configures and attempts to create a capture session.
462f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *
463f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param previewSurface the surface onto which the preview should be
464f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *            rendered.
465f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param listener called when the setup is completed.
466f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
467f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private void setup(Surface previewSurface, final CaptureReadyCallback listener) {
468f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        try {
469f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            if (mCaptureSession != null) {
470f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                mCaptureSession.abortCaptures();
471f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                mCaptureSession = null;
472f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            }
473f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            List<Surface> outputSurfaces = new ArrayList<Surface>(2);
474f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            outputSurfaces.add(previewSurface);
475967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            outputSurfaces.add(mCaptureImageReader.getSurface());
476f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
47776215c98a9a11d87b5ce9d2b4198654c2b8bbddfAlan Newberger            mDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
478f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
479f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                @Override
480f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                public void onConfigureFailed(CameraCaptureSession session) {
481f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    listener.onSetupFailed();
482f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                }
483f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
484f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                @Override
485f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                public void onConfigured(CameraCaptureSession session) {
486f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    mCaptureSession = session;
487b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    mAFRegions = ZERO_WEIGHT_3A_REGION;
488b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                    mAERegions = ZERO_WEIGHT_3A_REGION;
48926b3334755ffccc039249005435d5cc598d0689eAndy Huibers                    mZoomValue = 1f;
49026b3334755ffccc039249005435d5cc598d0689eAndy Huibers                    mCropRegion = cropRegionForZoom(mZoomValue);
49126b3334755ffccc039249005435d5cc598d0689eAndy Huibers                    boolean success = repeatingPreview(null);
49226b3334755ffccc039249005435d5cc598d0689eAndy Huibers                    if (success) {
49326b3334755ffccc039249005435d5cc598d0689eAndy Huibers                        listener.onReadyForCapture();
49426b3334755ffccc039249005435d5cc598d0689eAndy Huibers                    } else {
49526b3334755ffccc039249005435d5cc598d0689eAndy Huibers                        listener.onSetupFailed();
49626b3334755ffccc039249005435d5cc598d0689eAndy Huibers                    }
497f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                }
498f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
499f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                @Override
500f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                public void onClosed(CameraCaptureSession session) {
501f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    super.onClosed(session);
502f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    if (mCloseCallback != null) {
503f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                        mCloseCallback.onCameraClosed();
504f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                    }
505f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                }
506f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            }, mCameraHandler);
507f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        } catch (CameraAccessException ex) {
508f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            Log.e(TAG, "Could not set up capture session", ex);
509f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            listener.onSetupFailed();
510f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        }
511f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
512f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
513f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
51426b3334755ffccc039249005435d5cc598d0689eAndy Huibers     * Adds current regions to CaptureRequest and base AF mode + AF_TRIGGER_IDLE.
51526b3334755ffccc039249005435d5cc598d0689eAndy Huibers     *
51626b3334755ffccc039249005435d5cc598d0689eAndy Huibers     * @param builder Build for the CaptureRequest
51726b3334755ffccc039249005435d5cc598d0689eAndy Huibers     */
51826b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private void addBaselineCaptureKeysToRequest(CaptureRequest.Builder builder) {
519b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        builder.set(CaptureRequest.CONTROL_AF_REGIONS, mAFRegions);
520b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        builder.set(CaptureRequest.CONTROL_AE_REGIONS, mAERegions);
52126b3334755ffccc039249005435d5cc598d0689eAndy Huibers        builder.set(CaptureRequest.SCALER_CROP_REGION, mCropRegion);
52226b3334755ffccc039249005435d5cc598d0689eAndy Huibers        builder.set(CaptureRequest.CONTROL_AF_MODE, mControlAFMode);
52326b3334755ffccc039249005435d5cc598d0689eAndy Huibers        builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
524b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // Enable face detection
525b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        builder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE,
526b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                CaptureRequest.STATISTICS_FACE_DETECT_MODE_FULL);
527b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        builder.set(CaptureRequest.CONTROL_SCENE_MODE,
528b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                CaptureRequest.CONTROL_SCENE_MODE_FACE_PRIORITY);
52926b3334755ffccc039249005435d5cc598d0689eAndy Huibers    }
53026b3334755ffccc039249005435d5cc598d0689eAndy Huibers
53126b3334755ffccc039249005435d5cc598d0689eAndy Huibers    /**
53230ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * Request preview capture stream with AF_MODE_CONTINUOUS_PICTURE.
533f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *
53426b3334755ffccc039249005435d5cc598d0689eAndy Huibers     * @return true if request was build and sent successfully.
53526b3334755ffccc039249005435d5cc598d0689eAndy Huibers     * @param tag
536f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
53726b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private boolean repeatingPreview(Object tag) {
538f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        try {
53930ffce08f511fbed4cf18daa743778b541583351Andy Huibers            CaptureRequest.Builder builder = mDevice.
54030ffce08f511fbed4cf18daa743778b541583351Andy Huibers                    createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
54130ffce08f511fbed4cf18daa743778b541583351Andy Huibers            builder.addTarget(mPreviewSurface);
542f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
54326b3334755ffccc039249005435d5cc598d0689eAndy Huibers            addBaselineCaptureKeysToRequest(builder);
54430ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mCaptureSession.setRepeatingRequest(builder.build(), mAutoFocusStateListener,
54530ffce08f511fbed4cf18daa743778b541583351Andy Huibers                    mCameraHandler);
54626b3334755ffccc039249005435d5cc598d0689eAndy Huibers            Log.v(TAG, String.format("Sent repeating Preview request, zoom = %.2f", mZoomValue));
54726b3334755ffccc039249005435d5cc598d0689eAndy Huibers            return true;
54830ffce08f511fbed4cf18daa743778b541583351Andy Huibers        } catch (CameraAccessException ex) {
54930ffce08f511fbed4cf18daa743778b541583351Andy Huibers            Log.e(TAG, "Could not access camera setting up preview.", ex);
55026b3334755ffccc039249005435d5cc598d0689eAndy Huibers            return false;
55130ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
55230ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
55330ffce08f511fbed4cf18daa743778b541583351Andy Huibers
55430ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
55526b3334755ffccc039249005435d5cc598d0689eAndy Huibers     * Request preview capture stream with auto focus trigger cycle.
55630ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
55726b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private void sendAutoFocusTriggerCaptureRequest(Object tag) {
55830ffce08f511fbed4cf18daa743778b541583351Andy Huibers        try {
55926b3334755ffccc039249005435d5cc598d0689eAndy Huibers            // Step 1: Request single frame CONTROL_AF_TRIGGER_START.
56030ffce08f511fbed4cf18daa743778b541583351Andy Huibers            CaptureRequest.Builder builder;
56130ffce08f511fbed4cf18daa743778b541583351Andy Huibers            builder = mDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
562f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling            builder.addTarget(mPreviewSurface);
56330ffce08f511fbed4cf18daa743778b541583351Andy Huibers            builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
56426b3334755ffccc039249005435d5cc598d0689eAndy Huibers            mControlAFMode = CameraMetadata.CONTROL_AF_MODE_AUTO;
56526b3334755ffccc039249005435d5cc598d0689eAndy Huibers            addBaselineCaptureKeysToRequest(builder);
56630ffce08f511fbed4cf18daa743778b541583351Andy Huibers            builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
56726b3334755ffccc039249005435d5cc598d0689eAndy Huibers            builder.setTag(tag);
56830ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mCaptureSession.capture(builder.build(), mAutoFocusStateListener, mCameraHandler);
56930ffce08f511fbed4cf18daa743778b541583351Andy Huibers
57026b3334755ffccc039249005435d5cc598d0689eAndy Huibers            // Step 2: Call repeatingPreview to update mControlAFMode.
57126b3334755ffccc039249005435d5cc598d0689eAndy Huibers            repeatingPreview(tag);
57230ffce08f511fbed4cf18daa743778b541583351Andy Huibers            resumeContinuousAFAfterDelay(FOCUS_HOLD_MILLIS);
57330ffce08f511fbed4cf18daa743778b541583351Andy Huibers        } catch (CameraAccessException ex) {
57430ffce08f511fbed4cf18daa743778b541583351Andy Huibers            Log.e(TAG, "Could not execute preview request.", ex);
57530ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
57630ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
57730ffce08f511fbed4cf18daa743778b541583351Andy Huibers
57830ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
57930ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * Resume AF_MODE_CONTINUOUS_PICTURE after FOCUS_HOLD_MILLIS.
58030ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
58130ffce08f511fbed4cf18daa743778b541583351Andy Huibers    private void resumeContinuousAFAfterDelay(int millis) {
58230ffce08f511fbed4cf18daa743778b541583351Andy Huibers        mCameraHandler.removeCallbacks(mReturnToContinuousAFRunnable);
58330ffce08f511fbed4cf18daa743778b541583351Andy Huibers        mCameraHandler.postDelayed(mReturnToContinuousAFRunnable, millis);
58430ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
58530ffce08f511fbed4cf18daa743778b541583351Andy Huibers
58630ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
58730ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * This method takes appropriate action if camera2 AF state changes.
58830ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * <ol>
58930ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * <li>Reports changes in camera2 AF state to OneCamera.FocusStateListener.</li>
590b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers     * <li>Take picture after AF scan if mTakePictureWhenLensIsStopped true.</li>
59130ffce08f511fbed4cf18daa743778b541583351Andy Huibers     * </ol>
59230ffce08f511fbed4cf18daa743778b541583351Andy Huibers     */
59330ffce08f511fbed4cf18daa743778b541583351Andy Huibers    private void autofocusStateChangeDispatcher(CaptureResult result) {
594b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        if (result.getFrameNumber() < mLastControlAfStateFrameNumber ||
595b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                result.get(CaptureResult.CONTROL_AF_STATE) == null) {
596b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers            return;
597b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        }
598b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        mLastControlAfStateFrameNumber = result.getFrameNumber();
59930ffce08f511fbed4cf18daa743778b541583351Andy Huibers
60030ffce08f511fbed4cf18daa743778b541583351Andy Huibers        // Convert to OneCamera mode and state.
601b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        AutoFocusState resultAFState = AutoFocusHelper.
602b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                stateFromCamera2State(result.get(CaptureResult.CONTROL_AF_STATE));
603b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers
604b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // TODO: Consider using LENS_STATE.
605b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        boolean lensIsStopped = resultAFState == AutoFocusState.ACTIVE_FOCUSED ||
606b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                resultAFState == AutoFocusState.ACTIVE_UNFOCUSED ||
607b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                resultAFState == AutoFocusState.PASSIVE_FOCUSED ||
608b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers                resultAFState == AutoFocusState.PASSIVE_UNFOCUSED;
60930ffce08f511fbed4cf18daa743778b541583351Andy Huibers
61030ffce08f511fbed4cf18daa743778b541583351Andy Huibers        if (mTakePictureWhenLensIsStopped && lensIsStopped) {
61130ffce08f511fbed4cf18daa743778b541583351Andy Huibers            // Take the shot.
61230ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mCameraHandler.post(mTakePictureRunnable);
61330ffce08f511fbed4cf18daa743778b541583351Andy Huibers            mTakePictureWhenLensIsStopped = false;
61430ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
61530ffce08f511fbed4cf18daa743778b541583351Andy Huibers
616b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        // Report state change when AF state has changed.
617b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        if (resultAFState != mLastResultAFState && mFocusStateListener != null) {
618ca3c564536f154b83e380e37382bc7b9f6049302Andy Huibers            mFocusStateListener.onFocusStatusUpdate(resultAFState, result.getFrameNumber());
61930ffce08f511fbed4cf18daa743778b541583351Andy Huibers        }
62030ffce08f511fbed4cf18daa743778b541583351Andy Huibers        mLastResultAFState = resultAFState;
62130ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
62230ffce08f511fbed4cf18daa743778b541583351Andy Huibers
62330ffce08f511fbed4cf18daa743778b541583351Andy Huibers    @Override
62430ffce08f511fbed4cf18daa743778b541583351Andy Huibers    public void triggerFocusAndMeterAtPoint(float nx, float ny) {
6250971376b0ddf12c8aa886ad9109f6a8929095154Jiawen Chen        int sensorOrientation = mCharacteristics.get(
6260971376b0ddf12c8aa886ad9109f6a8929095154Jiawen Chen            CameraCharacteristics.SENSOR_ORIENTATION);
6270971376b0ddf12c8aa886ad9109f6a8929095154Jiawen Chen        mAERegions = AutoFocusHelper.aeRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation);
6280971376b0ddf12c8aa886ad9109f6a8929095154Jiawen Chen        mAFRegions = AutoFocusHelper.afRegionsForNormalizedCoord(nx, ny, mCropRegion, sensorOrientation);
62930ffce08f511fbed4cf18daa743778b541583351Andy Huibers
63026b3334755ffccc039249005435d5cc598d0689eAndy Huibers        sendAutoFocusTriggerCaptureRequest(RequestTag.TAP_TO_FOCUS);
63126b3334755ffccc039249005435d5cc598d0689eAndy Huibers    }
63226b3334755ffccc039249005435d5cc598d0689eAndy Huibers
63326b3334755ffccc039249005435d5cc598d0689eAndy Huibers    @Override
63426b3334755ffccc039249005435d5cc598d0689eAndy Huibers    public float getMaxZoom() {
63526b3334755ffccc039249005435d5cc598d0689eAndy Huibers        return mCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
63626b3334755ffccc039249005435d5cc598d0689eAndy Huibers    }
63726b3334755ffccc039249005435d5cc598d0689eAndy Huibers
63826b3334755ffccc039249005435d5cc598d0689eAndy Huibers    @Override
63926b3334755ffccc039249005435d5cc598d0689eAndy Huibers    public void setZoom(float zoom) {
64026b3334755ffccc039249005435d5cc598d0689eAndy Huibers        mZoomValue = zoom;
64126b3334755ffccc039249005435d5cc598d0689eAndy Huibers        mCropRegion = cropRegionForZoom(zoom);
64226b3334755ffccc039249005435d5cc598d0689eAndy Huibers        repeatingPreview(null);
64326b3334755ffccc039249005435d5cc598d0689eAndy Huibers    }
64426b3334755ffccc039249005435d5cc598d0689eAndy Huibers
645cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling    @Override
646cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling    public Size pickPreviewSize(Size pictureSize, Context context) {
647cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling        float pictureAspectRatio = pictureSize.getWidth() / (float) pictureSize.getHeight();
648cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling        return CaptureModuleUtil.getOptimalPreviewSize(context, getSupportedSizes(),
649cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling                pictureAspectRatio);
650cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling    }
651cbe861edcd0d094ee79d3eeaac48bb928017b600Sascha Haeberling
65226b3334755ffccc039249005435d5cc598d0689eAndy Huibers    private Rect cropRegionForZoom(float zoom) {
653b868274c9dc8d9c772ec89fb5955215cc7911087Andy Huibers        return AutoFocusHelper.cropRegionForZoom(mCharacteristics, zoom);
65430ffce08f511fbed4cf18daa743778b541583351Andy Huibers    }
65530ffce08f511fbed4cf18daa743778b541583351Andy Huibers
65630ffce08f511fbed4cf18daa743778b541583351Andy Huibers    /**
657f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * Calculate the aspect ratio of the full size capture on this device.
658f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *
659f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param characteristics the characteristics of the camera device.
660f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @return The aspect ration, in terms of width/height of the full capture
661f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *         size.
662f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
6639cefdd495332719d987ffb942742ec602793d8d4Jiawen Chen    private static float calculateFullSizeAspectRatio(CameraCharacteristics characteristics) {
664f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        Rect activeArraySize =
665f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling                characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
6669cefdd495332719d987ffb942742ec602793d8d4Jiawen Chen        return ((float)(activeArraySize.width())) / activeArraySize.height();
667f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
668f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
669f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    /**
670f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * Given an image reader, extracts the JPEG image bytes and then closes the
671f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * reader.
672f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     *
673f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @param reader the reader to read the JPEG data from.
674f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     * @return The bytes of the JPEG image. Newly allocated.
675f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling     */
676f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    private static byte[] acquireJpegBytesAndClose(ImageReader reader) {
677f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        Image img = reader.acquireLatestImage();
678967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
679967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        ByteBuffer buffer;
680967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
681967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        if (img.getFormat() == ImageFormat.JPEG) {
682967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            Image.Plane plane0 = img.getPlanes()[0];
683967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            buffer = plane0.getBuffer();
684967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        } else if (img.getFormat() == ImageFormat.YUV_420_888) {
685967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            buffer = ByteBuffer.allocateDirect(img.getWidth() * img.getHeight() * 3);
686967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
687967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            Log.v(TAG, "Compressing JPEG with software encoder.");
688967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            int numBytes = JpegUtilNative.compressJpegFromYUV420Image(img, buffer, JPEG_QUALITY);
689967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
690967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            if (numBytes < 0) {
691967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall                throw new RuntimeException("Error compressing jpeg.");
692967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            }
693967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall
694967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            buffer.limit(numBytes);
695967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        } else {
696967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall            throw new RuntimeException("Unsupported image format.");
697967b782837a22974f565f5bbc71bef7bc05fc878Puneet Lall        }
698f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling
699f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        byte[] imageBytes = new byte[buffer.remaining()];
700f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        buffer.get(imageBytes);
701f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        buffer.rewind();
702f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        img.close();
703f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling        return imageBytes;
704f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling    }
705f5e51ec44934d6d687267d2aff6386f5b728dd9fSascha Haeberling}
706