AndroidCamera2AgentImpl.java revision a97b7d1192e246a5f738991adca37cce282e1382
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);
204a0842b40441db5332a5290f941021636b1182761Sol Boucher
205a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraId == null) {
206a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mOpenCallback.onCameraDisabled(msg.arg1);
207a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
208a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
209a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this);
210a0842b40441db5332a5290f941021636b1182761Sol Boucher
211a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
212a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
213a0842b40441db5332a5290f941021636b1182761Sol Boucher
214a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.RELEASE: {
215a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) {
216a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring release at inappropriate time");
217a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
218a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
219a0842b40441db5332a5290f941021636b1182761Sol Boucher
220a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mSession != null) {
221a0842b40441db5332a5290f941021636b1182761Sol Boucher                            closePreviewSession();
222a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession = null;
223a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
224a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCamera != null) {
225a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mCamera.close();
226a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mCamera = null;
227a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
228a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraProxy = null;
229a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder = null;
230a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mActiveArray = null;
231a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mPreviewSurface != null) {
232a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mPreviewSurface.release();
233a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mPreviewSurface = null;
234a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
235a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPreviewTexture = null;
236a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPreviewSize = null;
237a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPhotoSize = null;
238a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraIndex = 0;
239a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraId = null;
240a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNOPENED);
241a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
242a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
243a0842b40441db5332a5290f941021636b1182761Sol Boucher
244a0842b40441db5332a5290f941021636b1182761Sol Boucher                    /*case CameraActions.UNLOCK: {
245a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
246a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
247a0842b40441db5332a5290f941021636b1182761Sol Boucher
248a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.LOCK: {
249a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
250a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
251a0842b40441db5332a5290f941021636b1182761Sol Boucher
252a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: {
253a0842b40441db5332a5290f941021636b1182761Sol Boucher                        setPreviewTexture((SurfaceTexture) msg.obj);
254a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
255a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
256a0842b40441db5332a5290f941021636b1182761Sol Boucher
257a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.START_PREVIEW_ASYNC: {
258a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() !=
259a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
260a0842b40441db5332a5290f941021636b1182761Sol Boucher                            // TODO: Provide better feedback here?
261a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Refusing to start preview at inappropriate time");
262a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
263a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
264a0842b40441db5332a5290f941021636b1182761Sol Boucher
265a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj;
266a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
267a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
268a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mSession.setRepeatingRequest(mPersistentRequestBuilder.build(),
269a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                /*listener*/mCameraFocusStateListener, /*handler*/this);
270a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
271a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Unable to start preview", ex);
272a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
273a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
274a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
275a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
276a0842b40441db5332a5290f941021636b1182761Sol Boucher
277a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.STOP_PREVIEW: {
278a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
279a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
280a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Refusing to stop preview at inappropriate time");
281a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
282a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
283a0842b40441db5332a5290f941021636b1182761Sol Boucher
284a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mSession.stopRepeating();
285a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
286a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
287a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
288a0842b40441db5332a5290f941021636b1182761Sol Boucher
289a0842b40441db5332a5290f941021636b1182761Sol Boucher                    /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: {
290a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
291a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
292a0842b40441db5332a5290f941021636b1182761Sol Boucher
293a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.ADD_CALLBACK_BUFFER: {
294a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
295a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
296a0842b40441db5332a5290f941021636b1182761Sol Boucher
297a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: {
298a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
299a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
300a0842b40441db5332a5290f941021636b1182761Sol Boucher
301a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_CALLBACK: {
302a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
303a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
304a0842b40441db5332a5290f941021636b1182761Sol Boucher
305a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: {
306a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
307a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
308a0842b40441db5332a5290f941021636b1182761Sol Boucher
309a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PARAMETERS: {
310a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
311a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
312a0842b40441db5332a5290f941021636b1182761Sol Boucher
313a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.GET_PARAMETERS: {
314a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
315a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
316a0842b40441db5332a5290f941021636b1182761Sol Boucher
317a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.REFRESH_PARAMETERS: {
318a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
319a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
320a0842b40441db5332a5290f941021636b1182761Sol Boucher
321a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.APPLY_SETTINGS: {
322a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraSettings settings = (CameraSettings) msg.obj;
323a0842b40441db5332a5290f941021636b1182761Sol Boucher                        applyToRequest(settings);
324a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
325a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
326a0842b40441db5332a5290f941021636b1182761Sol Boucher
327a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    case CameraActions.AUTO_FOCUS: {
328a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // We only support locking the focus while a preview is being displayed.
329a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // However, it can be requested multiple times in succession; the effect of
330a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // the subsequent invocations is determined by the focus mode defined in the
331a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // provided CameraSettings object. In passive (CONTINUOUS_*) mode, the
332a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // duplicate requests are no-ops and leave the lens locked at its current
333a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // position, but in active (AUTO) mode, they perform another scan and lock
334a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // once that is finished. In any manual focus mode, this call is a no-op,
335a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // and most notably, this is the only case where the callback isn't invoked.
336a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
337a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
338a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring attempt to autofocus without preview");
339a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
340a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
341a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
342a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // The earliest we can reliably tell whether the autofocus has locked in
343a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // response to our latest request is when our one-time capture completes.
344a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // However, it will probably take longer than that, so once that happens,
345a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // just start checking the repeating preview requests as they complete.
346a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        final CameraAFCallback callback = (CameraAFCallback) msg.obj;
347a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        CameraCaptureSession.CaptureListener deferredCallbackSetter =
348a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                new CameraCaptureSession.CaptureListener() {
349a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
350a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onCaptureCompleted(CameraCaptureSession session,
351a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                           CaptureRequest request,
352a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                           TotalCaptureResult result) {
353a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // Now our mCameraFocusStateListener will invoke the callback the
354a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // first time it finds the focus motor to be locked.
355a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mOneshotAfCallback = callback;
356a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
357a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
358a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
359a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onCaptureFailed(CameraCaptureSession session,
360a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                        CaptureRequest request,
361a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                        CaptureFailure failure) {
362a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                Log.e(TAG, "Focusing failed with reason " + failure.getReason());
363a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                callback.onAutoFocus(false, mCameraProxy);
364a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }};
365a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
366a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Send a one-time capture to trigger the camera driver to lock focus.
367a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
368a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
369a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_START);
370a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
371a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession.capture(mPersistentRequestBuilder.build(),
372a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    /*listener*/deferredCallbackSetter, /*handler*/ this);
373a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
374a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.e(TAG, "Unable to lock autofocus", ex);
375a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
376a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
377a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
378a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
379a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
380a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
381a0842b40441db5332a5290f941021636b1182761Sol Boucher
382a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.CANCEL_AUTO_FOCUS: {
383a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Why would you want to unlock the lens if it isn't already locked?
384a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
385a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
386a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring attempt to release focus lock without preview");
387a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
388a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
389a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
390a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Send a one-time capture to trigger the camera driver to resume scanning.
391a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
392a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
393a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
394a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
395a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession.capture(mPersistentRequestBuilder.build(),
396a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    /*listener*/null, /*handler*/this);
397a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
398a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.e(TAG, "Unable to cancel autofocus", ex);
399a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mCameraState.setState(
400a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
401a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
402a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
403a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
404a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
405a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
406a0842b40441db5332a5290f941021636b1182761Sol Boucher
407a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: {
408a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPassiveAfCallback = (CameraAFMoveCallback) msg.obj;
409a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
410a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
411a0842b40441db5332a5290f941021636b1182761Sol Boucher
412a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    /*case CameraActions.SET_ZOOM_CHANGE_LISTENER: {
413a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
414a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
415a0842b40441db5332a5290f941021636b1182761Sol Boucher
416a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_FACE_DETECTION_LISTENER: {
417a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
418a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
419a0842b40441db5332a5290f941021636b1182761Sol Boucher
420a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.START_FACE_DETECTION: {
421a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
422a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
423a0842b40441db5332a5290f941021636b1182761Sol Boucher
424a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.STOP_FACE_DETECTION: {
425a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
426a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
427a0842b40441db5332a5290f941021636b1182761Sol Boucher
428a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_ERROR_CALLBACK: {
429a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
430a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
431a0842b40441db5332a5290f941021636b1182761Sol Boucher
432a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.ENABLE_SHUTTER_SOUND: {
433a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
434a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
435a0842b40441db5332a5290f941021636b1182761Sol Boucher
436a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_DISPLAY_ORIENTATION: {
437a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
438a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
439a0842b40441db5332a5290f941021636b1182761Sol Boucher
440a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.CAPTURE_PHOTO: {
441a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
442a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
443a0842b40441db5332a5290f941021636b1182761Sol Boucher
444a0842b40441db5332a5290f941021636b1182761Sol Boucher                    default: {
445a0842b40441db5332a5290f941021636b1182761Sol Boucher                        // TODO: Rephrase once everything has been implemented
446a0842b40441db5332a5290f941021636b1182761Sol Boucher                        throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what);
447a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
448a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
449a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (final Exception ex) {
450a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (msg.what != CameraActions.RELEASE && mCamera != null) {
451a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // TODO: Handle this better
452a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCamera.close();
453a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCamera = null;
454a0842b40441db5332a5290f941021636b1182761Sol Boucher                } else if (mCamera == null) {
455a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (msg.what == CameraActions.OPEN_CAMERA) {
456a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mOpenCallback != null) {
457a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mOpenCallback.onDeviceOpenFailure(mCameraIndex,
458a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    generateHistoryString(mCameraIndex));
459a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
460a0842b40441db5332a5290f941021636b1182761Sol Boucher                    } else {
461a0842b40441db5332a5290f941021636b1182761Sol Boucher                        Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null");
462a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
463a0842b40441db5332a5290f941021636b1182761Sol Boucher                    return;
464a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
465a0842b40441db5332a5290f941021636b1182761Sol Boucher
466a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (ex instanceof RuntimeException) {
467a0842b40441db5332a5290f941021636b1182761Sol Boucher                    post(new Runnable() {
468a0842b40441db5332a5290f941021636b1182761Sol Boucher                        @Override
469a0842b40441db5332a5290f941021636b1182761Sol Boucher                        public void run() {
470a0842b40441db5332a5290f941021636b1182761Sol Boucher                            sCameraExceptionCallback.onCameraException((RuntimeException) ex);
471a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }});
472a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
473a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
474a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
475a0842b40441db5332a5290f941021636b1182761Sol Boucher
476a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraSettings buildSettings(AndroidCamera2Capabilities caps) {
477a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            return new AndroidCamera2Settings(caps, mPersistentRequestBuilder, mPreviewSize,
478a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mPhotoSize);
479a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
480a0842b40441db5332a5290f941021636b1182761Sol Boucher
481a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        /**
482a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * Simply propagates settings from provided {@link CameraSettings}
483a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * object to our {@link CaptureRequest.Builder} for use in captures.
484a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * <p>Most conversions to match the API 2 formats are performed by
485a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise
486a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * any final adjustments are done here before updating the builder.</p>
487a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         *
488a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * @param settings The new/updated settings
489a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         */
490a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Finish implementation to add support for all settings
491a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void applyToRequest(CameraSettings settings) {
492a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect
493a0842b40441db5332a5290f941021636b1182761Sol Boucher            AndroidCamera2Capabilities.IntegralStringifier intifier =
494a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCameraProxy.getSpecializedCapabilities().getIntegralStringifier();
495a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewSize = settings.getCurrentPreviewSize();
496a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPhotoSize = settings.getCurrentPhotoSize();
497a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
498a0842b40441db5332a5290f941021636b1182761Sol Boucher                    intifier.intify(settings.getCurrentFocusMode()));
499a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
500a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS,
501a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    legacyAreasToMeteringRectangles(settings.getFocusAreas()));
502a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.set(CaptureRequest.CONTROL_AE_REGIONS,
503a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    legacyAreasToMeteringRectangles(settings.getMeteringAreas()));
504a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
505a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (settings.getCurrentFlashMode() != CameraCapabilities.FlashMode.NO_FLASH) {
506a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mPersistentRequestBuilder.set(CaptureRequest.FLASH_MODE,
507a0842b40441db5332a5290f941021636b1182761Sol Boucher                        intifier.intify(settings.getCurrentFlashMode()));
508a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
509a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (settings.getCurrentSceneMode() != CameraCapabilities.SceneMode.NO_SCENE_MODE) {
510a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mPersistentRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
511a0842b40441db5332a5290f941021636b1182761Sol Boucher                        intifier.intify(settings.getCurrentSceneMode()));
512a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
513a0842b40441db5332a5290f941021636b1182761Sol Boucher
514a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
515a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                // If we're already previewing, reflect most settings immediately
516a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                try {
517a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mSession.setRepeatingRequest(mPersistentRequestBuilder.build(),
518a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            /*listener*/mCameraFocusStateListener, /*handler*/this);
519a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                } catch (CameraAccessException ex) {
520a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    Log.e(TAG, "Failed to apply updated request settings", ex);
521a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
522a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
523a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                // If we're already ready to preview, this doesn't regress our state
524a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
525a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
526a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
527a0842b40441db5332a5290f941021636b1182761Sol Boucher
528a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private MeteringRectangle[] legacyAreasToMeteringRectangles(
529a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                List<android.hardware.Camera.Area> reference) {
530a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            MeteringRectangle[] transformed = null;
531a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (reference.size() > 0) {
532a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
533a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                transformed = new MeteringRectangle[reference.size()];
534a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                for (int index = 0; index < reference.size(); ++index) {
535a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    android.hardware.Camera.Area source = reference.get(index);
536a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    Rect rectangle = source.rect;
537a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
538a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // Old API coordinates were [-1000,1000]; new ones are [0,ACTIVE_ARRAY_SIZE).
539a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldLeft = (rectangle.left + 1000) / 2000.0;
540a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldTop = (rectangle.top + 1000) / 2000.0;
541a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldRight = (rectangle.right + 1000) / 2000.0;
542a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    double oldBottom = (rectangle.bottom + 1000) / 2000.0;
543a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int left = toIntConstrained(
544a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.width() * oldLeft + mActiveArray.left,
545a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.width() - 1);
546a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int top = toIntConstrained(
547a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.height() * oldTop + mActiveArray.top,
548a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.height() - 1);
549a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int right = toIntConstrained(
550a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.width() * oldRight + mActiveArray.left,
551a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.width() - 1);
552a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int bottom = toIntConstrained(
553a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mActiveArray.height() * oldBottom + mActiveArray.top,
554a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            0, mActiveArray.height() - 1);
555a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    transformed[index] = new MeteringRectangle(left, top,
556a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            right - left, bottom - top, source.weight);
557a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
558a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
559a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            return transformed;
560a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
561a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
562a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private int toIntConstrained(double original, int min, int max) {
563a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            original = Math.max(original, min);
564a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            original = Math.min(original, max);
565a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            return (int) original;
566a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
567a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
568a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void setPreviewTexture(SurfaceTexture surfaceTexture) {
569a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: Must be called after providing a .*Settings populated with sizes
570a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures!
571a0842b40441db5332a5290f941021636b1182761Sol Boucher
572a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: Handle this error condition with a callback or exception
573a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) {
574a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Log.w(TAG, "Ignoring texture setting at inappropriate time");
575a0842b40441db5332a5290f941021636b1182761Sol Boucher                return;
576a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
577a0842b40441db5332a5290f941021636b1182761Sol Boucher
578a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Avoid initializing another capture session unless we absolutely have to
579a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (surfaceTexture == mPreviewTexture) {
580a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.i(TAG, "Optimizing out redundant preview texture setting");
581a0842b40441db5332a5290f941021636b1182761Sol Boucher                return;
582a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
583a0842b40441db5332a5290f941021636b1182761Sol Boucher
584a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mSession != null) {
585a0842b40441db5332a5290f941021636b1182761Sol Boucher                closePreviewSession();
586a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
587a0842b40441db5332a5290f941021636b1182761Sol Boucher
588a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewTexture = surfaceTexture;
589a0842b40441db5332a5290f941021636b1182761Sol Boucher            surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height());
590a0842b40441db5332a5290f941021636b1182761Sol Boucher
591a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (mPreviewSurface != null) {
592a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mPersistentRequestBuilder.removeTarget(mPreviewSurface);
593a0842b40441db5332a5290f941021636b1182761Sol Boucher                mPreviewSurface.release();
594a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
595a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewSurface = new Surface(surfaceTexture);
596a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mPersistentRequestBuilder.addTarget(mPreviewSurface);
597a0842b40441db5332a5290f941021636b1182761Sol Boucher
598a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
599a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCamera.createCaptureSession(Arrays.asList(mPreviewSurface),
600a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraPreviewStateListener, this);
601a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
602a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to create camera capture session", ex);
603a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
604a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
605a0842b40441db5332a5290f941021636b1182761Sol Boucher
606a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void closePreviewSession() {
607a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
608a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession.abortCaptures();
609a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession = null;
610a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
611a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to close existing camera capture session", ex);
612a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
613a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraState.setState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
614a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
615a0842b40441db5332a5290f941021636b1182761Sol Boucher
616a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors our connection to and disconnection from camera devices.
617a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraDevice.StateListener mCameraDeviceStateListener =
618a0842b40441db5332a5290f941021636b1182761Sol Boucher                new CameraDevice.StateListener() {
619a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
620a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onOpened(CameraDevice camera) {
621a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCamera = camera;
622a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (mOpenCallback != null) {
623a0842b40441db5332a5290f941021636b1182761Sol Boucher                    try {
624a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraCharacteristics props =
625a0842b40441db5332a5290f941021636b1182761Sol Boucher                                mCameraManager.getCameraCharacteristics(mCameraId);
626a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera,
627a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    getCameraDeviceInfo().getCharacteristics(mCameraIndex), props);
628a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPersistentRequestBuilder =
629a0842b40441db5332a5290f941021636b1182761Sol Boucher                                camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
630a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mActiveArray =
631a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
632a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraState.setState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED);
633a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback.onCameraOpened(mCameraProxy);
634a0842b40441db5332a5290f941021636b1182761Sol Boucher                    } catch (CameraAccessException ex) {
635a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback.onDeviceOpenFailure(mCameraIndex,
636a0842b40441db5332a5290f941021636b1182761Sol Boucher                                generateHistoryString(mCameraIndex));
637a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
638a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
639a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
640a0842b40441db5332a5290f941021636b1182761Sol Boucher
641a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
642a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onDisconnected(CameraDevice camera) {
643a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected");
644a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
645a0842b40441db5332a5290f941021636b1182761Sol Boucher
646a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
647a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onError(CameraDevice camera, int error) {
648a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" +
649a0842b40441db5332a5290f941021636b1182761Sol Boucher                        error + '\'');
650a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (mOpenCallback != null) {
651a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mOpenCallback.onDeviceOpenFailure(mCameraIndex,
652a0842b40441db5332a5290f941021636b1182761Sol Boucher                            generateHistoryString(mCameraIndex));
653a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
654a0842b40441db5332a5290f941021636b1182761Sol Boucher            }};
655a0842b40441db5332a5290f941021636b1182761Sol Boucher
656a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors our camera session (i.e. our transition into and out of preview).
657a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraCaptureSession.StateListener mCameraPreviewStateListener =
658a0842b40441db5332a5290f941021636b1182761Sol Boucher                new CameraCaptureSession.StateListener() {
659a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
660a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onConfigured(CameraCaptureSession session) {
661a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession = session;
662a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraState.setState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
663a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
664a0842b40441db5332a5290f941021636b1182761Sol Boucher
665a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
666a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onConfigureFailed(CameraCaptureSession session) {
667a0842b40441db5332a5290f941021636b1182761Sol Boucher                // TODO: Invoke a callback
668a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to configure the camera for capture");
669a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
670a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
671a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
672a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onActive(CameraCaptureSession session) {
673a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                if (mOneshotPreviewingCallback != null) {
674a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // The session is up and processing preview requests. Inform the caller.
675a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mOneshotPreviewingCallback.onPreviewStarted();
676a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mOneshotPreviewingCallback = null;
677a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
678a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }};
679a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
680a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors requested captures and notifies any relevant callbacks.
681a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraCaptureSession.CaptureListener mCameraFocusStateListener =
682a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                new CameraCaptureSession.CaptureListener() {
683a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            private int mLastAfState = -1;
684a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
685a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
686a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
687a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                           TotalCaptureResult result) {
688a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE);
689a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                if (afStateMaybe != null) {
690a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int afState = afStateMaybe;
691a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    boolean afStateChanged = false;
692a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (afState != mLastAfState) {
693a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mLastAfState = afState;
694a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        afStateChanged = true;
695a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
696a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
697a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    switch (afState) {
698a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
699a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
700a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: {
701a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            if (afStateChanged && mPassiveAfCallback != null) {
702a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // A CameraAFMoveCallback is attached. If we just started to scan,
703a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // the motor is moving; otherwise, it has settled.
704a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mPassiveAfCallback.onAutoFocusMoving(
705a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN,
706a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        mCameraProxy);
707a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
708a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
709a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
710a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
711a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
712a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: {
713a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            if (mOneshotAfCallback != null) {
714a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // A call to autoFocus() was just made to request a focus lock.
715a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // Notify the caller that the lens is now indefinitely fixed, and
716a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                // report whether the image we're now stuck with is in focus.
717a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mOneshotAfCallback.onAutoFocus(
718a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
719a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        mCameraProxy);
720a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                mOneshotAfCallback = null;
721a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
722a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
723a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
724a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
725a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
726a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
727a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
728a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
729a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
730a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        CaptureFailure failure) {
731a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Log.e(TAG, "Capture attempt failed with reason " + failure.getReason());
732a0842b40441db5332a5290f941021636b1182761Sol Boucher            }};
733a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
734a0842b40441db5332a5290f941021636b1182761Sol Boucher
735a0842b40441db5332a5290f941021636b1182761Sol Boucher    private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy {
736a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mCameraIndex;
737a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraDevice mCamera;
738a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraDeviceInfo.Characteristics mCharacteristics;
739a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final AndroidCamera2Capabilities mCapabilities;
740a0842b40441db5332a5290f941021636b1182761Sol Boucher
741a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera,
742a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraDeviceInfo.Characteristics characteristics,
743a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraCharacteristics properties) {
744a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraIndex = cameraIndex;
745a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCamera = camera;
746a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCharacteristics = characteristics;
747a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCapabilities = new AndroidCamera2Capabilities(properties);
748a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
749a0842b40441db5332a5290f941021636b1182761Sol Boucher
750a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
751a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
752a0842b40441db5332a5290f941021636b1182761Sol Boucher        public android.hardware.Camera getCamera() { return null; }
753a0842b40441db5332a5290f941021636b1182761Sol Boucher
754a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
755a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getCameraId() {
756a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraIndex;
757a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
758a0842b40441db5332a5290f941021636b1182761Sol Boucher
759a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
760a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraDeviceInfo.Characteristics getCharacteristics() {
761a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCharacteristics;
762a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
763a0842b40441db5332a5290f941021636b1182761Sol Boucher
764a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
765a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraCapabilities getCapabilities() {
766a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCapabilities;
767a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
768a0842b40441db5332a5290f941021636b1182761Sol Boucher
769a0842b40441db5332a5290f941021636b1182761Sol Boucher        private AndroidCamera2Capabilities getSpecializedCapabilities() {
770a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCapabilities;
771a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
772a0842b40441db5332a5290f941021636b1182761Sol Boucher
773a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
774a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
775a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
776a0842b40441db5332a5290f941021636b1182761Sol Boucher
777a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
778a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
779a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {}
780a0842b40441db5332a5290f941021636b1182761Sol Boucher
781a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
782a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
783a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)
784a0842b40441db5332a5290f941021636b1182761Sol Boucher                {}
785a0842b40441db5332a5290f941021636b1182761Sol Boucher
786a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
787a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void autoFocus(final Handler handler, final CameraAFCallback cb) {
788a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mDispatchThread.runJob(new Runnable() {
789a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                @Override
790a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                public void run() {
791a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    CameraAFCallback cbForward = null;
792a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (cb != null) {
793a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        cbForward = new CameraAFCallback() {
794a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
795a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onAutoFocus(final boolean focused,
796a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                    final CameraProxy camera) {
797a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                handler.post(new Runnable() {
798a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    @Override
799a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    public void run() {
800a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        cb.onAutoFocus(focused, camera);
801a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    }});
802a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }};
803a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
804a0842b40441db5332a5290f941021636b1182761Sol Boucher
805a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
806a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
807a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward)
808a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            .sendToTarget();
809a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }});
810a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
811a0842b40441db5332a5290f941021636b1182761Sol Boucher
812a0842b40441db5332a5290f941021636b1182761Sol Boucher        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
813a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
814a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) {
815a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mDispatchThread.runJob(new Runnable() {
816a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                @Override
817a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                public void run() {
818a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    CameraAFMoveCallback cbForward = null;
819a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (cb != null) {
820a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        cbForward = new CameraAFMoveCallback() {
821a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
822a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onAutoFocusMoving(final boolean moving,
823a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                          final CameraProxy camera) {
824a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                handler.post(new Runnable() {
825a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    @Override
826a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    public void run() {
827a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        cb.onAutoFocusMoving(moving, camera);
828a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    }});
829a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                }};
830a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
831a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
832a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK,
833a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            cbForward).sendToTarget();
834a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }});
835a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
836a0842b40441db5332a5290f941021636b1182761Sol Boucher
837a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
838a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
839a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void takePicture(Handler handler,
840a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraShutterCallback shutter,
841a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback raw,
842a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback postview,
843a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback jpeg) {}
844a0842b40441db5332a5290f941021636b1182761Sol Boucher
845a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Remove this method override once we handle the message
846a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
847a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setDisplayOrientation(int degrees) {}
848a0842b40441db5332a5290f941021636b1182761Sol Boucher
849a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
850a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
851a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {}
852a0842b40441db5332a5290f941021636b1182761Sol Boucher
853a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
854a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
855a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback)
856a0842b40441db5332a5290f941021636b1182761Sol Boucher                {}
857a0842b40441db5332a5290f941021636b1182761Sol Boucher
858a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Remove this method override once we handle this message
859a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
860a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void startFaceDetection() {}
861a0842b40441db5332a5290f941021636b1182761Sol Boucher
862a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // TODO: Remove this method override once we handle this message
863a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        @Override
864a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void stopFaceDetection() {}
865a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
866a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
867a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
868a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setErrorCallback(Handler handler, CameraErrorCallback cb) {}
869a0842b40441db5332a5290f941021636b1182761Sol Boucher
870a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
871a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
872a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setParameters(android.hardware.Camera.Parameters params) {}
873a0842b40441db5332a5290f941021636b1182761Sol Boucher
874a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
875a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
876a0842b40441db5332a5290f941021636b1182761Sol Boucher        public android.hardware.Camera.Parameters getParameters() { return null; }
877a0842b40441db5332a5290f941021636b1182761Sol Boucher
878a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
879a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraSettings getSettings() {
880a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraHandler.buildSettings(mCapabilities);
881a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
882a0842b40441db5332a5290f941021636b1182761Sol Boucher
883a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
884a0842b40441db5332a5290f941021636b1182761Sol Boucher        public boolean applySettings(CameraSettings settings) {
885a0842b40441db5332a5290f941021636b1182761Sol Boucher            return applySettingsHelper(settings, AndroidCamera2StateHolder.CAMERA_UNCONFIGURED |
886a0842b40441db5332a5290f941021636b1182761Sol Boucher                    AndroidCamera2StateHolder.CAMERA_CONFIGURED |
887a0842b40441db5332a5290f941021636b1182761Sol Boucher                    AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
888a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
889a0842b40441db5332a5290f941021636b1182761Sol Boucher
890a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
891a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
892a0842b40441db5332a5290f941021636b1182761Sol Boucher        public String dumpDeviceSettings() { return null; }
893a0842b40441db5332a5290f941021636b1182761Sol Boucher
894a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
895a0842b40441db5332a5290f941021636b1182761Sol Boucher        public Handler getCameraHandler() {
896a0842b40441db5332a5290f941021636b1182761Sol Boucher            return AndroidCamera2AgentImpl.this.getCameraHandler();
897a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
898a0842b40441db5332a5290f941021636b1182761Sol Boucher
899a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
900a0842b40441db5332a5290f941021636b1182761Sol Boucher        public DispatchThread getDispatchThread() {
901a0842b40441db5332a5290f941021636b1182761Sol Boucher            return AndroidCamera2AgentImpl.this.getDispatchThread();
902a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
903a0842b40441db5332a5290f941021636b1182761Sol Boucher
904a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
905a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraStateHolder getCameraState() {
906a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraState;
907a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
908a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
909a0842b40441db5332a5290f941021636b1182761Sol Boucher
910a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher    /** A linear state machine: each state entails all the states below it. */
911a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static class AndroidCamera2StateHolder extends CameraStateHolder {
912a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() ->
913a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        //             autoFocus() -> takePicture()
914a0842b40441db5332a5290f941021636b1182761Sol Boucher        /* Camera states */
915a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** No camera device is opened. */
916a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_UNOPENED = 1;
917a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A camera is opened, but no settings have been provided. */
918a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_UNCONFIGURED = 2;
919a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** The open camera has been configured by providing it with settings. */
920a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_CONFIGURED = 3;
921a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A capture session is ready to stream a preview, but still has no repeating request. */
922a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_PREVIEW_READY = 4;
923a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A preview is currently being streamed. */
924a0842b40441db5332a5290f941021636b1182761Sol Boucher        public static final int CAMERA_PREVIEW_ACTIVE = 5;
925a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        /** The lens is locked on a particular region. */
926a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public static final int CAMERA_FOCUS_LOCKED = 6;
927a0842b40441db5332a5290f941021636b1182761Sol Boucher
928a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2StateHolder() {
929a0842b40441db5332a5290f941021636b1182761Sol Boucher            this(CAMERA_UNOPENED);
930a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
931a0842b40441db5332a5290f941021636b1182761Sol Boucher
932a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2StateHolder(int state) {
9337e0d39bf7b6e0f0df606e3f6c15f673f70fed3f7Sol Boucher            super(state);
934a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
935a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
936a0842b40441db5332a5290f941021636b1182761Sol Boucher
937a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo {
938a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraManager mCameraManager;
939a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final String[] mCameraIds;
940a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mNumberOfCameras;
941a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mFirstBackCameraId;
942a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mFirstFrontCameraId;
943a0842b40441db5332a5290f941021636b1182761Sol Boucher
944a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2DeviceInfo(CameraManager cameraManager,
945a0842b40441db5332a5290f941021636b1182761Sol Boucher                                        String[] cameraIds, int numberOfCameras) {
946a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraManager = cameraManager;
947a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraIds = cameraIds;
948a0842b40441db5332a5290f941021636b1182761Sol Boucher            mNumberOfCameras = numberOfCameras;
949a0842b40441db5332a5290f941021636b1182761Sol Boucher
950a0842b40441db5332a5290f941021636b1182761Sol Boucher            int firstBackId = NO_DEVICE;
951a0842b40441db5332a5290f941021636b1182761Sol Boucher            int firstFrontId = NO_DEVICE;
952a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (int id = 0; id < cameraIds.length; ++id) {
953a0842b40441db5332a5290f941021636b1182761Sol Boucher                try {
954a0842b40441db5332a5290f941021636b1182761Sol Boucher                    int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id])
955a0842b40441db5332a5290f941021636b1182761Sol Boucher                            .get(CameraCharacteristics.LENS_FACING);
956a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (firstBackId == NO_DEVICE &&
957a0842b40441db5332a5290f941021636b1182761Sol Boucher                            lensDirection == CameraCharacteristics.LENS_FACING_BACK) {
958a0842b40441db5332a5290f941021636b1182761Sol Boucher                        firstBackId = id;
959a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
960a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (firstFrontId == NO_DEVICE &&
961a0842b40441db5332a5290f941021636b1182761Sol Boucher                            lensDirection == CameraCharacteristics.LENS_FACING_FRONT) {
962a0842b40441db5332a5290f941021636b1182761Sol Boucher                        firstFrontId = id;
963a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
964a0842b40441db5332a5290f941021636b1182761Sol Boucher                } catch (CameraAccessException ex) {
965a0842b40441db5332a5290f941021636b1182761Sol Boucher                    Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex);
966a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
967a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
968a0842b40441db5332a5290f941021636b1182761Sol Boucher            mFirstBackCameraId = firstBackId;
969a0842b40441db5332a5290f941021636b1182761Sol Boucher            mFirstFrontCameraId = firstFrontId;
970a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
971a0842b40441db5332a5290f941021636b1182761Sol Boucher
972a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
973a0842b40441db5332a5290f941021636b1182761Sol Boucher        public Characteristics getCharacteristics(int cameraId) {
974a0842b40441db5332a5290f941021636b1182761Sol Boucher            String actualId = mCameraIds[cameraId];
975a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
976a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId);
977a0842b40441db5332a5290f941021636b1182761Sol Boucher                return new AndroidCharacteristics2(info);
978a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
979a0842b40441db5332a5290f941021636b1182761Sol Boucher                return null;
980a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
981a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
982a0842b40441db5332a5290f941021636b1182761Sol Boucher
983a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
984a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getNumberOfCameras() {
985a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mNumberOfCameras;
986a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
987a0842b40441db5332a5290f941021636b1182761Sol Boucher
988a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
989a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getFirstBackCameraId() {
990a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mFirstBackCameraId;
991a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
992a0842b40441db5332a5290f941021636b1182761Sol Boucher
993a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
994a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getFirstFrontCameraId() {
995a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mFirstFrontCameraId;
996a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
997a0842b40441db5332a5290f941021636b1182761Sol Boucher
998a0842b40441db5332a5290f941021636b1182761Sol Boucher        private static class AndroidCharacteristics2 implements Characteristics {
999a0842b40441db5332a5290f941021636b1182761Sol Boucher            private CameraCharacteristics mCameraInfo;
1000a0842b40441db5332a5290f941021636b1182761Sol Boucher
1001a0842b40441db5332a5290f941021636b1182761Sol Boucher            AndroidCharacteristics2(CameraCharacteristics cameraInfo) {
1002a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraInfo = cameraInfo;
1003a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1004a0842b40441db5332a5290f941021636b1182761Sol Boucher
1005a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1006a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean isFacingBack() {
1007a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
1008a0842b40441db5332a5290f941021636b1182761Sol Boucher                        .equals(CameraCharacteristics.LENS_FACING_BACK);
1009a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1010a0842b40441db5332a5290f941021636b1182761Sol Boucher
1011a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1012a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean isFacingFront() {
1013a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
1014a0842b40441db5332a5290f941021636b1182761Sol Boucher                        .equals(CameraCharacteristics.LENS_FACING_FRONT);
1015a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1016a0842b40441db5332a5290f941021636b1182761Sol Boucher
1017a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1018a0842b40441db5332a5290f941021636b1182761Sol Boucher            public int getSensorOrientation() {
1019a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION);
1020a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1021a0842b40441db5332a5290f941021636b1182761Sol Boucher
1022a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1023a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean canDisableShutterSound() {
1024a0842b40441db5332a5290f941021636b1182761Sol Boucher                // The new API doesn't support this operation, so don't encourage people to try it.
1025a0842b40441db5332a5290f941021636b1182761Sol Boucher                // TODO: What kind of assumptions have callers made about this result's meaning?
1026a0842b40441db5332a5290f941021636b1182761Sol Boucher                return false;
1027a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1028a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1029a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
1030a0842b40441db5332a5290f941021636b1182761Sol Boucher
1031a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static final CameraExceptionCallback sCameraExceptionCallback =
1032a0842b40441db5332a5290f941021636b1182761Sol Boucher            new CameraExceptionCallback() {
1033a0842b40441db5332a5290f941021636b1182761Sol Boucher                @Override
1034a0842b40441db5332a5290f941021636b1182761Sol Boucher                public synchronized void onCameraException(RuntimeException e) {
1035a0842b40441db5332a5290f941021636b1182761Sol Boucher                    throw e;
1036a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
1037a0842b40441db5332a5290f941021636b1182761Sol Boucher            };
1038a0842b40441db5332a5290f941021636b1182761Sol Boucher}
1039