AndroidCamera2AgentImpl.java revision 50f5b019ba3f333a09a1beb9667fd7290082dc31
1a0842b40441db5332a5290f941021636b1182761Sol Boucher/*
2a0842b40441db5332a5290f941021636b1182761Sol Boucher * Copyright (C) 2014 The Android Open Source Project
3a0842b40441db5332a5290f941021636b1182761Sol Boucher *
4a0842b40441db5332a5290f941021636b1182761Sol Boucher * Licensed under the Apache License, Version 2.0 (the "License");
5a0842b40441db5332a5290f941021636b1182761Sol Boucher * you may not use this file except in compliance with the License.
6a0842b40441db5332a5290f941021636b1182761Sol Boucher * You may obtain a copy of the License at
7a0842b40441db5332a5290f941021636b1182761Sol Boucher *
8a0842b40441db5332a5290f941021636b1182761Sol Boucher *      http://www.apache.org/licenses/LICENSE-2.0
9a0842b40441db5332a5290f941021636b1182761Sol Boucher *
10a0842b40441db5332a5290f941021636b1182761Sol Boucher * Unless required by applicable law or agreed to in writing, software
11a0842b40441db5332a5290f941021636b1182761Sol Boucher * distributed under the License is distributed on an "AS IS" BASIS,
12a0842b40441db5332a5290f941021636b1182761Sol Boucher * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0842b40441db5332a5290f941021636b1182761Sol Boucher * See the License for the specific language governing permissions and
14a0842b40441db5332a5290f941021636b1182761Sol Boucher * limitations under the License.
15a0842b40441db5332a5290f941021636b1182761Sol Boucher */
16a0842b40441db5332a5290f941021636b1182761Sol Boucher
17a0842b40441db5332a5290f941021636b1182761Sol Boucherpackage com.android.ex.camera2.portability;
18a0842b40441db5332a5290f941021636b1182761Sol Boucher
19a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.annotation.TargetApi;
20a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.content.Context;
21a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.graphics.Rect;
22a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.graphics.SurfaceTexture;
23a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraAccessException;
24a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraCaptureSession;
25a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraCharacteristics;
26a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraDevice;
27a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraManager;
28a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.CaptureFailure;
29a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CaptureRequest;
30a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.CaptureResult;
31a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.TotalCaptureResult;
32a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.params.MeteringRectangle;
33a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Build;
34a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Handler;
35a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.HandlerThread;
36a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Looper;
37a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Message;
38a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.view.Surface;
39a0842b40441db5332a5290f941021636b1182761Sol Boucher
40a0842b40441db5332a5290f941021636b1182761Sol Boucherimport com.android.ex.camera2.portability.debug.Log;
41a0842b40441db5332a5290f941021636b1182761Sol Boucher
42a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.ArrayList;
43a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.Arrays;
44a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.HashSet;
45a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.List;
46a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.Set;
47a0842b40441db5332a5290f941021636b1182761Sol Boucher
48a0842b40441db5332a5290f941021636b1182761Sol Boucher/**
49a0842b40441db5332a5290f941021636b1182761Sol Boucher * A class to implement {@link CameraAgent} of the Android camera2 framework.
50a0842b40441db5332a5290f941021636b1182761Sol Boucher */
51a0842b40441db5332a5290f941021636b1182761Sol Boucherclass AndroidCamera2AgentImpl extends CameraAgent {
52a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static final Log.Tag TAG = new Log.Tag("AndCam2AgntImp");
53a0842b40441db5332a5290f941021636b1182761Sol Boucher
54a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final Camera2Handler mCameraHandler;
55a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final HandlerThread mCameraHandlerThread;
56a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final CameraStateHolder mCameraState;
57a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final DispatchThread mDispatchThread;
58a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final CameraManager mCameraManager;
59a0842b40441db5332a5290f941021636b1182761Sol Boucher
60a0842b40441db5332a5290f941021636b1182761Sol Boucher    /**
61a0842b40441db5332a5290f941021636b1182761Sol Boucher     * Number of camera devices.  The length of {@code mCameraDevices} does not reveal this
62a0842b40441db5332a5290f941021636b1182761Sol Boucher     * information because that list may contain since-invalidated indices.
63a0842b40441db5332a5290f941021636b1182761Sol Boucher     */
64a0842b40441db5332a5290f941021636b1182761Sol Boucher    private int mNumCameraDevices;
65a0842b40441db5332a5290f941021636b1182761Sol Boucher
66a0842b40441db5332a5290f941021636b1182761Sol Boucher    /**
67a0842b40441db5332a5290f941021636b1182761Sol Boucher     * Transformation between integral camera indices and the {@link java.lang.String} indices used
68a0842b40441db5332a5290f941021636b1182761Sol Boucher     * by the underlying API.  Note that devices may disappear because they've been disconnected or
69a0842b40441db5332a5290f941021636b1182761Sol Boucher     * have otherwise gone offline.  Because we need to keep the meanings of whatever indices we
70a0842b40441db5332a5290f941021636b1182761Sol Boucher     * expose stable, we cannot simply remove them in such a case; instead, we insert {@code null}s
71a0842b40441db5332a5290f941021636b1182761Sol Boucher     * to invalidate any such indices.  Whenever new devices appear, they are appended to the end of
72a0842b40441db5332a5290f941021636b1182761Sol Boucher     * the list, and thereby assigned the lowest index that has never yet been used.
73a0842b40441db5332a5290f941021636b1182761Sol Boucher     */
74a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final List<String> mCameraDevices;
75a0842b40441db5332a5290f941021636b1182761Sol Boucher
76a0842b40441db5332a5290f941021636b1182761Sol Boucher    AndroidCamera2AgentImpl(Context context) {
77a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread");
78a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraHandlerThread.start();
79a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper());
80a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraState = new AndroidCamera2StateHolder();
81a0842b40441db5332a5290f941021636b1182761Sol Boucher        mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread);
82a0842b40441db5332a5290f941021636b1182761Sol Boucher        mDispatchThread.start();
83a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
84a0842b40441db5332a5290f941021636b1182761Sol Boucher
85a0842b40441db5332a5290f941021636b1182761Sol Boucher        mNumCameraDevices = 0;
86a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraDevices = new ArrayList<String>();
87a0842b40441db5332a5290f941021636b1182761Sol Boucher        updateCameraDevices();
88a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
89a0842b40441db5332a5290f941021636b1182761Sol Boucher
90a0842b40441db5332a5290f941021636b1182761Sol Boucher    /**
91a0842b40441db5332a5290f941021636b1182761Sol Boucher     * Updates the camera device index assignments stored in {@link mCameraDevices}, without
92a0842b40441db5332a5290f941021636b1182761Sol Boucher     * reappropriating any currently-assigned index.
93a0842b40441db5332a5290f941021636b1182761Sol Boucher     * @return Whether the operation was successful
94a0842b40441db5332a5290f941021636b1182761Sol Boucher     */
95a0842b40441db5332a5290f941021636b1182761Sol Boucher    private boolean updateCameraDevices() {
96a0842b40441db5332a5290f941021636b1182761Sol Boucher        try {
97a0842b40441db5332a5290f941021636b1182761Sol Boucher            String[] currentCameraDevices = mCameraManager.getCameraIdList();
98a0842b40441db5332a5290f941021636b1182761Sol Boucher            Set<String> currentSet = new HashSet<String>(Arrays.asList(currentCameraDevices));
99a0842b40441db5332a5290f941021636b1182761Sol Boucher
100a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Invalidate the indices assigned to any camera devices that are no longer present
101a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (int index = 0; index < mCameraDevices.size(); ++index) {
102a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (!currentSet.contains(mCameraDevices.get(index))) {
103a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCameraDevices.set(index, null);
104a0842b40441db5332a5290f941021636b1182761Sol Boucher                    --mNumCameraDevices;
105a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
106a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
107a0842b40441db5332a5290f941021636b1182761Sol Boucher
108a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Assign fresh indices to any new camera devices
109a0842b40441db5332a5290f941021636b1182761Sol Boucher            currentSet.removeAll(mCameraDevices); // The devices we didn't know about
110a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (String device : currentCameraDevices) {
111a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (currentSet.contains(device)) {
112a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCameraDevices.add(device);
113a0842b40441db5332a5290f941021636b1182761Sol Boucher                    ++mNumCameraDevices;
114a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
115a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
116a0842b40441db5332a5290f941021636b1182761Sol Boucher
117a0842b40441db5332a5290f941021636b1182761Sol Boucher            return true;
118a0842b40441db5332a5290f941021636b1182761Sol Boucher        } catch (CameraAccessException ex) {
119a0842b40441db5332a5290f941021636b1182761Sol Boucher            Log.e(TAG, "Could not get device listing from camera subsystem", ex);
120a0842b40441db5332a5290f941021636b1182761Sol Boucher            return false;
121a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
122a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
123a0842b40441db5332a5290f941021636b1182761Sol Boucher
124a0842b40441db5332a5290f941021636b1182761Sol Boucher    // TODO: Implement
125a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
126a0842b40441db5332a5290f941021636b1182761Sol Boucher    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
127a0842b40441db5332a5290f941021636b1182761Sol Boucher            Handler handler) {}
128a0842b40441db5332a5290f941021636b1182761Sol Boucher
129a0842b40441db5332a5290f941021636b1182761Sol Boucher    // TODO: Implement
130a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
131a0842b40441db5332a5290f941021636b1182761Sol Boucher    public void recycle() {}
132a0842b40441db5332a5290f941021636b1182761Sol Boucher
133a0842b40441db5332a5290f941021636b1182761Sol Boucher    // TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs
134a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
135a0842b40441db5332a5290f941021636b1182761Sol Boucher    public CameraDeviceInfo getCameraDeviceInfo() {
136a0842b40441db5332a5290f941021636b1182761Sol Boucher        updateCameraDevices();
137a0842b40441db5332a5290f941021636b1182761Sol Boucher        return new AndroidCamera2DeviceInfo(mCameraManager, mCameraDevices.toArray(new String[0]),
138a0842b40441db5332a5290f941021636b1182761Sol Boucher                mNumCameraDevices);
139a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
140a0842b40441db5332a5290f941021636b1182761Sol Boucher
141a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
142a0842b40441db5332a5290f941021636b1182761Sol Boucher    protected Handler getCameraHandler() {
143a0842b40441db5332a5290f941021636b1182761Sol Boucher        return mCameraHandler;
144a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
145a0842b40441db5332a5290f941021636b1182761Sol Boucher
146a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
147a0842b40441db5332a5290f941021636b1182761Sol Boucher    protected DispatchThread getDispatchThread() {
148a0842b40441db5332a5290f941021636b1182761Sol Boucher        return mDispatchThread;
149a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
150a0842b40441db5332a5290f941021636b1182761Sol Boucher
151a0842b40441db5332a5290f941021636b1182761Sol Boucher    private class Camera2Handler extends HistoryHandler {
152a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Caller-provided when leaving CAMERA_UNOPENED state:
153a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraOpenCallback mOpenCallback;
154a0842b40441db5332a5290f941021636b1182761Sol Boucher        private int mCameraIndex;
155a0842b40441db5332a5290f941021636b1182761Sol Boucher        private String mCameraId;
156a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
157a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in CAMERA_UNCONFIGURED state and above:
158a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraDevice mCamera;
159a0842b40441db5332a5290f941021636b1182761Sol Boucher        private AndroidCamera2ProxyImpl mCameraProxy;
160a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CaptureRequest.Builder mPersistentRequestBuilder;
161a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private Rect mActiveArray;
162a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
163a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in CAMERA_CONFIGURED state and above:
164a0842b40441db5332a5290f941021636b1182761Sol Boucher        private Size mPreviewSize;
165a0842b40441db5332a5290f941021636b1182761Sol Boucher        private Size mPhotoSize;
166a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
167a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in PREVIEW_READY state and above:
168a0842b40441db5332a5290f941021636b1182761Sol Boucher        private SurfaceTexture mPreviewTexture;
169a0842b40441db5332a5290f941021636b1182761Sol Boucher        private Surface mPreviewSurface;
170a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraCaptureSession mSession;
171a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
172a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available from the beginning of PREVIEW_ACTIVE until the first preview frame arrives:
173a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraStartPreviewCallback mOneshotPreviewingCallback;
174a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
175a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in FOCUS_LOCKED between AF trigger receipt and whenever the lens stops moving:
176a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraAFCallback mOneshotAfCallback;
177a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
178a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available whenever setAutoFocusMoveCallback() was last invoked with a non-null argument:
179a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraAFMoveCallback mPassiveAfCallback;
180a0842b40441db5332a5290f941021636b1182761Sol Boucher
181a0842b40441db5332a5290f941021636b1182761Sol Boucher        Camera2Handler(Looper looper) {
182a0842b40441db5332a5290f941021636b1182761Sol Boucher            super(looper);
183a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
184a0842b40441db5332a5290f941021636b1182761Sol Boucher
185a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
186a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void handleMessage(final Message msg) {
187a0842b40441db5332a5290f941021636b1182761Sol Boucher            super.handleMessage(msg);
188a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
189a0842b40441db5332a5290f941021636b1182761Sol Boucher                switch(msg.what) {
190a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.OPEN_CAMERA:
191a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.RECONNECT: {
192a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
193a0842b40441db5332a5290f941021636b1182761Sol Boucher                        int cameraIndex = msg.arg1;
194a0842b40441db5332a5290f941021636b1182761Sol Boucher
195a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() != AndroidCamera2StateHolder.CAMERA_UNOPENED) {
196a0842b40441db5332a5290f941021636b1182761Sol Boucher                            openCallback.onDeviceOpenedAlready(cameraIndex,
197a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    generateHistoryString(cameraIndex));
198a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
199a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
200a0842b40441db5332a5290f941021636b1182761Sol Boucher
201a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback = openCallback;
202a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraIndex = cameraIndex;
203a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraId = mCameraDevices.get(mCameraIndex);
20450f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher                        Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API",
20550f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher                                cameraIndex, mCameraId));
206a0842b40441db5332a5290f941021636b1182761Sol Boucher
207a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraId == null) {
208a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mOpenCallback.onCameraDisabled(msg.arg1);
209a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
210a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
211a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this);
212a0842b40441db5332a5290f941021636b1182761Sol Boucher
213a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
214a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
215a0842b40441db5332a5290f941021636b1182761Sol Boucher
216a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.RELEASE: {
217a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) {
218a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring release at inappropriate time");
219a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
220a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
221a0842b40441db5332a5290f941021636b1182761Sol Boucher
222a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mSession != null) {
223a0842b40441db5332a5290f941021636b1182761Sol Boucher                            closePreviewSession();
224a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession = null;
225a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
226a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCamera != null) {
227a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mCamera.close();
228a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mCamera = null;
229a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
230a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraProxy = null;
231a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder = null;
232a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mActiveArray = null;
233a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mPreviewSurface != null) {
234a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mPreviewSurface.release();
235a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mPreviewSurface = null;
236a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
237a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPreviewTexture = null;
238a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPreviewSize = null;
239a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPhotoSize = null;
240a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraIndex = 0;
241a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraId = null;
242a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNOPENED);
243a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
244a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
245a0842b40441db5332a5290f941021636b1182761Sol Boucher
246a0842b40441db5332a5290f941021636b1182761Sol Boucher                    /*case CameraActions.UNLOCK: {
247a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
248a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
249a0842b40441db5332a5290f941021636b1182761Sol Boucher
250a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.LOCK: {
251a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
252a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
253a0842b40441db5332a5290f941021636b1182761Sol Boucher
254a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: {
255a0842b40441db5332a5290f941021636b1182761Sol Boucher                        setPreviewTexture((SurfaceTexture) msg.obj);
256a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
257a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
258a0842b40441db5332a5290f941021636b1182761Sol Boucher
259a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.START_PREVIEW_ASYNC: {
260a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() !=
261a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
262a0842b40441db5332a5290f941021636b1182761Sol Boucher                            // TODO: Provide better feedback here?
263a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Refusing to start preview at inappropriate time");
264a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
265a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
266a0842b40441db5332a5290f941021636b1182761Sol Boucher
267a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj;
268a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
269a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
270a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mSession.setRepeatingRequest(mPersistentRequestBuilder.build(),
271a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                /*listener*/mCameraFocusStateListener, /*handler*/this);
272a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
273a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Unable to start preview", ex);
274a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
275a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
276a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
277a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
278a0842b40441db5332a5290f941021636b1182761Sol Boucher
279a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.STOP_PREVIEW: {
280a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
281a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
282a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Refusing to stop preview at inappropriate time");
283a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
284a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
285a0842b40441db5332a5290f941021636b1182761Sol Boucher
286a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mSession.stopRepeating();
287a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
288a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
289a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
290a0842b40441db5332a5290f941021636b1182761Sol Boucher
291a0842b40441db5332a5290f941021636b1182761Sol Boucher                    /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: {
292a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
293a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
294a0842b40441db5332a5290f941021636b1182761Sol Boucher
295a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.ADD_CALLBACK_BUFFER: {
296a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
297a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
298a0842b40441db5332a5290f941021636b1182761Sol Boucher
299a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: {
300a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
301a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
302a0842b40441db5332a5290f941021636b1182761Sol Boucher
303a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_CALLBACK: {
304a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
305a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
306a0842b40441db5332a5290f941021636b1182761Sol Boucher
307a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: {
308a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
309a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
310a0842b40441db5332a5290f941021636b1182761Sol Boucher
311a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PARAMETERS: {
312a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
313a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
314a0842b40441db5332a5290f941021636b1182761Sol Boucher
315a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.GET_PARAMETERS: {
316a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
317a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
318a0842b40441db5332a5290f941021636b1182761Sol Boucher
319a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.REFRESH_PARAMETERS: {
320a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
321a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
322a0842b40441db5332a5290f941021636b1182761Sol Boucher
323a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.APPLY_SETTINGS: {
324a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraSettings settings = (CameraSettings) msg.obj;
325a0842b40441db5332a5290f941021636b1182761Sol Boucher                        applyToRequest(settings);
326a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
327a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
328a0842b40441db5332a5290f941021636b1182761Sol Boucher
329a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    case CameraActions.AUTO_FOCUS: {
330a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // We only support locking the focus while a preview is being displayed.
331a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // However, it can be requested multiple times in succession; the effect of
332a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // the subsequent invocations is determined by the focus mode defined in the
333a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // provided CameraSettings object. In passive (CONTINUOUS_*) mode, the
334a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // duplicate requests are no-ops and leave the lens locked at its current
335a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // position, but in active (AUTO) mode, they perform another scan and lock
336a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // once that is finished. In any manual focus mode, this call is a no-op,
337a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // and most notably, this is the only case where the callback isn't invoked.
338a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
339a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
340a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring attempt to autofocus without preview");
341a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
342a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
343a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
344a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // The earliest we can reliably tell whether the autofocus has locked in
345a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // response to our latest request is when our one-time capture completes.
346a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // However, it will probably take longer than that, so once that happens,
347a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // just start checking the repeating preview requests as they complete.
348a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        final CameraAFCallback callback = (CameraAFCallback) msg.obj;
349a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        CameraCaptureSession.CaptureListener deferredCallbackSetter =
350a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                new CameraCaptureSession.CaptureListener() {
351a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
352a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onCaptureCompleted(CameraCaptureSession session,
353a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                           CaptureRequest request,
354a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                           TotalCaptureResult result) {
355a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // Now our mCameraFocusStateListener will invoke the callback the
356a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // first time it finds the focus motor to be locked.
357a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mOneshotAfCallback = callback;
358a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
359a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
360a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
361a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onCaptureFailed(CameraCaptureSession session,
362a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                        CaptureRequest request,
363a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                        CaptureFailure failure) {
364a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                Log.e(TAG, "Focusing failed with reason " + failure.getReason());
365a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                callback.onAutoFocus(false, mCameraProxy);
366a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }};
367a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
368a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Send a one-time capture to trigger the camera driver to lock focus.
369a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
370a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
371a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_START);
372a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
373a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession.capture(mPersistentRequestBuilder.build(),
374a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    /*listener*/deferredCallbackSetter, /*handler*/ this);
375a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
376a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.e(TAG, "Unable to lock autofocus", ex);
377a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
378a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
379a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
380a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
381a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
382a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
383a0842b40441db5332a5290f941021636b1182761Sol Boucher
384a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.CANCEL_AUTO_FOCUS: {
385a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Why would you want to unlock the lens if it isn't already locked?
386a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
387a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
388a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring attempt to release focus lock without preview");
389a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
390a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
391a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
392a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Send a one-time capture to trigger the camera driver to resume scanning.
393a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
394a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
395a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
396a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
397a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession.capture(mPersistentRequestBuilder.build(),
398a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    /*listener*/null, /*handler*/this);
399a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
400a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.e(TAG, "Unable to cancel autofocus", ex);
401a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mCameraState.setState(
402a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
403a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
404a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
405a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
406a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
407a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
408a0842b40441db5332a5290f941021636b1182761Sol Boucher
409a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: {
410a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPassiveAfCallback = (CameraAFMoveCallback) msg.obj;
411a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
412a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
413a0842b40441db5332a5290f941021636b1182761Sol Boucher
414a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    /*case CameraActions.SET_ZOOM_CHANGE_LISTENER: {
415a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
416a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
417a0842b40441db5332a5290f941021636b1182761Sol Boucher
418a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_FACE_DETECTION_LISTENER: {
419a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
420a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
421a0842b40441db5332a5290f941021636b1182761Sol Boucher
422a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.START_FACE_DETECTION: {
423a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
424a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
425a0842b40441db5332a5290f941021636b1182761Sol Boucher
426a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.STOP_FACE_DETECTION: {
427a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
428a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
429a0842b40441db5332a5290f941021636b1182761Sol Boucher
430a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_ERROR_CALLBACK: {
431a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
432a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
433a0842b40441db5332a5290f941021636b1182761Sol Boucher
434a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.ENABLE_SHUTTER_SOUND: {
435a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
436a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
437a0842b40441db5332a5290f941021636b1182761Sol Boucher
438a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_DISPLAY_ORIENTATION: {
439a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
440a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
441a0842b40441db5332a5290f941021636b1182761Sol Boucher
442a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.CAPTURE_PHOTO: {
443a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
444a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
445a0842b40441db5332a5290f941021636b1182761Sol Boucher
446a0842b40441db5332a5290f941021636b1182761Sol Boucher                    default: {
447a0842b40441db5332a5290f941021636b1182761Sol Boucher                        // TODO: Rephrase once everything has been implemented
448a0842b40441db5332a5290f941021636b1182761Sol Boucher                        throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what);
449a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
450a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
451a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (final Exception ex) {
452a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (msg.what != CameraActions.RELEASE && mCamera != null) {
453a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // TODO: Handle this better
454a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCamera.close();
455a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCamera = null;
456a0842b40441db5332a5290f941021636b1182761Sol Boucher                } else if (mCamera == null) {
457a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (msg.what == CameraActions.OPEN_CAMERA) {
458a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mOpenCallback != null) {
459a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mOpenCallback.onDeviceOpenFailure(mCameraIndex,
460a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    generateHistoryString(mCameraIndex));
461a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
462a0842b40441db5332a5290f941021636b1182761Sol Boucher                    } else {
463a0842b40441db5332a5290f941021636b1182761Sol Boucher                        Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null");
464a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
465a0842b40441db5332a5290f941021636b1182761Sol Boucher                    return;
466a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
467a0842b40441db5332a5290f941021636b1182761Sol Boucher
468a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (ex instanceof RuntimeException) {
469a0842b40441db5332a5290f941021636b1182761Sol Boucher                    post(new Runnable() {
470a0842b40441db5332a5290f941021636b1182761Sol Boucher                        @Override
471a0842b40441db5332a5290f941021636b1182761Sol Boucher                        public void run() {
472a0842b40441db5332a5290f941021636b1182761Sol Boucher                            sCameraExceptionCallback.onCameraException((RuntimeException) ex);
473a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }});
474a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
475a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
476a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
477a0842b40441db5332a5290f941021636b1182761Sol Boucher
478a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraSettings buildSettings(AndroidCamera2Capabilities caps) {
479a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            return new AndroidCamera2Settings(caps, mPersistentRequestBuilder, mPreviewSize,
480a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mPhotoSize);
481a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
482a0842b40441db5332a5290f941021636b1182761Sol Boucher
483a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        /**
484a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * Simply propagates settings from provided {@link CameraSettings}
485a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * object to our {@link CaptureRequest.Builder} for use in captures.
486a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * <p>Most conversions to match the API 2 formats are performed by
487a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise
488a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * any final adjustments are done here before updating the builder.</p>
489a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         *
490a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * @param settings The new/updated settings
491a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         */
492a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Finish implementation to add support for all settings
493a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void applyToRequest(CameraSettings settings) {
494a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect
495a0842b40441db5332a5290f941021636b1182761Sol Boucher            AndroidCamera2Capabilities.IntegralStringifier intifier =
496a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCameraProxy.getSpecializedCapabilities().getIntegralStringifier();
497a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewSize = settings.getCurrentPreviewSize();
498a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPhotoSize = settings.getCurrentPhotoSize();
499a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
500a0842b40441db5332a5290f941021636b1182761Sol Boucher                    intifier.intify(settings.getCurrentFocusMode()));
501a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
502a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS,
503a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    legacyAreasToMeteringRectangles(settings.getFocusAreas()));
504a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS,
505a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    legacyAreasToMeteringRectangles(settings.getMeteringAreas()));
506a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
507a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (settings.getCurrentFlashMode() != CameraCapabilities.FlashMode.NO_FLASH) {
508a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mPersistentRequestBuilder.set(CaptureRequest.FLASH_MODE,
509a0842b40441db5332a5290f941021636b1182761Sol Boucher                        intifier.intify(settings.getCurrentFlashMode()));
510a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
511a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (settings.getCurrentSceneMode() != CameraCapabilities.SceneMode.NO_SCENE_MODE) {
512a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mPersistentRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
513a0842b40441db5332a5290f941021636b1182761Sol Boucher                        intifier.intify(settings.getCurrentSceneMode()));
514a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
515a0842b40441db5332a5290f941021636b1182761Sol Boucher
516a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
517a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                // If we're already previewing, reflect most settings immediately
518a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                try {
519a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mSession.setRepeatingRequest(mPersistentRequestBuilder.build(),
520a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            /*listener*/mCameraFocusStateListener, /*handler*/this);
521a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                } catch (CameraAccessException ex) {
522a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    Log.e(TAG, "Failed to apply updated request settings", ex);
523a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
524a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
525a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                // If we're already ready to preview, this doesn't regress our state
526a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
527a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
528a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
529a0842b40441db5332a5290f941021636b1182761Sol Boucher
530a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private MeteringRectangle[] legacyAreasToMeteringRectangles(
531a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                List<android.hardware.Camera.Area> reference) {
532a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            MeteringRectangle[] transformed = null;
533a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (reference.size() > 0) {
534a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
535a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                transformed = new MeteringRectangle[reference.size()];
536a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                for (int index = 0; index < reference.size(); ++index) {
537a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    android.hardware.Camera.Area source = reference.get(index);
538a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    Rect rectangle = source.rect;
539a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
540a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // Old API coordinates were [-1000,1000]; new ones are [0,ACTIVE_ARRAY_SIZE).
541a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldLeft = (rectangle.left + 1000) / 2000.0;
542a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldTop = (rectangle.top + 1000) / 2000.0;
543a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldRight = (rectangle.right + 1000) / 2000.0;
544a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldBottom = (rectangle.bottom + 1000) / 2000.0;
545a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int left = toIntConstrained(
546a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.width() * oldLeft + mActiveArray.left,
547a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.width() - 1);
548a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int top = toIntConstrained(
549a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.height() * oldTop + mActiveArray.top,
550a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.height() - 1);
551a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int right = toIntConstrained(
552a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.width() * oldRight + mActiveArray.left,
553a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.width() - 1);
554a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int bottom = toIntConstrained(
555a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.height() * oldBottom + mActiveArray.top,
556a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.height() - 1);
557a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    transformed[index] = new MeteringRectangle(left, top,
558a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            right - left, bottom - top, source.weight);
559a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
560a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
561a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            return transformed;
562a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
563a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
564a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private int toIntConstrained(double original, int min, int max) {
565a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            original = Math.max(original, min);
566a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            original = Math.min(original, max);
567a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            return (int) original;
568a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
569a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
570a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void setPreviewTexture(SurfaceTexture surfaceTexture) {
571a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: Must be called after providing a .*Settings populated with sizes
572a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures!
573a0842b40441db5332a5290f941021636b1182761Sol Boucher
574a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: Handle this error condition with a callback or exception
575a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) {
576a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Log.w(TAG, "Ignoring texture setting at inappropriate time");
577a0842b40441db5332a5290f941021636b1182761Sol Boucher                return;
578a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
579a0842b40441db5332a5290f941021636b1182761Sol Boucher
580a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Avoid initializing another capture session unless we absolutely have to
581a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (surfaceTexture == mPreviewTexture) {
582a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.i(TAG, "Optimizing out redundant preview texture setting");
583a0842b40441db5332a5290f941021636b1182761Sol Boucher                return;
584a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
585a0842b40441db5332a5290f941021636b1182761Sol Boucher
586a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mSession != null) {
587a0842b40441db5332a5290f941021636b1182761Sol Boucher                closePreviewSession();
588a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
589a0842b40441db5332a5290f941021636b1182761Sol Boucher
590a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewTexture = surfaceTexture;
591a0842b40441db5332a5290f941021636b1182761Sol Boucher            surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height());
592a0842b40441db5332a5290f941021636b1182761Sol Boucher
593a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (mPreviewSurface != null) {
594a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mPersistentRequestBuilder.removeTarget(mPreviewSurface);
595a0842b40441db5332a5290f941021636b1182761Sol Boucher                mPreviewSurface.release();
596a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
597a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewSurface = new Surface(surfaceTexture);
598a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.addTarget(mPreviewSurface);
599a0842b40441db5332a5290f941021636b1182761Sol Boucher
600a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
601a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCamera.createCaptureSession(Arrays.asList(mPreviewSurface),
602a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraPreviewStateListener, this);
603a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
604a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to create camera capture session", ex);
605a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
606a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
607a0842b40441db5332a5290f941021636b1182761Sol Boucher
608a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void closePreviewSession() {
609a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
610a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession.abortCaptures();
611a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession = null;
612a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
613a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to close existing camera capture session", ex);
614a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
615a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
616a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
617a0842b40441db5332a5290f941021636b1182761Sol Boucher
618a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors our connection to and disconnection from camera devices.
619a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraDevice.StateListener mCameraDeviceStateListener =
620a0842b40441db5332a5290f941021636b1182761Sol Boucher                new CameraDevice.StateListener() {
621a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
622a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onOpened(CameraDevice camera) {
623a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCamera = camera;
624a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (mOpenCallback != null) {
625a0842b40441db5332a5290f941021636b1182761Sol Boucher                    try {
626a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraCharacteristics props =
627a0842b40441db5332a5290f941021636b1182761Sol Boucher                                mCameraManager.getCameraCharacteristics(mCameraId);
628a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera,
629a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    getCameraDeviceInfo().getCharacteristics(mCameraIndex), props);
630a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder =
631a0842b40441db5332a5290f941021636b1182761Sol Boucher                                camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
632a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mActiveArray =
633a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
634a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED);
635a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback.onCameraOpened(mCameraProxy);
636a0842b40441db5332a5290f941021636b1182761Sol Boucher                    } catch (CameraAccessException ex) {
637a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback.onDeviceOpenFailure(mCameraIndex,
638a0842b40441db5332a5290f941021636b1182761Sol Boucher                                generateHistoryString(mCameraIndex));
639a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
640a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
641a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
642a0842b40441db5332a5290f941021636b1182761Sol Boucher
643a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
644a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onDisconnected(CameraDevice camera) {
645a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected");
646a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
647a0842b40441db5332a5290f941021636b1182761Sol Boucher
648a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
649a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onError(CameraDevice camera, int error) {
650a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" +
651a0842b40441db5332a5290f941021636b1182761Sol Boucher                        error + '\'');
652a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (mOpenCallback != null) {
653a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mOpenCallback.onDeviceOpenFailure(mCameraIndex,
654a0842b40441db5332a5290f941021636b1182761Sol Boucher                            generateHistoryString(mCameraIndex));
655a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
656a0842b40441db5332a5290f941021636b1182761Sol Boucher            }};
657a0842b40441db5332a5290f941021636b1182761Sol Boucher
658a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors our camera session (i.e. our transition into and out of preview).
659a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraCaptureSession.StateListener mCameraPreviewStateListener =
660a0842b40441db5332a5290f941021636b1182761Sol Boucher                new CameraCaptureSession.StateListener() {
661a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
662a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onConfigured(CameraCaptureSession session) {
663a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession = session;
664a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
665a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
666a0842b40441db5332a5290f941021636b1182761Sol Boucher
667a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
668a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onConfigureFailed(CameraCaptureSession session) {
669a0842b40441db5332a5290f941021636b1182761Sol Boucher                // TODO: Invoke a callback
670a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to configure the camera for capture");
671a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
672a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
673a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
674a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onActive(CameraCaptureSession session) {
675a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                if (mOneshotPreviewingCallback != null) {
676a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // The session is up and processing preview requests. Inform the caller.
677a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mOneshotPreviewingCallback.onPreviewStarted();
678a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mOneshotPreviewingCallback = null;
679a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
680a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }};
681a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
682a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors requested captures and notifies any relevant callbacks.
683a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraCaptureSession.CaptureListener mCameraFocusStateListener =
684a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                new CameraCaptureSession.CaptureListener() {
685a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            private int mLastAfState = -1;
686a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
687a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
688a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
689a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                           TotalCaptureResult result) {
690a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE);
691a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                if (afStateMaybe != null) {
692a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int afState = afStateMaybe;
693a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    boolean afStateChanged = false;
694a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (afState != mLastAfState) {
695a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mLastAfState = afState;
696a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        afStateChanged = true;
697a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
698a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
699a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    switch (afState) {
700a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
701a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
702a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: {
703a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            if (afStateChanged && mPassiveAfCallback != null) {
704a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // A CameraAFMoveCallback is attached. If we just started to scan,
705a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // the motor is moving; otherwise, it has settled.
706a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mPassiveAfCallback.onAutoFocusMoving(
707a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN,
708a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        mCameraProxy);
709a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
710a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
711a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
712a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
713a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
714a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: {
715a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            if (mOneshotAfCallback != null) {
716a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // A call to autoFocus() was just made to request a focus lock.
717a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // Notify the caller that the lens is now indefinitely fixed, and
718a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // report whether the image we're now stuck with is in focus.
719a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mOneshotAfCallback.onAutoFocus(
720a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
721a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        mCameraProxy);
722a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mOneshotAfCallback = null;
723a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
724a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
725a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
726a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
727a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
728a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
729a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
730a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
731a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
732a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        CaptureFailure failure) {
733a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Log.e(TAG, "Capture attempt failed with reason " + failure.getReason());
734a0842b40441db5332a5290f941021636b1182761Sol Boucher            }};
735a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
736a0842b40441db5332a5290f941021636b1182761Sol Boucher
737a0842b40441db5332a5290f941021636b1182761Sol Boucher    private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy {
738a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mCameraIndex;
739a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraDevice mCamera;
740a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraDeviceInfo.Characteristics mCharacteristics;
741a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final AndroidCamera2Capabilities mCapabilities;
742a0842b40441db5332a5290f941021636b1182761Sol Boucher
743a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera,
744a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraDeviceInfo.Characteristics characteristics,
745a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraCharacteristics properties) {
746a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraIndex = cameraIndex;
747a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCamera = camera;
748a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCharacteristics = characteristics;
749a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCapabilities = new AndroidCamera2Capabilities(properties);
750a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
751a0842b40441db5332a5290f941021636b1182761Sol Boucher
752a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
753a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
754a0842b40441db5332a5290f941021636b1182761Sol Boucher        public android.hardware.Camera getCamera() { return null; }
755a0842b40441db5332a5290f941021636b1182761Sol Boucher
756a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
757a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getCameraId() {
758a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraIndex;
759a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
760a0842b40441db5332a5290f941021636b1182761Sol Boucher
761a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
762a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraDeviceInfo.Characteristics getCharacteristics() {
763a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCharacteristics;
764a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
765a0842b40441db5332a5290f941021636b1182761Sol Boucher
766a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
767a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraCapabilities getCapabilities() {
768a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCapabilities;
769a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
770a0842b40441db5332a5290f941021636b1182761Sol Boucher
771a0842b40441db5332a5290f941021636b1182761Sol Boucher        private AndroidCamera2Capabilities getSpecializedCapabilities() {
772a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCapabilities;
773a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
774a0842b40441db5332a5290f941021636b1182761Sol Boucher
775a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
776a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
777a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
778a0842b40441db5332a5290f941021636b1182761Sol Boucher
779a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
780a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
781a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {}
782a0842b40441db5332a5290f941021636b1182761Sol Boucher
783a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
784a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
785a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)
786a0842b40441db5332a5290f941021636b1182761Sol Boucher                {}
787a0842b40441db5332a5290f941021636b1182761Sol Boucher
78850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher        // TODO: Implement
78950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher        public void addCallbackBuffer(final byte[] callbackBuffer) {}
79050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher
791a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
792a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void autoFocus(final Handler handler, final CameraAFCallback cb) {
793a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mDispatchThread.runJob(new Runnable() {
794a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                @Override
795a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                public void run() {
796a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    CameraAFCallback cbForward = null;
797a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (cb != null) {
798a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        cbForward = new CameraAFCallback() {
799a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
800a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onAutoFocus(final boolean focused,
801a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                    final CameraProxy camera) {
802a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                handler.post(new Runnable() {
803a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    @Override
804a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    public void run() {
805a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        cb.onAutoFocus(focused, camera);
806a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    }});
807a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }};
808a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
809a0842b40441db5332a5290f941021636b1182761Sol Boucher
810a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
811a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
812a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward)
813a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            .sendToTarget();
814a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }});
815a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
816a0842b40441db5332a5290f941021636b1182761Sol Boucher
817a0842b40441db5332a5290f941021636b1182761Sol Boucher        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
818a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
819a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) {
820a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mDispatchThread.runJob(new Runnable() {
821a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                @Override
822a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                public void run() {
823a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    CameraAFMoveCallback cbForward = null;
824a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (cb != null) {
825a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        cbForward = new CameraAFMoveCallback() {
826a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
827a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onAutoFocusMoving(final boolean moving,
828a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                          final CameraProxy camera) {
829a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                handler.post(new Runnable() {
830a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    @Override
831a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    public void run() {
832a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        cb.onAutoFocusMoving(moving, camera);
833a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    }});
834a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                }};
835a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
836a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
837a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK,
838a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            cbForward).sendToTarget();
839a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }});
840a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
841a0842b40441db5332a5290f941021636b1182761Sol Boucher
842a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
843a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
844a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void takePicture(Handler handler,
845a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraShutterCallback shutter,
846a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback raw,
847a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback postview,
848a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback jpeg) {}
849a0842b40441db5332a5290f941021636b1182761Sol Boucher
850a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Remove this method override once we handle the message
851a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
852a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setDisplayOrientation(int degrees) {}
853a0842b40441db5332a5290f941021636b1182761Sol Boucher
854a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
855a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
856a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {}
857a0842b40441db5332a5290f941021636b1182761Sol Boucher
858a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
859a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
860a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback)
861a0842b40441db5332a5290f941021636b1182761Sol Boucher                {}
862a0842b40441db5332a5290f941021636b1182761Sol Boucher
863a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Remove this method override once we handle this message
864a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
865a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void startFaceDetection() {}
866a0842b40441db5332a5290f941021636b1182761Sol Boucher
867a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // TODO: Remove this method override once we handle this message
868a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        @Override
869a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void stopFaceDetection() {}
870a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
871a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
872a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
873a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setErrorCallback(Handler handler, CameraErrorCallback cb) {}
874a0842b40441db5332a5290f941021636b1182761Sol Boucher
875a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
876a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
877a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setParameters(android.hardware.Camera.Parameters params) {}
878a0842b40441db5332a5290f941021636b1182761Sol Boucher
879a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
880a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
881a0842b40441db5332a5290f941021636b1182761Sol Boucher        public android.hardware.Camera.Parameters getParameters() { return null; }
882a0842b40441db5332a5290f941021636b1182761Sol Boucher
883a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
884a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraSettings getSettings() {
885a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraHandler.buildSettings(mCapabilities);
886a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
887a0842b40441db5332a5290f941021636b1182761Sol Boucher
888a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
889a0842b40441db5332a5290f941021636b1182761Sol Boucher        public boolean applySettings(CameraSettings settings) {
890a0842b40441db5332a5290f941021636b1182761Sol Boucher            return applySettingsHelper(settings, AndroidCamera2StateHolder.CAMERA_UNCONFIGURED |
891a0842b40441db5332a5290f941021636b1182761Sol Boucher                    AndroidCamera2StateHolder.CAMERA_CONFIGURED |
892a0842b40441db5332a5290f941021636b1182761Sol Boucher                    AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
893a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
894a0842b40441db5332a5290f941021636b1182761Sol Boucher
895a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
896a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
897a0842b40441db5332a5290f941021636b1182761Sol Boucher        public String dumpDeviceSettings() { return null; }
898a0842b40441db5332a5290f941021636b1182761Sol Boucher
899a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
900a0842b40441db5332a5290f941021636b1182761Sol Boucher        public Handler getCameraHandler() {
901a0842b40441db5332a5290f941021636b1182761Sol Boucher            return AndroidCamera2AgentImpl.this.getCameraHandler();
902a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
903a0842b40441db5332a5290f941021636b1182761Sol Boucher
904a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
905a0842b40441db5332a5290f941021636b1182761Sol Boucher        public DispatchThread getDispatchThread() {
906a0842b40441db5332a5290f941021636b1182761Sol Boucher            return AndroidCamera2AgentImpl.this.getDispatchThread();
907a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
908a0842b40441db5332a5290f941021636b1182761Sol Boucher
909a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
910a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraStateHolder getCameraState() {
911a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraState;
912a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
913a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
914a0842b40441db5332a5290f941021636b1182761Sol Boucher
915a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher    /** A linear state machine: each state entails all the states below it. */
916a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static class AndroidCamera2StateHolder extends CameraStateHolder {
917a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() ->
918a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        //             autoFocus() -> takePicture()
919a0842b40441db5332a5290f941021636b1182761Sol Boucher        /* Camera states */
920a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** No camera device is opened. */
921a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_UNOPENED = 1;
922a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A camera is opened, but no settings have been provided. */
923a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_UNCONFIGURED = 2;
924a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** The open camera has been configured by providing it with settings. */
925a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_CONFIGURED = 3;
926a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A capture session is ready to stream a preview, but still has no repeating request. */
927a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_PREVIEW_READY = 4;
928a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A preview is currently being streamed. */
929a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_PREVIEW_ACTIVE = 5;
930a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        /** The lens is locked on a particular region. */
931a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public static final int CAMERA_FOCUS_LOCKED = 6;
932a0842b40441db5332a5290f941021636b1182761Sol Boucher
933a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2StateHolder() {
934a0842b40441db5332a5290f941021636b1182761Sol Boucher            this(CAMERA_UNOPENED);
935a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
936a0842b40441db5332a5290f941021636b1182761Sol Boucher
937a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2StateHolder(int state) {
9387e0d39bf7b6e0f0df606e3f6c15f673f70fed3f7Sol Boucher            super(state);
939a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
940a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
941a0842b40441db5332a5290f941021636b1182761Sol Boucher
942a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo {
943a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraManager mCameraManager;
944a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final String[] mCameraIds;
945a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mNumberOfCameras;
946a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mFirstBackCameraId;
947a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mFirstFrontCameraId;
948a0842b40441db5332a5290f941021636b1182761Sol Boucher
949a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2DeviceInfo(CameraManager cameraManager,
950a0842b40441db5332a5290f941021636b1182761Sol Boucher                                        String[] cameraIds, int numberOfCameras) {
951a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraManager = cameraManager;
952a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraIds = cameraIds;
953a0842b40441db5332a5290f941021636b1182761Sol Boucher            mNumberOfCameras = numberOfCameras;
954a0842b40441db5332a5290f941021636b1182761Sol Boucher
955a0842b40441db5332a5290f941021636b1182761Sol Boucher            int firstBackId = NO_DEVICE;
956a0842b40441db5332a5290f941021636b1182761Sol Boucher            int firstFrontId = NO_DEVICE;
957a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (int id = 0; id < cameraIds.length; ++id) {
958a0842b40441db5332a5290f941021636b1182761Sol Boucher                try {
959a0842b40441db5332a5290f941021636b1182761Sol Boucher                    int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id])
960a0842b40441db5332a5290f941021636b1182761Sol Boucher                            .get(CameraCharacteristics.LENS_FACING);
961a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (firstBackId == NO_DEVICE &&
962a0842b40441db5332a5290f941021636b1182761Sol Boucher                            lensDirection == CameraCharacteristics.LENS_FACING_BACK) {
963a0842b40441db5332a5290f941021636b1182761Sol Boucher                        firstBackId = id;
964a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
965a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (firstFrontId == NO_DEVICE &&
966a0842b40441db5332a5290f941021636b1182761Sol Boucher                            lensDirection == CameraCharacteristics.LENS_FACING_FRONT) {
967a0842b40441db5332a5290f941021636b1182761Sol Boucher                        firstFrontId = id;
968a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
969a0842b40441db5332a5290f941021636b1182761Sol Boucher                } catch (CameraAccessException ex) {
970a0842b40441db5332a5290f941021636b1182761Sol Boucher                    Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex);
971a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
972a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
973a0842b40441db5332a5290f941021636b1182761Sol Boucher            mFirstBackCameraId = firstBackId;
974a0842b40441db5332a5290f941021636b1182761Sol Boucher            mFirstFrontCameraId = firstFrontId;
975a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
976a0842b40441db5332a5290f941021636b1182761Sol Boucher
977a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
978a0842b40441db5332a5290f941021636b1182761Sol Boucher        public Characteristics getCharacteristics(int cameraId) {
979a0842b40441db5332a5290f941021636b1182761Sol Boucher            String actualId = mCameraIds[cameraId];
980a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
981a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId);
982a0842b40441db5332a5290f941021636b1182761Sol Boucher                return new AndroidCharacteristics2(info);
983a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
984a0842b40441db5332a5290f941021636b1182761Sol Boucher                return null;
985a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
986a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
987a0842b40441db5332a5290f941021636b1182761Sol Boucher
988a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
989a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getNumberOfCameras() {
990a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mNumberOfCameras;
991a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
992a0842b40441db5332a5290f941021636b1182761Sol Boucher
993a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
994a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getFirstBackCameraId() {
995a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mFirstBackCameraId;
996a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
997a0842b40441db5332a5290f941021636b1182761Sol Boucher
998a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
999a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getFirstFrontCameraId() {
1000a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mFirstFrontCameraId;
1001a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1002a0842b40441db5332a5290f941021636b1182761Sol Boucher
1003a0842b40441db5332a5290f941021636b1182761Sol Boucher        private static class AndroidCharacteristics2 implements Characteristics {
1004a0842b40441db5332a5290f941021636b1182761Sol Boucher            private CameraCharacteristics mCameraInfo;
1005a0842b40441db5332a5290f941021636b1182761Sol Boucher
1006a0842b40441db5332a5290f941021636b1182761Sol Boucher            AndroidCharacteristics2(CameraCharacteristics cameraInfo) {
1007a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraInfo = cameraInfo;
1008a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1009a0842b40441db5332a5290f941021636b1182761Sol Boucher
1010a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1011a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean isFacingBack() {
1012a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
1013a0842b40441db5332a5290f941021636b1182761Sol Boucher                        .equals(CameraCharacteristics.LENS_FACING_BACK);
1014a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1015a0842b40441db5332a5290f941021636b1182761Sol Boucher
1016a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1017a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean isFacingFront() {
1018a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
1019a0842b40441db5332a5290f941021636b1182761Sol Boucher                        .equals(CameraCharacteristics.LENS_FACING_FRONT);
1020a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1021a0842b40441db5332a5290f941021636b1182761Sol Boucher
1022a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1023a0842b40441db5332a5290f941021636b1182761Sol Boucher            public int getSensorOrientation() {
1024a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION);
1025a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1026a0842b40441db5332a5290f941021636b1182761Sol Boucher
1027a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1028a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean canDisableShutterSound() {
1029a0842b40441db5332a5290f941021636b1182761Sol Boucher                // The new API doesn't support this operation, so don't encourage people to try it.
1030a0842b40441db5332a5290f941021636b1182761Sol Boucher                // TODO: What kind of assumptions have callers made about this result's meaning?
1031a0842b40441db5332a5290f941021636b1182761Sol Boucher                return false;
1032a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1033a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1034a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
1035a0842b40441db5332a5290f941021636b1182761Sol Boucher
1036a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static final CameraExceptionCallback sCameraExceptionCallback =
1037a0842b40441db5332a5290f941021636b1182761Sol Boucher            new CameraExceptionCallback() {
1038a0842b40441db5332a5290f941021636b1182761Sol Boucher                @Override
1039a0842b40441db5332a5290f941021636b1182761Sol Boucher                public synchronized void onCameraException(RuntimeException e) {
1040a0842b40441db5332a5290f941021636b1182761Sol Boucher                    throw e;
1041a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
1042a0842b40441db5332a5290f941021636b1182761Sol Boucher            };
1043a0842b40441db5332a5290f941021636b1182761Sol Boucher}
1044