1b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford/*
2b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * Copyright (C) 2015 The Android Open Source Project
3b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford *
4b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * Licensed under the Apache License, Version 2.0 (the "License");
5b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * you may not use this file except in compliance with the License.
6b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * You may obtain a copy of the License at
7b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford *
8b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford *      http://www.apache.org/licenses/LICENSE-2.0
9b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford *
10b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * Unless required by applicable law or agreed to in writing, software
11b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * distributed under the License is distributed on an "AS IS" BASIS,
12b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * See the License for the specific language governing permissions and
14b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * limitations under the License.
15b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford */
16b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
17b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordpackage com.android.example.cannylive;
18b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
19b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.content.Context;
20b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.graphics.ImageFormat;
21b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.CameraAccessException;
22b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.CameraCaptureSession;
23b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.CameraCharacteristics;
24b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.CameraDevice;
25b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.CameraManager;
26b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.CaptureRequest;
27b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.TotalCaptureResult;
28b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.hardware.camera2.params.StreamConfigurationMap;
29b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.media.Image;
30b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.media.ImageReader;
31b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.os.ConditionVariable;
32b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.os.Handler;
33b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.os.HandlerThread;
34b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.os.Looper;
35b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.util.Log;
36b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.util.Range;
37b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.util.Size;
38b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.view.Surface;
39b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport android.view.SurfaceHolder;
40b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
41b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.io.IOException;
42b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.io.OutputStream;
43b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.nio.ByteBuffer;
44b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.util.ArrayList;
45b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.util.Arrays;
46b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.util.Collections;
47b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.util.Comparator;
48b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordimport java.util.List;
49b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
50b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford/**
51b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * Simple interface for operating the camera, with major camera operations
52b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford * all performed on a background handler thread.
53b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford */
54b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehofordpublic class CameraOps {
55b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
56b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private static final String TAG = "CameraOps";
57b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private static final long ONE_SECOND = 1000000000;
58b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public static final long CAMERA_CLOSE_TIMEOUT = 2000; // ms
59b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
60b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private final CameraManager mCameraManager;
61b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private CameraDevice mCameraDevice;
62b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private CameraCaptureSession mCameraSession;
63b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private List<Surface> mSurfaces;
64b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
65b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private final ConditionVariable mCloseWaiter = new ConditionVariable();
66b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
67b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private HandlerThread mCameraThread;
68b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private Handler mCameraHandler;
69b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
70b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private final ErrorDisplayer mErrorDisplayer;
71b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
72b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private final CameraReadyListener mReadyListener;
73b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private final Handler mReadyHandler;
74b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
75b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private int mISOmax;
76b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private int mISOmin;
77b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private long mExpMax;
78b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private long mExpMin;
79b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private float mFocusMin;
80b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private float mFocusDist = 0;
81b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private int mIso;
82b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    boolean mAutoExposure = true;
83b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    boolean mAutoFocus = true;
84b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private long mExposure = ONE_SECOND / 33;
85b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
86b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private Object mAutoExposureTag = new Object();
87b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
88b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private ImageReader mImageReader;
89b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private Handler mBackgroundHandler;
90b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private CameraCharacteristics mCameraInfo;
91b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private HandlerThread mBackgroundThread;
92b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    CaptureRequest.Builder mHdrBuilder;
93b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private Surface mProcessingNormalSurface;
94b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    CaptureRequest mPreviewRequest;
95b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private String mSaveFileName;
96b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private Context mContext;
97b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private int mCaptureMode;
98b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
99b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public String resume() {
100b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        String errorMessage = "Unknown error";
101b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        boolean foundCamera = false;
102b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        try {
103b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            // Find first back-facing camera that has necessary capability
104b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            String[] cameraIds = mCameraManager.getCameraIdList();
105b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            for (String id : cameraIds) {
106b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id);
107b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                int facing = info.get(CameraCharacteristics.LENS_FACING);
108b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
109b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                int level = info.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
110b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                boolean hasFullLevel
111b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        = (level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
112b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
113b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                int[] capabilities = info.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
114b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                int syncLatency = info.get(CameraCharacteristics.SYNC_MAX_LATENCY);
115b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                boolean hasManualControl = hasCapability(capabilities,
116b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
117b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                boolean hasEnoughCapability = hasManualControl &&
118b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        syncLatency == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL;
119b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Range<Integer> irange;
120b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Range<Long> lrange;
121b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
122b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                irange = info.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE);
123b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                if (irange != null) {
124b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mISOmax = irange.getUpper();
125b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mISOmin = irange.getLower();
126b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    lrange = info.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
127b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mExpMax = lrange.getUpper();
128b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mExpMin = lrange.getLower();
129b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mFocusMin = info.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE);
130b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                } else {
131b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mISOmax = 200;
132b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mISOmin = 100;
133b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mExpMax = 1000;
134b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
135b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                mFocusDist = mFocusMin;
136b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                StreamConfigurationMap map = info.get(
137b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
138b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Size[] sizes = map.getOutputSizes(ImageFormat.JPEG);
139b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                List<Size> sizeList = Arrays.asList(sizes);
140b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Collections.sort(sizeList, new Comparator<Size>() {
141b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    @Override
142b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    public int compare(Size lhs, Size rhs) {
143b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        int leftArea = lhs.getHeight() * lhs.getWidth();
144b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        int rightArea = lhs.getHeight() * lhs.getWidth();
145b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        return Integer.compare(leftArea, rightArea);
146b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    }
147b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                });
148b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Size max = sizeList.get(0);
149b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                int check = 1;
150b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Size big = sizeList.get(check);
151b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                float aspect = 16/9f;
152b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Log.v(TAG,"max big "+max.getWidth()+" x "+max.getHeight());
153b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                for (int i = 0; i < sizeList.size(); i++) {
154b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    Size s = sizeList.get(i);
155b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    if (s.getHeight() == 720) {
156b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        big = s;
157b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        break;
158b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    }
159b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
160b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Log.v(TAG,"BIG wil be "+big.getWidth()+" x "+big.getHeight());
161b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                mImageReader = ImageReader.newInstance(big.getWidth(), big.getHeight(),
162b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        ImageFormat.JPEG, /*maxImages*/2);
163b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                mImageReader.setOnImageAvailableListener(
164b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        mOnImageAvailableListener, mBackgroundHandler);
165b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
166b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                if (facing == CameraCharacteristics.LENS_FACING_BACK &&
167b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        (hasFullLevel || hasEnoughCapability)) {
168b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    // Found suitable camera - get info, open, and set up outputs
169b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraInfo = info;
170b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    openCamera(id);
171b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    foundCamera = true;
172b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    break;
173b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
174b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
175b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            if (!foundCamera) {
176b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                errorMessage = "no back camera";
177b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
178b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } catch (CameraAccessException e) {
179b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            errorMessage = e.getMessage();
180b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
181b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        // startBackgroundThread
182b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mBackgroundThread = new HandlerThread("CameraBackground");
183b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mBackgroundThread.start();
184b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
185b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return (foundCamera) ? null : errorMessage;
186b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
187b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
188b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
189b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private boolean hasCapability(int[] capabilities, int capability) {
190b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        for (int c : capabilities) {
191b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            if (c == capability) return true;
192b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
193b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return false;
194b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
195b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
196b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
197b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            = new ImageReader.OnImageAvailableListener() {
198b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
199b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        @Override
200b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onImageAvailable(ImageReader reader) {
201b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(),
202b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mSaveFileName, mContext,mCaptureMode));
203b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
204b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
205b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    };
206b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
207b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
208b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Saves a JPEG {@link android.media.Image} into the specified {@link java.io.File}.
209b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
210b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private static class ImageSaver implements Runnable {
211b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        private final Image mImage;
212b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        private final String mName;
213b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        Context mContext;
214b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        private int mMode;
215b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
216b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public ImageSaver(Image image, String fileName, Context context,int mode) {
217b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mImage = image;
218b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mName = fileName;
219b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mContext = context;
220b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mMode = mode;
221b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
222b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
223b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        @Override
224b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void run() {
225b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            Log.v(TAG, "S>> SAVING...");
226b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            String url = MediaStoreSaver.insertImage(mContext.getContentResolver(),
227b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    new MediaStoreSaver.StreamWriter() {
228b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        @Override
229b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        public void write(OutputStream imageOut) throws IOException {
230b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            try {
231b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
232b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                byte[] bytes = new byte[buffer.remaining()];
233b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                Log.v(TAG, "S>> size=" + mImage.getWidth() +
234b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                        "," + mImage.getHeight());
235b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                Log.v(TAG, "S>> bytes " + bytes.length +
236b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                        " (" + bytes.length / (1024 * 1024) + "MB");
237b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                Log.v(TAG, "S>> bytes out " + bytes.length / mImage.getWidth());
238b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                buffer.get(bytes);
239b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                imageOut.write(bytes);
240b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            } finally {
241b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                mImage.close();
242b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            }
243b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        }
244b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    }, mName, "Saved from Simple Camera Demo");
245b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            ViewfinderProcessor.reProcessImage(mContext, url, mMode);
246b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
247b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
248b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
249b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
250b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Create a new camera ops thread.
251b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     *
252b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * @param errorDisplayer listener for displaying error messages
253b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * @param readyListener  listener for notifying when camera is ready for requests
254b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
255b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    CameraOps(CameraManager manager, ErrorDisplayer errorDisplayer,
256b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford              CameraReadyListener readyListener) {
257b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mReadyHandler = new Handler(Looper.getMainLooper());
258b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
259b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraThread = new HandlerThread("CameraOpsThread");
260b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraThread.start();
261b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
262b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (manager == null || errorDisplayer == null ||
263b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                readyListener == null || mReadyHandler == null) {
264b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            throw new IllegalArgumentException("Need valid displayer, listener, handler");
265b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
266b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
267b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraManager = manager;
268b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mErrorDisplayer = errorDisplayer;
269b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mReadyListener = readyListener;
270b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
271b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
272b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
273b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
274b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Open the first backfacing camera listed by the camera manager.
275b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Displays a dialog if it cannot open a camera.
276b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
277b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void openCamera(final String cameraId) {
278b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler = new Handler(mCameraThread.getLooper());
279b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
280b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler.post(new Runnable() {
281b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            public void run() {
282b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                if (mCameraDevice != null) {
283b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    throw new IllegalStateException("Camera already open");
284b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
285b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                try {
286b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
287b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraManager.openCamera(cameraId, mCameraDeviceListener, mCameraHandler);
288b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                } catch (CameraAccessException e) {
289b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    String errorMessage = mErrorDisplayer.getErrorString(e);
290b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mErrorDisplayer.showErrorDialog(errorMessage);
291b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
292b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
293b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        });
294b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
295b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
296b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void pause() {
297b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
298b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        closeCameraAndWait();
299b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mBackgroundThread.quitSafely();
300b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        try {
301b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mBackgroundThread.join();
302b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mBackgroundThread = null;
303b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mBackgroundHandler = null;
304b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } catch (InterruptedException e) {
305b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            e.printStackTrace();
306b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
307b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
308b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
309b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public Size getBestSize() {
310b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        // Find a good size for output - largest 16:9 aspect ratio that's less than 720p
311b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        final int MAX_WIDTH = 640;
312b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        final float TARGET_ASPECT = 16.f / 9.f;
313b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
314b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
315b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        StreamConfigurationMap configs =
316b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                mCameraInfo.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
317b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
318b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        Size[] outputSizes = configs.getOutputSizes(SurfaceHolder.class);
319b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
320b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        Size outputSize = null;
321b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        ArrayList<Size> smallEnough = new ArrayList<Size>();
322b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        for (Size candidateSize : outputSizes) {
323b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            if (candidateSize.getWidth() <= MAX_WIDTH) {
324b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                Log.v(TAG, "consider " + candidateSize);
325b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                smallEnough.add(candidateSize);
326b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
327b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
328b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (smallEnough.size() == 0) {
329b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            return outputSizes[outputSizes.length - 1]; //pick the smallest
330b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
331b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        Size maxSize = smallEnough.get(0);
332b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        double aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT);
333b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        for (Size candidateSize : smallEnough) {
334b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            if (maxSize.getWidth() < candidateSize.getWidth()) {
335b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                maxSize = candidateSize;
336b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT);
337b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
338b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            if (maxSize.getWidth() == candidateSize.getWidth()) {
339b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                if (aspectDelta > Math.abs(candidateSize.getWidth() / candidateSize.getHeight() - TARGET_ASPECT)) {
340b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    maxSize = candidateSize;
341b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    aspectDelta = Math.abs(maxSize.getWidth() / maxSize.getHeight() - TARGET_ASPECT);
342b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
343b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
344b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
345b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
346b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return maxSize;
347b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
348b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
349b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
350b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Close the camera and wait for the close callback to be called in the camera thread.
351b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Times out after @{value CAMERA_CLOSE_TIMEOUT} ms.
352b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
353b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void closeCameraAndWait() {
354b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCloseWaiter.close();
355b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler.post(mCloseCameraRunnable);
356b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        boolean closed = mCloseWaiter.block(CAMERA_CLOSE_TIMEOUT);
357b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (!closed) {
358b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            Log.e(TAG, "Timeout closing camera");
359b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
360b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
361b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
362b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private Runnable mCloseCameraRunnable = new Runnable() {
363b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void run() {
364b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            if (mCameraDevice != null) {
365b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                mCameraDevice.close();
366b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
367b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice = null;
368b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraSession = null;
369b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mSurfaces = null;
370b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
371b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    };
372b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
373b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
374b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Set the output Surfaces, and finish configuration if otherwise ready.
375b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
376b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setSurface(Surface surface) {
377b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        final List<Surface> surfaceList = new ArrayList<Surface>();
378b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        surfaceList.add(surface);
379b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        surfaceList.add(mImageReader.getSurface());
380b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
381b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler.post(new Runnable() {
382b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            public void run() {
383b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                mSurfaces = surfaceList;
384b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                startCameraSession();
385b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
386b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        });
387b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
388b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
389b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
390b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Get a request builder for the current camera.
391b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
392b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public CaptureRequest.Builder createCaptureRequest(int template) throws CameraAccessException {
393b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        CameraDevice device = mCameraDevice;
394b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (device == null) {
395b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            throw new IllegalStateException("Can't get requests when no camera is open");
396b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
397b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return device.createCaptureRequest(template);
398b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
399b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
400b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
401b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Set a repeating request.
402b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
403b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setRepeatingRequest(final CaptureRequest request,
404b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                    final CameraCaptureSession.CaptureCallback listener,
405b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                    final Handler handler) {
406b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler.post(new Runnable() {
407b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            public void run() {
408b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                try {
409b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraSession.setRepeatingRequest(request, listener, handler);
410b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                } catch (CameraAccessException e) {
411b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    String errorMessage = mErrorDisplayer.getErrorString(e);
412b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mErrorDisplayer.showErrorDialog(errorMessage);
413b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
414b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
415b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        });
416b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
417b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
418b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
419b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Set a repeating request.
420b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
421b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setRepeatingBurst(final List<CaptureRequest> requests,
422b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                  final CameraCaptureSession.CaptureCallback listener,
423b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                  final Handler handler) {
424b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler.post(new Runnable() {
425b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            public void run() {
426b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                try {
427b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraSession.setRepeatingBurst(requests, listener, handler);
428b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
429b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                } catch (CameraAccessException e) {
430b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    String errorMessage = mErrorDisplayer.getErrorString(e);
431b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mErrorDisplayer.showErrorDialog(errorMessage);
432b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
433b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
434b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        });
435b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
436b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
437b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
438b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Configure the camera session.
439b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
440b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private void startCameraSession() {
441b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        // Wait until both the camera device is open and the SurfaceView is ready
442b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (mCameraDevice == null || mSurfaces == null) return;
443b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
444b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        try {
445b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
446b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice.createCaptureSession(
447b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mSurfaces, mCameraSessionListener, mCameraHandler);
448b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } catch (CameraAccessException e) {
449b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            String errorMessage = mErrorDisplayer.getErrorString(e);
450b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mErrorDisplayer.showErrorDialog(errorMessage);
451b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice.close();
452b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice = null;
453b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
454b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
455b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
456b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
457b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Main listener for camera session events
458b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Invoked on mCameraThread
459b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
460b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private CameraCaptureSession.StateCallback mCameraSessionListener =
461b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            new CameraCaptureSession.StateCallback() {
462b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
463b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                @Override
464b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                public void onConfigured(CameraCaptureSession session) {
465b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraSession = session;
466b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mReadyHandler.post(new Runnable() {
467b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        public void run() {
468b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            // This can happen when the screen is turned off and turned back on.
469b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            if (null == mCameraDevice) {
470b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                return;
471b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            }
472b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
473b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            mReadyListener.onCameraReady();
474b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                        }
475b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    });
476b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
477b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
478b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
479b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                @Override
480b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                public void onConfigureFailed(CameraCaptureSession session) {
481b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mErrorDisplayer.showErrorDialog("Unable to configure the capture session");
482b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraDevice.close();
483b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraDevice = null;
484b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
485b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            };
486b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
487b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
488b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Main listener for camera device events.
489b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Invoked on mCameraThread
490b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
491b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private CameraDevice.StateCallback mCameraDeviceListener = new CameraDevice.StateCallback() {
492b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
493b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        @Override
494b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onOpened(CameraDevice camera) {
495b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice = camera;
496b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            startCameraSession();
497b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
498b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
499b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        @Override
500b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onClosed(CameraDevice camera) {
501b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCloseWaiter.open();
502b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
503b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
504b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        @Override
505b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onDisconnected(CameraDevice camera) {
506b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mErrorDisplayer.showErrorDialog("The camera device has been disconnected.");
507b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            camera.close();
508b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice = null;
509b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
510b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
511b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        @Override
512b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onError(CameraDevice camera, int error) {
513b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mErrorDisplayer.showErrorDialog("The camera encountered an error:" + error);
514b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            camera.close();
515b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mCameraDevice = null;
516b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
517b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
518b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    };
519b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
520b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void captureStillPicture(int currentJpegRotation, String name, Context context, int mode) {
521b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mSaveFileName = name;
522b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mContext = context;
523b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCaptureMode = mode;
524b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        try {
525b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            // TODO call lock focus if we are in "AF-S(One-Shot AF) mode"
526b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            // TODO call precapture if we are using flash
527b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            // This is the CaptureRequest.Builder that we use to take a picture.
528b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            final CaptureRequest.Builder captureBuilder =
529b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
530b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            Log.v(TAG, "S>>  Target " + mImageReader.getWidth() + "," + mImageReader.getHeight());
531b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
532b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            captureBuilder.addTarget(mImageReader.getSurface());
533b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
534b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, currentJpegRotation);
535b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
536b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            CameraCaptureSession.CaptureCallback captureCallback
537b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    = new CameraCaptureSession.CaptureCallback() {
538b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
539b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                @Override
540b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
541b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                               TotalCaptureResult result) {
542b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    Log.v(TAG, "S>>  onCaptureCompleted");
543b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    setParameters();
544b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
545b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            };
546b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
547b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
548b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            setRequest(captureBuilder.build(), captureCallback, null);
549b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } catch (CameraAccessException e) {
550b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            e.printStackTrace();
551b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
552b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
553b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
554b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
555b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Set a repeating request.
556b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
557b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private void setRequest(final CaptureRequest request,
558b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            final CameraCaptureSession.CaptureCallback listener,
559b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                            final Handler handler) {
560b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mCameraHandler.post(new Runnable() {
561b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            public void run() {
562b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                try {
563b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraSession.stopRepeating();
564b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mCameraSession.capture(request, listener, handler);
565b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                } catch (CameraAccessException e) {
566b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    String errorMessage = mErrorDisplayer.getErrorString(e);
567b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    mErrorDisplayer.showErrorDialog(errorMessage);
568b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                }
569b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            }
570b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        });
571b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
572b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
573b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setUpCamera(Surface processingNormalSurface) {
574b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mProcessingNormalSurface = processingNormalSurface;
575b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        // Ready to send requests in, so set them up
576b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        try {
577b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            CaptureRequest.Builder previewBuilder =
578b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
579b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            previewBuilder.addTarget(mProcessingNormalSurface);
580b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            previewBuilder.setTag(mAutoExposureTag);
581b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mPreviewRequest = previewBuilder.build();
582b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder = createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
583b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE,
584b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                    CaptureRequest.CONTROL_AE_MODE_OFF);
585b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.addTarget(mProcessingNormalSurface);
586b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            setParameters();
587b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
588b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } catch (CameraAccessException e) {
589b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            String errorMessage = e.getMessage();
590b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            // MessageDialogFragment.newInstance(errorMessage).show(getFragmentManager(), FRAGMENT_DIALOG);
591b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
592b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
593b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
594b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
595b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Start running an HDR burst on a configured camera session
596b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
597b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setParameters() {
598b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (mHdrBuilder == null) {
599b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            Log.v(TAG, " Camera not set up");
600b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            return;
601b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
602b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (mAutoExposure) {
603b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30);
604b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, getExposure());
605b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
606b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } else {
607b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
608b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.SENSOR_FRAME_DURATION, ONE_SECOND / 30);
609b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, getExposure());
610b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, getIso());
611b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
612b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        if (mAutoFocus) {
613b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
614b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
615b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        } else {
616b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
617b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.LENS_FOCUS_DISTANCE, getFocusDistance());
618b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            mHdrBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
619b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
620b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
621b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        setRepeatingRequest(mHdrBuilder.build(), mCaptureCallback, mReadyHandler);
622b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
623b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
624b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    private CameraCaptureSession.CaptureCallback mCaptureCallback
625b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford            = new CameraCaptureSession.CaptureCallback() {
626b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
627b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
628b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford                                       TotalCaptureResult result) {
629b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        }
630b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    };
631b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
632b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
633b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Simple listener for main code to know the camera is ready for requests, or failed to
634b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * start.
635b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
636b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public interface CameraReadyListener {
637b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void onCameraReady();
638b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
639b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
640b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    /**
641b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     * Simple listener for displaying error messages
642b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford     */
643b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public interface ErrorDisplayer {
644b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public void showErrorDialog(String errorMessage);
645b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
646b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        public String getErrorString(CameraAccessException e);
647b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
648b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
649b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public float getFocusDistance() {
650b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mFocusDist;
651b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
652b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
653b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setFocusDistance(float focusDistance) {
654b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mFocusDist = focusDistance;
655b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
656b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
657b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setIso(int iso) {
658b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mIso = iso;
659b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
660b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
661b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public boolean isAutoExposure() {
662b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mAutoExposure;
663b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
664b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
665b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setAutoExposure(boolean autoExposure) {
666b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mAutoExposure = autoExposure;
667b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
668b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
669b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public boolean isAutoFocus() {
670b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mAutoFocus;
671b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
672b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
673b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setAutoFocus(boolean autoFocus) {
674b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mAutoFocus = autoFocus;
675b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
676b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
677b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public int getIso() {
678b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mIso;
679b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
680b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
681b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public long getExposure() {
682b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mExposure;
683b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
684b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
685b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public void setExposure(long exposure) {
686b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        mExposure = exposure;
687b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
688b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
689b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public int getIsoMax() {
690b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mISOmax;
691b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
692b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
693b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public int getIsoMin() {
694b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mISOmin;
695b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
696b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
697b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public long getExpMax() {
698b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mExpMax;
699b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
700b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
701b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public long getExpMin() {
702b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mExpMin;
703b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
704b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford
705b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    public float getFocusMin() {
706b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford        return mFocusMin;
707b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford    }
708b7a6edcb8646d1ef4a090769c1ed53f273d89e6ehoford}
709