AndroidCamera2AgentImpl.java revision 2569329d6cff25bfe9941df539df14a0aeb4c4f4
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;
21de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucherimport android.graphics.ImageFormat;
22f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucherimport android.graphics.Matrix;
23a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.graphics.Rect;
24f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucherimport android.graphics.RectF;
25a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.graphics.SurfaceTexture;
26a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraAccessException;
27a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraCaptureSession;
28a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraCharacteristics;
29a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraDevice;
30a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CameraManager;
31a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.CaptureFailure;
32a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.hardware.camera2.CaptureRequest;
33a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.CaptureResult;
34a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.TotalCaptureResult;
35a97b7d1192e246a5f738991adca37cce282e1382Sol Boucherimport android.hardware.camera2.params.MeteringRectangle;
36de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucherimport android.media.Image;
37de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucherimport android.media.ImageReader;
38aa907a3b6637b4f95dbf572d0cf790a70ba3aeb0Sol Boucherimport android.media.MediaActionSound;
39a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Build;
40a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Handler;
41a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.HandlerThread;
42a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Looper;
43a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.os.Message;
44a0842b40441db5332a5290f941021636b1182761Sol Boucherimport android.view.Surface;
45a0842b40441db5332a5290f941021636b1182761Sol Boucher
46a0842b40441db5332a5290f941021636b1182761Sol Boucherimport com.android.ex.camera2.portability.debug.Log;
47de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucherimport com.android.ex.camera2.utils.Camera2RequestSettingsSet;
48a0842b40441db5332a5290f941021636b1182761Sol Boucher
49de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucherimport java.nio.ByteBuffer;
50a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.ArrayList;
51a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.Arrays;
52a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.HashSet;
53a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.List;
54a0842b40441db5332a5290f941021636b1182761Sol Boucherimport java.util.Set;
55a0842b40441db5332a5290f941021636b1182761Sol Boucher
56a0842b40441db5332a5290f941021636b1182761Sol Boucher/**
57a0842b40441db5332a5290f941021636b1182761Sol Boucher * A class to implement {@link CameraAgent} of the Android camera2 framework.
58a0842b40441db5332a5290f941021636b1182761Sol Boucher */
59a0842b40441db5332a5290f941021636b1182761Sol Boucherclass AndroidCamera2AgentImpl extends CameraAgent {
60a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static final Log.Tag TAG = new Log.Tag("AndCam2AgntImp");
61a0842b40441db5332a5290f941021636b1182761Sol Boucher
62a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final Camera2Handler mCameraHandler;
63a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final HandlerThread mCameraHandlerThread;
64a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final CameraStateHolder mCameraState;
65a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final DispatchThread mDispatchThread;
66a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final CameraManager mCameraManager;
67aa907a3b6637b4f95dbf572d0cf790a70ba3aeb0Sol Boucher    private final MediaActionSound mNoisemaker;
68a0842b40441db5332a5290f941021636b1182761Sol Boucher
69a0842b40441db5332a5290f941021636b1182761Sol Boucher    /**
70a0842b40441db5332a5290f941021636b1182761Sol Boucher     * Number of camera devices.  The length of {@code mCameraDevices} does not reveal this
71a0842b40441db5332a5290f941021636b1182761Sol Boucher     * information because that list may contain since-invalidated indices.
72a0842b40441db5332a5290f941021636b1182761Sol Boucher     */
73a0842b40441db5332a5290f941021636b1182761Sol Boucher    private int mNumCameraDevices;
74a0842b40441db5332a5290f941021636b1182761Sol Boucher
75a0842b40441db5332a5290f941021636b1182761Sol Boucher    /**
76a0842b40441db5332a5290f941021636b1182761Sol Boucher     * Transformation between integral camera indices and the {@link java.lang.String} indices used
77a0842b40441db5332a5290f941021636b1182761Sol Boucher     * by the underlying API.  Note that devices may disappear because they've been disconnected or
78a0842b40441db5332a5290f941021636b1182761Sol Boucher     * have otherwise gone offline.  Because we need to keep the meanings of whatever indices we
79a0842b40441db5332a5290f941021636b1182761Sol Boucher     * expose stable, we cannot simply remove them in such a case; instead, we insert {@code null}s
80a0842b40441db5332a5290f941021636b1182761Sol Boucher     * to invalidate any such indices.  Whenever new devices appear, they are appended to the end of
81a0842b40441db5332a5290f941021636b1182761Sol Boucher     * the list, and thereby assigned the lowest index that has never yet been used.
82a0842b40441db5332a5290f941021636b1182761Sol Boucher     */
83a0842b40441db5332a5290f941021636b1182761Sol Boucher    private final List<String> mCameraDevices;
84a0842b40441db5332a5290f941021636b1182761Sol Boucher
85a0842b40441db5332a5290f941021636b1182761Sol Boucher    AndroidCamera2AgentImpl(Context context) {
86a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraHandlerThread = new HandlerThread("Camera2 Handler Thread");
87a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraHandlerThread.start();
88a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraHandler = new Camera2Handler(mCameraHandlerThread.getLooper());
89a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraState = new AndroidCamera2StateHolder();
90a0842b40441db5332a5290f941021636b1182761Sol Boucher        mDispatchThread = new DispatchThread(mCameraHandler, mCameraHandlerThread);
91a0842b40441db5332a5290f941021636b1182761Sol Boucher        mDispatchThread.start();
92a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
93aa907a3b6637b4f95dbf572d0cf790a70ba3aeb0Sol Boucher        mNoisemaker = new MediaActionSound();
94aa907a3b6637b4f95dbf572d0cf790a70ba3aeb0Sol Boucher        mNoisemaker.load(MediaActionSound.SHUTTER_CLICK);
95a0842b40441db5332a5290f941021636b1182761Sol Boucher
96a0842b40441db5332a5290f941021636b1182761Sol Boucher        mNumCameraDevices = 0;
97a0842b40441db5332a5290f941021636b1182761Sol Boucher        mCameraDevices = new ArrayList<String>();
98a0842b40441db5332a5290f941021636b1182761Sol Boucher        updateCameraDevices();
99a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
100a0842b40441db5332a5290f941021636b1182761Sol Boucher
101a0842b40441db5332a5290f941021636b1182761Sol Boucher    /**
102a0842b40441db5332a5290f941021636b1182761Sol Boucher     * Updates the camera device index assignments stored in {@link mCameraDevices}, without
103a0842b40441db5332a5290f941021636b1182761Sol Boucher     * reappropriating any currently-assigned index.
104a0842b40441db5332a5290f941021636b1182761Sol Boucher     * @return Whether the operation was successful
105a0842b40441db5332a5290f941021636b1182761Sol Boucher     */
106a0842b40441db5332a5290f941021636b1182761Sol Boucher    private boolean updateCameraDevices() {
107a0842b40441db5332a5290f941021636b1182761Sol Boucher        try {
108a0842b40441db5332a5290f941021636b1182761Sol Boucher            String[] currentCameraDevices = mCameraManager.getCameraIdList();
109a0842b40441db5332a5290f941021636b1182761Sol Boucher            Set<String> currentSet = new HashSet<String>(Arrays.asList(currentCameraDevices));
110a0842b40441db5332a5290f941021636b1182761Sol Boucher
111a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Invalidate the indices assigned to any camera devices that are no longer present
112a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (int index = 0; index < mCameraDevices.size(); ++index) {
113a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (!currentSet.contains(mCameraDevices.get(index))) {
114a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCameraDevices.set(index, null);
115a0842b40441db5332a5290f941021636b1182761Sol Boucher                    --mNumCameraDevices;
116a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
117a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
118a0842b40441db5332a5290f941021636b1182761Sol Boucher
119a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Assign fresh indices to any new camera devices
120a0842b40441db5332a5290f941021636b1182761Sol Boucher            currentSet.removeAll(mCameraDevices); // The devices we didn't know about
121a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (String device : currentCameraDevices) {
122a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (currentSet.contains(device)) {
123a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCameraDevices.add(device);
124a0842b40441db5332a5290f941021636b1182761Sol Boucher                    ++mNumCameraDevices;
125a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
126a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
127a0842b40441db5332a5290f941021636b1182761Sol Boucher
128a0842b40441db5332a5290f941021636b1182761Sol Boucher            return true;
129a0842b40441db5332a5290f941021636b1182761Sol Boucher        } catch (CameraAccessException ex) {
130a0842b40441db5332a5290f941021636b1182761Sol Boucher            Log.e(TAG, "Could not get device listing from camera subsystem", ex);
131a0842b40441db5332a5290f941021636b1182761Sol Boucher            return false;
132a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
133a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
134a0842b40441db5332a5290f941021636b1182761Sol Boucher
135a0842b40441db5332a5290f941021636b1182761Sol Boucher    // TODO: Implement
136a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
137a0842b40441db5332a5290f941021636b1182761Sol Boucher    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
138a0842b40441db5332a5290f941021636b1182761Sol Boucher            Handler handler) {}
139a0842b40441db5332a5290f941021636b1182761Sol Boucher
140a0842b40441db5332a5290f941021636b1182761Sol Boucher    // TODO: Implement
141a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
142a0842b40441db5332a5290f941021636b1182761Sol Boucher    public void recycle() {}
143a0842b40441db5332a5290f941021636b1182761Sol Boucher
144a0842b40441db5332a5290f941021636b1182761Sol Boucher    // TODO: Some indices may now be invalid; ensure everyone can handle that and update the docs
145a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
146a0842b40441db5332a5290f941021636b1182761Sol Boucher    public CameraDeviceInfo getCameraDeviceInfo() {
147a0842b40441db5332a5290f941021636b1182761Sol Boucher        updateCameraDevices();
148a0842b40441db5332a5290f941021636b1182761Sol Boucher        return new AndroidCamera2DeviceInfo(mCameraManager, mCameraDevices.toArray(new String[0]),
149a0842b40441db5332a5290f941021636b1182761Sol Boucher                mNumCameraDevices);
150a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
151a0842b40441db5332a5290f941021636b1182761Sol Boucher
152a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
153a0842b40441db5332a5290f941021636b1182761Sol Boucher    protected Handler getCameraHandler() {
154a0842b40441db5332a5290f941021636b1182761Sol Boucher        return mCameraHandler;
155a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
156a0842b40441db5332a5290f941021636b1182761Sol Boucher
157a0842b40441db5332a5290f941021636b1182761Sol Boucher    @Override
158a0842b40441db5332a5290f941021636b1182761Sol Boucher    protected DispatchThread getDispatchThread() {
159a0842b40441db5332a5290f941021636b1182761Sol Boucher        return mDispatchThread;
160a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
161a0842b40441db5332a5290f941021636b1182761Sol Boucher
162de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher    private static abstract class CaptureAvailableListener
163de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            extends CameraCaptureSession.CaptureListener
164de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            implements ImageReader.OnImageAvailableListener {};
165de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
166a0842b40441db5332a5290f941021636b1182761Sol Boucher    private class Camera2Handler extends HistoryHandler {
167a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Caller-provided when leaving CAMERA_UNOPENED state:
168a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraOpenCallback mOpenCallback;
169a0842b40441db5332a5290f941021636b1182761Sol Boucher        private int mCameraIndex;
170a0842b40441db5332a5290f941021636b1182761Sol Boucher        private String mCameraId;
171a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
172a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in CAMERA_UNCONFIGURED state and above:
173a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraDevice mCamera;
174a0842b40441db5332a5290f941021636b1182761Sol Boucher        private AndroidCamera2ProxyImpl mCameraProxy;
175de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private Camera2RequestSettingsSet mPersistentSettings;
176a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private Rect mActiveArray;
177de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private boolean mLegacyDevice;
178a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
179a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in CAMERA_CONFIGURED state and above:
180a0842b40441db5332a5290f941021636b1182761Sol Boucher        private Size mPreviewSize;
181a0842b40441db5332a5290f941021636b1182761Sol Boucher        private Size mPhotoSize;
182a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
183a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in PREVIEW_READY state and above:
184a0842b40441db5332a5290f941021636b1182761Sol Boucher        private SurfaceTexture mPreviewTexture;
185a0842b40441db5332a5290f941021636b1182761Sol Boucher        private Surface mPreviewSurface;
186a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraCaptureSession mSession;
187de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private ImageReader mCaptureReader;
188a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
189a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available from the beginning of PREVIEW_ACTIVE until the first preview frame arrives:
190a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraStartPreviewCallback mOneshotPreviewingCallback;
191a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
192a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available in FOCUS_LOCKED between AF trigger receipt and whenever the lens stops moving:
193a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraAFCallback mOneshotAfCallback;
194a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
195de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        // Available when taking picture between AE trigger receipt and autoexposure convergence
196de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private CaptureAvailableListener mOneshotCaptureCallback;
197de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
198a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Available whenever setAutoFocusMoveCallback() was last invoked with a non-null argument:
199a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        private CameraAFMoveCallback mPassiveAfCallback;
200a0842b40441db5332a5290f941021636b1182761Sol Boucher
201984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        // Gets reset on every state change
202984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        private int mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE;
203984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
204a0842b40441db5332a5290f941021636b1182761Sol Boucher        Camera2Handler(Looper looper) {
205a0842b40441db5332a5290f941021636b1182761Sol Boucher            super(looper);
206a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
207a0842b40441db5332a5290f941021636b1182761Sol Boucher
208a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
209a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void handleMessage(final Message msg) {
210a0842b40441db5332a5290f941021636b1182761Sol Boucher            super.handleMessage(msg);
211a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
212a0842b40441db5332a5290f941021636b1182761Sol Boucher                switch(msg.what) {
213a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.OPEN_CAMERA:
214a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.RECONNECT: {
215a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraOpenCallback openCallback = (CameraOpenCallback) msg.obj;
216a0842b40441db5332a5290f941021636b1182761Sol Boucher                        int cameraIndex = msg.arg1;
217a0842b40441db5332a5290f941021636b1182761Sol Boucher
218772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher                        if (mCameraState.getState() > AndroidCamera2StateHolder.CAMERA_UNOPENED) {
219a0842b40441db5332a5290f941021636b1182761Sol Boucher                            openCallback.onDeviceOpenedAlready(cameraIndex,
220a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    generateHistoryString(cameraIndex));
221a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
222a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
223a0842b40441db5332a5290f941021636b1182761Sol Boucher
224a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback = openCallback;
225a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraIndex = cameraIndex;
226a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraId = mCameraDevices.get(mCameraIndex);
22750f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher                        Log.i(TAG, String.format("Opening camera index %d (id %s) with camera2 API",
22850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher                                cameraIndex, mCameraId));
229a0842b40441db5332a5290f941021636b1182761Sol Boucher
230a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraId == null) {
231a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mOpenCallback.onCameraDisabled(msg.arg1);
232a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
233a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
234a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraManager.openCamera(mCameraId, mCameraDeviceStateListener, this);
235a0842b40441db5332a5290f941021636b1182761Sol Boucher
236a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
237a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
238a0842b40441db5332a5290f941021636b1182761Sol Boucher
239a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.RELEASE: {
240a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() == AndroidCamera2StateHolder.CAMERA_UNOPENED) {
241a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring release at inappropriate time");
242a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
243a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
244a0842b40441db5332a5290f941021636b1182761Sol Boucher
245a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mSession != null) {
246a0842b40441db5332a5290f941021636b1182761Sol Boucher                            closePreviewSession();
247a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            mSession = null;
248a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
249a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCamera != null) {
250a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mCamera.close();
251a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mCamera = null;
252a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
253a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraProxy = null;
254de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        mPersistentSettings = null;
255a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mActiveArray = null;
256a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mPreviewSurface != null) {
257a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mPreviewSurface.release();
258a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mPreviewSurface = null;
259a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
260a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPreviewTexture = null;
261de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        if (mCaptureReader != null) {
262de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mCaptureReader.close();
263de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mCaptureReader = null;
264de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        }
265a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPreviewSize = null;
266a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mPhotoSize = null;
267a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraIndex = 0;
268a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraId = null;
269984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        changeState(AndroidCamera2StateHolder.CAMERA_UNOPENED);
270a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
271a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
272a0842b40441db5332a5290f941021636b1182761Sol Boucher
273a0842b40441db5332a5290f941021636b1182761Sol Boucher                    /*case CameraActions.UNLOCK: {
274a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
275a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
276a0842b40441db5332a5290f941021636b1182761Sol Boucher
277a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.LOCK: {
278a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
279a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
280a0842b40441db5332a5290f941021636b1182761Sol Boucher
281a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_TEXTURE_ASYNC: {
282a0842b40441db5332a5290f941021636b1182761Sol Boucher                        setPreviewTexture((SurfaceTexture) msg.obj);
283a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
284a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
285a0842b40441db5332a5290f941021636b1182761Sol Boucher
286a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.START_PREVIEW_ASYNC: {
287a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mCameraState.getState() !=
288a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
289a0842b40441db5332a5290f941021636b1182761Sol Boucher                            // TODO: Provide better feedback here?
290a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Refusing to start preview at inappropriate time");
291a0842b40441db5332a5290f941021636b1182761Sol Boucher                            break;
292a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
293a0842b40441db5332a5290f941021636b1182761Sol Boucher
294a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mOneshotPreviewingCallback = (CameraStartPreviewCallback) msg.obj;
295984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
296a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
297de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mSession.setRepeatingRequest(
298de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    mPersistentSettings.createRequest(mCamera,
299de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                            CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface),
300984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    /*listener*/mCameraResultStateListener, /*handler*/this);
301a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
302a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Unable to start preview", ex);
303984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
304a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
305a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
306a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
307a0842b40441db5332a5290f941021636b1182761Sol Boucher
3082569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher                    // FIXME: We need to tear down the CameraCaptureSession here
3092569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher                    // (and unlock the CameraSettings object from our
3102569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher                    // CameraProxy) so that the preview/photo sizes can be
3112569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher                    // changed again while no preview is running.
312a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.STOP_PREVIEW: {
313a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
314a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
315a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Refusing to stop preview at inappropriate time");
316a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
317a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
318a0842b40441db5332a5290f941021636b1182761Sol Boucher
319a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mSession.stopRepeating();
320984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
321a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
322a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
323a0842b40441db5332a5290f941021636b1182761Sol Boucher
324a0842b40441db5332a5290f941021636b1182761Sol Boucher                    /*case CameraActions.SET_PREVIEW_CALLBACK_WITH_BUFFER: {
325a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
326a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
327a0842b40441db5332a5290f941021636b1182761Sol Boucher
328a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.ADD_CALLBACK_BUFFER: {
329a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
330a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
331a0842b40441db5332a5290f941021636b1182761Sol Boucher
332a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_DISPLAY_ASYNC: {
333a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
334a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
335a0842b40441db5332a5290f941021636b1182761Sol Boucher
336a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PREVIEW_CALLBACK: {
337a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
338a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
339a0842b40441db5332a5290f941021636b1182761Sol Boucher
340a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_ONE_SHOT_PREVIEW_CALLBACK: {
341a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
342a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
343a0842b40441db5332a5290f941021636b1182761Sol Boucher
344a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_PARAMETERS: {
345a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
346a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
347a0842b40441db5332a5290f941021636b1182761Sol Boucher
348a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.GET_PARAMETERS: {
349a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
350a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
351a0842b40441db5332a5290f941021636b1182761Sol Boucher
352a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.REFRESH_PARAMETERS: {
353a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
354a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }*/
355a0842b40441db5332a5290f941021636b1182761Sol Boucher
356a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.APPLY_SETTINGS: {
357de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        AndroidCamera2Settings settings = (AndroidCamera2Settings) msg.obj;
358a0842b40441db5332a5290f941021636b1182761Sol Boucher                        applyToRequest(settings);
359a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
360a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
361a0842b40441db5332a5290f941021636b1182761Sol Boucher
362a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    case CameraActions.AUTO_FOCUS: {
363a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // We only support locking the focus while a preview is being displayed.
364a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // However, it can be requested multiple times in succession; the effect of
365a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // the subsequent invocations is determined by the focus mode defined in the
366a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // provided CameraSettings object. In passive (CONTINUOUS_*) mode, the
367a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // duplicate requests are no-ops and leave the lens locked at its current
368a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // position, but in active (AUTO) mode, they perform another scan and lock
369a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // once that is finished. In any manual focus mode, this call is a no-op,
370a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // and most notably, this is the only case where the callback isn't invoked.
371a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
372a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
373a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring attempt to autofocus without preview");
374a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
375a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
376a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
377a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // The earliest we can reliably tell whether the autofocus has locked in
378984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        // response to our latest request is when our one-time capture progresses.
379a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // However, it will probably take longer than that, so once that happens,
380a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // just start checking the repeating preview requests as they complete.
381a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        final CameraAFCallback callback = (CameraAFCallback) msg.obj;
382a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        CameraCaptureSession.CaptureListener deferredCallbackSetter =
383a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                new CameraCaptureSession.CaptureListener() {
384984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            private boolean mAlreadyDispatched = false;
385984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
386984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            @Override
387984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            public void onCaptureProgressed(CameraCaptureSession session,
388984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                            CaptureRequest request,
389984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                            CaptureResult result) {
390984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                checkAfState(result);
391984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            }
392984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
393a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
394a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onCaptureCompleted(CameraCaptureSession session,
395a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                           CaptureRequest request,
396a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                           TotalCaptureResult result) {
397984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                checkAfState(result);
398984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            }
399984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
400984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            private void checkAfState(CaptureResult result) {
401984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                if (result.get(CaptureResult.CONTROL_AF_STATE) != null &&
402984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        !mAlreadyDispatched) {
403984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // Now our mCameraResultStateListener will invoke the callback
404984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // the first time it finds the focus motor to be locked.
405984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mAlreadyDispatched = true;
406984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mOneshotAfCallback = callback;
407984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // This is an optimization: check the AF state of this frame
408984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // instead of simply waiting for the next.
409984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mCameraResultStateListener.monitorControlStates(result);
410984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                }
411a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
412a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
413a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
414a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onCaptureFailed(CameraCaptureSession session,
415a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                        CaptureRequest request,
416a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                        CaptureFailure failure) {
417a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                Log.e(TAG, "Focusing failed with reason " + failure.getReason());
418a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                callback.onAutoFocus(false, mCameraProxy);
419a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }};
420a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
421a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Send a one-time capture to trigger the camera driver to lock focus.
422984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        changeState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
423de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        Camera2RequestSettingsSet trigger =
424de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                new Camera2RequestSettingsSet(mPersistentSettings);
425de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        trigger.set(CaptureRequest.CONTROL_AF_TRIGGER,
426a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_START);
427a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
428de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mSession.capture(
429de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    trigger.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW,
430de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                            mPreviewSurface),
431a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    /*listener*/deferredCallbackSetter, /*handler*/ this);
432a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
433a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.e(TAG, "Unable to lock autofocus", ex);
434984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
435a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
436a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
437a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
438a0842b40441db5332a5290f941021636b1182761Sol Boucher
439a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.CANCEL_AUTO_FOCUS: {
440a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Why would you want to unlock the lens if it isn't already locked?
441a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        if (mCameraState.getState() <
442a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
443a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.w(TAG, "Ignoring attempt to release focus lock without preview");
444a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            break;
445a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
446a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
447a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        // Send a one-time capture to trigger the camera driver to resume scanning.
448984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE);
449de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        Camera2RequestSettingsSet cancel =
450de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                new Camera2RequestSettingsSet(mPersistentSettings);
451de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        cancel.set(CaptureRequest.CONTROL_AF_TRIGGER,
452a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);
453a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        try {
454de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mSession.capture(
455de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    cancel.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW,
456de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                            mPreviewSurface),
457a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    /*listener*/null, /*handler*/this);
458a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        } catch(CameraAccessException ex) {
459a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            Log.e(TAG, "Unable to cancel autofocus", ex);
460984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            changeState(AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
461a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
462a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
463a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
464a0842b40441db5332a5290f941021636b1182761Sol Boucher
465a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK: {
466a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mPassiveAfCallback = (CameraAFMoveCallback) msg.obj;
467a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
468a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
469a0842b40441db5332a5290f941021636b1182761Sol Boucher
470a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    /*case CameraActions.SET_ZOOM_CHANGE_LISTENER: {
471a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
472a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
473a0842b40441db5332a5290f941021636b1182761Sol Boucher
474a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_FACE_DETECTION_LISTENER: {
475a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
476a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
477a0842b40441db5332a5290f941021636b1182761Sol Boucher
478a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.START_FACE_DETECTION: {
479a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
480a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
481a0842b40441db5332a5290f941021636b1182761Sol Boucher
482a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.STOP_FACE_DETECTION: {
483a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
484a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
485a0842b40441db5332a5290f941021636b1182761Sol Boucher
486a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_ERROR_CALLBACK: {
487a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
488a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
489a0842b40441db5332a5290f941021636b1182761Sol Boucher
490a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.ENABLE_SHUTTER_SOUND: {
491a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
492de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    }*/
493a0842b40441db5332a5290f941021636b1182761Sol Boucher
494a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.SET_DISPLAY_ORIENTATION: {
495de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        // Only set the JPEG capture orientation if requested to do so; otherwise,
496de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        // capture in the sensor's physical orientation
497de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg2 > 0 ?
498de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                mCameraProxy.getCharacteristics().getJpegOrientation(msg.arg1) : 0);
499a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
500a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
501a0842b40441db5332a5290f941021636b1182761Sol Boucher
502a0842b40441db5332a5290f941021636b1182761Sol Boucher                    case CameraActions.CAPTURE_PHOTO: {
503de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        if (mCameraState.getState() <
504de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                        AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
505de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            Log.e(TAG, "Photos may only be taken when a preview is active");
506de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            break;
507de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        }
508de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        if (mCameraState.getState() !=
509de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED) {
510de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            Log.w(TAG, "Taking a (likely blurry) photo without the lens locked");
511de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        }
512de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
513de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        final CaptureAvailableListener listener =
514de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                (CaptureAvailableListener) msg.obj;
515984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        if (mLegacyDevice ||
516984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                (mCurrentAeState == CaptureResult.CONTROL_AE_STATE_CONVERGED &&
517984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                !mPersistentSettings.matches(CaptureRequest.CONTROL_AE_MODE,
518984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH) &&
519984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                !mPersistentSettings.matches(CaptureRequest.FLASH_MODE,
520984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        CaptureRequest.FLASH_MODE_SINGLE)))
521984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                {
522984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // Legacy devices don't support the precapture state keys and instead
523984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // perform autoexposure convergence automatically upon capture.
524984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
525984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // On other devices, as long as it has already converged, it determined
526984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // that flash was not required, and we're not going to invalidate the
527984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // current exposure levels by forcing the force on, we can save
528984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // significant capture time by not forcing a recalculation.
529984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            Log.i(TAG, "Skipping pre-capture autoexposure convergence");
530de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mCaptureReader.setOnImageAvailableListener(listener, /*handler*/this);
531de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            try {
532de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                mSession.capture(
533de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                        mPersistentSettings.createRequest(mCamera,
534de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                CameraDevice.TEMPLATE_STILL_CAPTURE,
535de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                mCaptureReader.getSurface()),
536de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                        listener, /*handler*/this);
537de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            } catch (CameraAccessException ex) {
538984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                Log.e(TAG, "Unable to initiate immediate capture", ex);
539de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            }
540de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        } else {
541984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // We need to let AE converge before capturing. Once our one-time
542984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // trigger capture has made it into the pipeline, we'll start checking
543984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            // for the completion of that convergence, capturing when that happens.
544984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            Log.i(TAG, "Forcing pre-capture autoexposure convergence");
545de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            CameraCaptureSession.CaptureListener deferredCallbackSetter =
546de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    new CameraCaptureSession.CaptureListener() {
547984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                private boolean mAlreadyDispatched = false;
548984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
549984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                @Override
550984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                public void onCaptureProgressed(CameraCaptureSession session,
551984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                                CaptureRequest request,
552984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                                CaptureResult result) {
553984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    checkAeState(result);
554984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                }
555984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
556de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                @Override
557de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                public void onCaptureCompleted(CameraCaptureSession session,
558de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                               CaptureRequest request,
559de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                               TotalCaptureResult result) {
560984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    checkAeState(result);
561984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                }
562984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
563984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                private void checkAeState(CaptureResult result) {
564984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    if (result.get(CaptureResult.CONTROL_AE_STATE) != null &&
565984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                            !mAlreadyDispatched) {
566984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        // Now our mCameraResultStateListener will invoke the
567984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        // callback once the autoexposure routine has converged.
568984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        mAlreadyDispatched = true;
569984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        mOneshotCaptureCallback = listener;
570984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        // This is an optimization: check the AE state of this frame
571984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        // instead of simply waiting for the next.
572984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        mCameraResultStateListener.monitorControlStates(result);
573984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    }
574de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                }
575de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
576de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                @Override
577de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                public void onCaptureFailed(CameraCaptureSession session,
578de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                            CaptureRequest request,
579de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                            CaptureFailure failure) {
580de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    Log.e(TAG, "Autoexposure and capture failed with reason " +
581de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                            failure.getReason());
582de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    // TODO: Make an error callback?
583de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                }};
584de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
585de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            // Set a one-time capture to trigger the camera driver's autoexposure:
586de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            Camera2RequestSettingsSet expose =
587de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    new Camera2RequestSettingsSet(mPersistentSettings);
588de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            expose.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
589de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
590de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            try {
591de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                mSession.capture(
592de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                        expose.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW,
593de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                                mPreviewSurface),
594de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                        /*listener*/deferredCallbackSetter, /*handler*/this);
595de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            } catch (CameraAccessException ex) {
596de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                Log.e(TAG, "Unable to run autoexposure and perform capture", ex);
597de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            }
598de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        }
599a0842b40441db5332a5290f941021636b1182761Sol Boucher                        break;
600de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    }
601a0842b40441db5332a5290f941021636b1182761Sol Boucher
602a0842b40441db5332a5290f941021636b1182761Sol Boucher                    default: {
603a0842b40441db5332a5290f941021636b1182761Sol Boucher                        // TODO: Rephrase once everything has been implemented
604a0842b40441db5332a5290f941021636b1182761Sol Boucher                        throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what);
605a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
606a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
607a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (final Exception ex) {
608a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (msg.what != CameraActions.RELEASE && mCamera != null) {
609a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // TODO: Handle this better
610a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCamera.close();
611a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mCamera = null;
612a0842b40441db5332a5290f941021636b1182761Sol Boucher                } else if (mCamera == null) {
613a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (msg.what == CameraActions.OPEN_CAMERA) {
614a0842b40441db5332a5290f941021636b1182761Sol Boucher                        if (mOpenCallback != null) {
615a0842b40441db5332a5290f941021636b1182761Sol Boucher                            mOpenCallback.onDeviceOpenFailure(mCameraIndex,
616a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    generateHistoryString(mCameraIndex));
617a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }
618a0842b40441db5332a5290f941021636b1182761Sol Boucher                    } else {
619a0842b40441db5332a5290f941021636b1182761Sol Boucher                        Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null");
620a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
621a0842b40441db5332a5290f941021636b1182761Sol Boucher                    return;
622a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
623a0842b40441db5332a5290f941021636b1182761Sol Boucher
624a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (ex instanceof RuntimeException) {
625a0842b40441db5332a5290f941021636b1182761Sol Boucher                    post(new Runnable() {
626a0842b40441db5332a5290f941021636b1182761Sol Boucher                        @Override
627a0842b40441db5332a5290f941021636b1182761Sol Boucher                        public void run() {
628a0842b40441db5332a5290f941021636b1182761Sol Boucher                            sCameraExceptionCallback.onCameraException((RuntimeException) ex);
629a0842b40441db5332a5290f941021636b1182761Sol Boucher                        }});
630a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
631a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
632a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
633a0842b40441db5332a5290f941021636b1182761Sol Boucher
634a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraSettings buildSettings(AndroidCamera2Capabilities caps) {
635de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            try {
636de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                return new AndroidCamera2Settings(mCamera, CameraDevice.TEMPLATE_PREVIEW,
637de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        mActiveArray, mPreviewSize, mPhotoSize);
638de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            } catch (CameraAccessException ex) {
639de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                Log.e(TAG, "Unable to query camera device to build settings representation");
640de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                return null;
641de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            }
642a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
643a0842b40441db5332a5290f941021636b1182761Sol Boucher
644a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        /**
645a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * Simply propagates settings from provided {@link CameraSettings}
646a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * object to our {@link CaptureRequest.Builder} for use in captures.
647a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * <p>Most conversions to match the API 2 formats are performed by
648a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise
649a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * any final adjustments are done here before updating the builder.</p>
650a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         *
651a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         * @param settings The new/updated settings
652a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher         */
653de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private void applyToRequest(AndroidCamera2Settings settings) {
654a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect
655de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
656de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            mPersistentSettings.union(settings.getRequestSettings());
657a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewSize = settings.getCurrentPreviewSize();
658a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPhotoSize = settings.getCurrentPhotoSize();
659a0842b40441db5332a5290f941021636b1182761Sol Boucher
660a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
661a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                // If we're already previewing, reflect most settings immediately
662a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                try {
663de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    mSession.setRepeatingRequest(
664de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            mPersistentSettings.createRequest(mCamera,
665de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface),
666984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            /*listener*/mCameraResultStateListener, /*handler*/this);
667a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                } catch (CameraAccessException ex) {
668a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    Log.e(TAG, "Failed to apply updated request settings", ex);
669a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
670a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) {
671a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                // If we're already ready to preview, this doesn't regress our state
672984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
673a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
674a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
675a0842b40441db5332a5290f941021636b1182761Sol Boucher
676a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void setPreviewTexture(SurfaceTexture surfaceTexture) {
677a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: Must be called after providing a .*Settings populated with sizes
678a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures!
679a0842b40441db5332a5290f941021636b1182761Sol Boucher
680a0842b40441db5332a5290f941021636b1182761Sol Boucher            // TODO: Handle this error condition with a callback or exception
681a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) {
682a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Log.w(TAG, "Ignoring texture setting at inappropriate time");
683a0842b40441db5332a5290f941021636b1182761Sol Boucher                return;
684a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
685a0842b40441db5332a5290f941021636b1182761Sol Boucher
686a0842b40441db5332a5290f941021636b1182761Sol Boucher            // Avoid initializing another capture session unless we absolutely have to
687a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (surfaceTexture == mPreviewTexture) {
688a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.i(TAG, "Optimizing out redundant preview texture setting");
689a0842b40441db5332a5290f941021636b1182761Sol Boucher                return;
690a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
691a0842b40441db5332a5290f941021636b1182761Sol Boucher
692a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            if (mSession != null) {
693a0842b40441db5332a5290f941021636b1182761Sol Boucher                closePreviewSession();
694a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
695a0842b40441db5332a5290f941021636b1182761Sol Boucher
696a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewTexture = surfaceTexture;
697a0842b40441db5332a5290f941021636b1182761Sol Boucher            surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height());
698a0842b40441db5332a5290f941021636b1182761Sol Boucher
699a0842b40441db5332a5290f941021636b1182761Sol Boucher            if (mPreviewSurface != null) {
700a0842b40441db5332a5290f941021636b1182761Sol Boucher                mPreviewSurface.release();
701a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
702a0842b40441db5332a5290f941021636b1182761Sol Boucher            mPreviewSurface = new Surface(surfaceTexture);
703de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
704de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            if (mCaptureReader != null) {
705de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                mCaptureReader.close();
706de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            }
707de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            mCaptureReader = ImageReader.newInstance(
708de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    mPhotoSize.width(), mPhotoSize.height(), ImageFormat.JPEG, 1);
709a0842b40441db5332a5290f941021636b1182761Sol Boucher
710a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
711de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                mCamera.createCaptureSession(
712de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        Arrays.asList(mPreviewSurface, mCaptureReader.getSurface()),
713a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraPreviewStateListener, this);
714a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
715a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to create camera capture session", ex);
716a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
717a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
718a0842b40441db5332a5290f941021636b1182761Sol Boucher
719a0842b40441db5332a5290f941021636b1182761Sol Boucher        private void closePreviewSession() {
720a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
721a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession.abortCaptures();
722a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession = null;
723a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
724a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to close existing camera capture session", ex);
725a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
726984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED);
727984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        }
728984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
729984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        private void changeState(int newState) {
730984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            if (mCameraState.getState() != newState) {
731984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                mCameraState.setState(newState);
732984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                if (newState < AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) {
733984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE;
734984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    mCameraResultStateListener.resetState();
735984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                }
736984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            }
737a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
738a0842b40441db5332a5290f941021636b1182761Sol Boucher
739a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors our connection to and disconnection from camera devices.
740a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraDevice.StateListener mCameraDeviceStateListener =
741a0842b40441db5332a5290f941021636b1182761Sol Boucher                new CameraDevice.StateListener() {
742a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
743a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onOpened(CameraDevice camera) {
744a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCamera = camera;
745a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (mOpenCallback != null) {
746a0842b40441db5332a5290f941021636b1182761Sol Boucher                    try {
747a0842b40441db5332a5290f941021636b1182761Sol Boucher                        CameraCharacteristics props =
748a0842b40441db5332a5290f941021636b1182761Sol Boucher                                mCameraManager.getCameraCharacteristics(mCameraId);
749a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera,
750a0842b40441db5332a5290f941021636b1182761Sol Boucher                                    getCameraDeviceInfo().getCharacteristics(mCameraIndex), props);
751de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        mPersistentSettings = new Camera2RequestSettingsSet();
752a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mActiveArray =
753a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
754de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        mLegacyDevice =
755de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) ==
756de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                        CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
757984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        changeState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED);
758a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback.onCameraOpened(mCameraProxy);
759a0842b40441db5332a5290f941021636b1182761Sol Boucher                    } catch (CameraAccessException ex) {
760a0842b40441db5332a5290f941021636b1182761Sol Boucher                        mOpenCallback.onDeviceOpenFailure(mCameraIndex,
761a0842b40441db5332a5290f941021636b1182761Sol Boucher                                generateHistoryString(mCameraIndex));
762a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
763a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
764a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
765a0842b40441db5332a5290f941021636b1182761Sol Boucher
766a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
767a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onDisconnected(CameraDevice camera) {
768a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected");
769a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
770a0842b40441db5332a5290f941021636b1182761Sol Boucher
771a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
772a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onError(CameraDevice camera, int error) {
773a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" +
774a0842b40441db5332a5290f941021636b1182761Sol Boucher                        error + '\'');
775a0842b40441db5332a5290f941021636b1182761Sol Boucher                if (mOpenCallback != null) {
776a0842b40441db5332a5290f941021636b1182761Sol Boucher                    mOpenCallback.onDeviceOpenFailure(mCameraIndex,
777a0842b40441db5332a5290f941021636b1182761Sol Boucher                            generateHistoryString(mCameraIndex));
778a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
779a0842b40441db5332a5290f941021636b1182761Sol Boucher            }};
780a0842b40441db5332a5290f941021636b1182761Sol Boucher
781a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors our camera session (i.e. our transition into and out of preview).
782a0842b40441db5332a5290f941021636b1182761Sol Boucher        private CameraCaptureSession.StateListener mCameraPreviewStateListener =
783a0842b40441db5332a5290f941021636b1182761Sol Boucher                new CameraCaptureSession.StateListener() {
784a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
785a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onConfigured(CameraCaptureSession session) {
786a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                mSession = session;
787984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY);
788a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
789a0842b40441db5332a5290f941021636b1182761Sol Boucher
790a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
791a0842b40441db5332a5290f941021636b1182761Sol Boucher            public void onConfigureFailed(CameraCaptureSession session) {
792a0842b40441db5332a5290f941021636b1182761Sol Boucher                // TODO: Invoke a callback
793a0842b40441db5332a5290f941021636b1182761Sol Boucher                Log.e(TAG, "Failed to configure the camera for capture");
794a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
795a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
796a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
797a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onActive(CameraCaptureSession session) {
798a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                if (mOneshotPreviewingCallback != null) {
799a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    // The session is up and processing preview requests. Inform the caller.
800a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mOneshotPreviewingCallback.onPreviewStarted();
801a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mOneshotPreviewingCallback = null;
802a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
803a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }};
804a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
805984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        private abstract class CameraResultStateListener
806984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                extends CameraCaptureSession.CaptureListener {
807984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            public abstract void monitorControlStates(CaptureResult result);
808984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
809984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            public abstract void resetState();
810984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        }
811984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
812a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // This listener monitors requested captures and notifies any relevant callbacks.
813984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher        private CameraResultStateListener mCameraResultStateListener =
814984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                new CameraResultStateListener() {
815a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            private int mLastAfState = -1;
816984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            private long mLastAfFrameNumber = -1;
817984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            private long mLastAeFrameNumber = -1;
818984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
819984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            @Override
820984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request,
821984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                            CaptureResult result) {
822984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                monitorControlStates(result);
823984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            }
824a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
825a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
826a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
827a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                           TotalCaptureResult result) {
828984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                monitorControlStates(result);
829984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            }
830984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
831984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            @Override
832984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            public void monitorControlStates(CaptureResult result) {
833a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE);
834a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                if (afStateMaybe != null) {
835a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    int afState = afStateMaybe;
836984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // Since we handle both partial and total results for multiple frames here, we
837984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // might get the final callbacks for an earlier frame after receiving one or
838984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // more that correspond to the next one. To prevent our data from oscillating,
839984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // we never consider AF states that are older than the last one we've seen.
840984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    if (result.getFrameNumber() > mLastAfFrameNumber) {
841984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        boolean afStateChanged = afState != mLastAfState;
842a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        mLastAfState = afState;
843984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        mLastAfFrameNumber = result.getFrameNumber();
844984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
845984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        switch (afState) {
846984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN:
847984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED:
848984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: {
849984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                if (afStateChanged && mPassiveAfCallback != null) {
850984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // A CameraAFMoveCallback is attached. If we just started to
851984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // scan, the motor is moving; otherwise, it has settled.
852984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mPassiveAfCallback.onAutoFocusMoving(
853984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                            afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN,
854984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                            mCameraProxy);
855984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                }
856984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                break;
857a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
858a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
859984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
860984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: {
8617d71703202c2fba36653293eba2772745db46c00Sol Boucher                                // This check must be made regardless of whether the focus state has
8627d71703202c2fba36653293eba2772745db46c00Sol Boucher                                // changed recently to avoid infinite waiting during autoFocus()
8637d71703202c2fba36653293eba2772745db46c00Sol Boucher                                // when the algorithm has already either converged or failed to.
864984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                if (mOneshotAfCallback != null) {
865984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // A call to autoFocus() was just made to request a focus lock.
866984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // Notify the caller that the lens is now indefinitely fixed,
867984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // and report whether the image we're stuck with is in focus.
868984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mOneshotAfCallback.onAutoFocus(
869984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                            afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED,
870984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                            mCameraProxy);
871984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mOneshotAfCallback = null;
872984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                }
873984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                break;
874a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }
875a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        }
876a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
877a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }
878de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
879de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                Integer aeStateMaybe = result.get(CaptureResult.CONTROL_AE_STATE);
880de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                if (aeStateMaybe != null) {
881de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    int aeState = aeStateMaybe;
882984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // Since we handle both partial and total results for multiple frames here, we
883984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // might get the final callbacks for an earlier frame after receiving one or
884984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // more that correspond to the next one. To prevent our data from oscillating,
885984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                    // we never consider AE states that are older than the last one we've seen.
8867d71703202c2fba36653293eba2772745db46c00Sol Boucher                    if (result.getFrameNumber() > mLastAeFrameNumber) {
887984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        mCurrentAeState = aeStateMaybe;
888984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        mLastAeFrameNumber = result.getFrameNumber();
889984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
890984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                        switch (aeState) {
891984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AE_STATE_CONVERGED:
892984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED:
893984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                            case CaptureResult.CONTROL_AE_STATE_LOCKED: {
8947d71703202c2fba36653293eba2772745db46c00Sol Boucher                                // This check must be made regardless of whether the exposure state
8957d71703202c2fba36653293eba2772745db46c00Sol Boucher                                // has changed recently to avoid infinite waiting during
8967d71703202c2fba36653293eba2772745db46c00Sol Boucher                                // takePicture() when the algorithm has already converged.
897984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                if (mOneshotCaptureCallback != null) {
898984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // A call to takePicture() was just made, and autoexposure
899984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    // converged so it's time to initiate the capture!
900984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    mCaptureReader.setOnImageAvailableListener(
901de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                            /*listener*/mOneshotCaptureCallback,
902de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                            /*handler*/Camera2Handler.this);
903984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    try {
904984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        mSession.capture(
905984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                mPersistentSettings.createRequest(mCamera,
906984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                        CameraDevice.TEMPLATE_STILL_CAPTURE,
907984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                        mCaptureReader.getSurface()),
908984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                /*listener*/mOneshotCaptureCallback,
909984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                                /*handler*/Camera2Handler.this);
910984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    } catch (CameraAccessException ex) {
911984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        Log.e(TAG, "Unable to initiate capture", ex);
912984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    } finally {
913984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                        mOneshotCaptureCallback = null;
914984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                    }
915de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                }
916984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                                break;
917de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            }
918de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        }
919de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    }
920de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                }
921a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            }
922a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
923a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            @Override
924984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            public void resetState() {
925984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                mLastAfState = -1;
926984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                mLastAfFrameNumber = -1;
927984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher                mLastAeFrameNumber = -1;
928984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            }
929984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher
930984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher            @Override
931a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
932a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        CaptureFailure failure) {
933a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                Log.e(TAG, "Capture attempt failed with reason " + failure.getReason());
934a0842b40441db5332a5290f941021636b1182761Sol Boucher            }};
935a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
936a0842b40441db5332a5290f941021636b1182761Sol Boucher
937a0842b40441db5332a5290f941021636b1182761Sol Boucher    private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy {
938a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mCameraIndex;
939a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraDevice mCamera;
940a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraDeviceInfo.Characteristics mCharacteristics;
941a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final AndroidCamera2Capabilities mCapabilities;
94280cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher        private CameraSettings mLastSettings;
943a0842b40441db5332a5290f941021636b1182761Sol Boucher
944a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera,
945a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraDeviceInfo.Characteristics characteristics,
946a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraCharacteristics properties) {
947a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraIndex = cameraIndex;
948a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCamera = camera;
949a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCharacteristics = characteristics;
950a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCapabilities = new AndroidCamera2Capabilities(properties);
95180cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher            mLastSettings = null;
952a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
953a0842b40441db5332a5290f941021636b1182761Sol Boucher
954a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
955a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
956a0842b40441db5332a5290f941021636b1182761Sol Boucher        public android.hardware.Camera getCamera() { return null; }
957a0842b40441db5332a5290f941021636b1182761Sol Boucher
958a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
959a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getCameraId() {
960a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraIndex;
961a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
962a0842b40441db5332a5290f941021636b1182761Sol Boucher
963a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
964a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraDeviceInfo.Characteristics getCharacteristics() {
965a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCharacteristics;
966a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
967a0842b40441db5332a5290f941021636b1182761Sol Boucher
968a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
969a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraCapabilities getCapabilities() {
970a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCapabilities;
971a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
972a0842b40441db5332a5290f941021636b1182761Sol Boucher
973a0842b40441db5332a5290f941021636b1182761Sol Boucher        private AndroidCamera2Capabilities getSpecializedCapabilities() {
974a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCapabilities;
975a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
976a0842b40441db5332a5290f941021636b1182761Sol Boucher
9772569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
9782569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        // explanation on the STOP_PREVIEW case in the handler.
9792569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        @Override
9802569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        public void setPreviewTexture(SurfaceTexture surfaceTexture) {
9812569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            // Once the Surface has been selected, we configure the session and
9822569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            // are no longer able to change the sizes.
9832569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            getSettings().setSizesLocked(true);
9842569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            super.setPreviewTexture(surfaceTexture);
9852569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        }
9862569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher
9872569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        // FIXME: Unlock the sizes in stopPreview(), as per the corresponding
9882569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        // explanation on the STOP_PREVIEW case in the handler.
9892569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        @Override
9902569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        public void setPreviewTextureSync(SurfaceTexture surfaceTexture) {
9912569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            // Once the Surface has been selected, we configure the session and
9922569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            // are no longer able to change the sizes.
9932569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            getSettings().setSizesLocked(true);
9942569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher            super.setPreviewTexture(surfaceTexture);
9952569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher        }
9962569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher
997a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
998a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
999a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {}
1000a0842b40441db5332a5290f941021636b1182761Sol Boucher
1001a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1002a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1003a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {}
1004a0842b40441db5332a5290f941021636b1182761Sol Boucher
1005a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1006a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1007a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb)
1008a0842b40441db5332a5290f941021636b1182761Sol Boucher                {}
1009a0842b40441db5332a5290f941021636b1182761Sol Boucher
101050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher        // TODO: Implement
101150f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher        public void addCallbackBuffer(final byte[] callbackBuffer) {}
101250f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher
1013a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1014a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void autoFocus(final Handler handler, final CameraAFCallback cb) {
1015a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mDispatchThread.runJob(new Runnable() {
1016a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                @Override
1017a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                public void run() {
1018a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    CameraAFCallback cbForward = null;
1019a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (cb != null) {
1020a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        cbForward = new CameraAFCallback() {
1021a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
1022a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onAutoFocus(final boolean focused,
1023a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                    final CameraProxy camera) {
1024a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                handler.post(new Runnable() {
1025a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    @Override
1026a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    public void run() {
1027a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        cb.onAutoFocus(focused, camera);
1028a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    }});
1029a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            }};
1030a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
1031a0842b40441db5332a5290f941021636b1182761Sol Boucher
1032a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE |
1033a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED);
1034a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward)
1035a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            .sendToTarget();
1036a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }});
1037a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
1038a0842b40441db5332a5290f941021636b1182761Sol Boucher
1039a0842b40441db5332a5290f941021636b1182761Sol Boucher        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
1040a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1041a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) {
1042a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher            mDispatchThread.runJob(new Runnable() {
1043a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                @Override
1044a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                public void run() {
1045a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    CameraAFMoveCallback cbForward = null;
1046a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    if (cb != null) {
1047a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                        cbForward = new CameraAFMoveCallback() {
1048a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            @Override
1049a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            public void onAutoFocusMoving(final boolean moving,
1050a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                                          final CameraProxy camera) {
1051a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                handler.post(new Runnable() {
1052a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    @Override
1053a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    public void run() {
1054a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                        cb.onAutoFocusMoving(moving, camera);
1055a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                    }});
1056a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                                }};
1057a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    }
1058a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
1059a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                    mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK,
1060a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                            cbForward).sendToTarget();
1061a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher                }});
1062a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        }
1063a0842b40441db5332a5290f941021636b1182761Sol Boucher
1064a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1065de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        public void takePicture(final Handler handler,
1066de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                final CameraShutterCallback shutter,
1067a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback raw,
1068a0842b40441db5332a5290f941021636b1182761Sol Boucher                                CameraPictureCallback postview,
1069de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                final CameraPictureCallback jpeg) {
1070de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            // TODO: We never call raw or postview
1071de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            final CaptureAvailableListener picListener =
1072de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    new CaptureAvailableListener() {
1073de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                @Override
1074de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request,
1075de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                             long timestamp) {
1076de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    if (shutter != null) {
1077de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        handler.post(new Runnable() {
1078de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            @Override
1079de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            public void run() {
1080aa907a3b6637b4f95dbf572d0cf790a70ba3aeb0Sol Boucher                                mNoisemaker.play(MediaActionSound.SHUTTER_CLICK);
1081de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                shutter.onShutter(AndroidCamera2ProxyImpl.this);
1082de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            }});
1083de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    }
1084de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                }
1085a0842b40441db5332a5290f941021636b1182761Sol Boucher
1086de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                @Override
1087de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                public void onImageAvailable(ImageReader reader) {
1088de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    try (Image image = reader.acquireNextImage()) {
1089de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        if (jpeg != null) {
1090de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
1091de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            final byte[] pixels = new byte[buffer.remaining()];
1092de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            buffer.get(pixels);
1093de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            handler.post(new Runnable() {
1094de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                @Override
1095de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                public void run() {
1096de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                    jpeg.onPictureTaken(pixels, AndroidCamera2ProxyImpl.this);
1097de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                                }});
1098de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                        }
1099de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    }
1100de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                }};
1101de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            mDispatchThread.runJob(new Runnable() {
1102de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                @Override
1103de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                public void run() {
1104772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher                    // Wait until PREVIEW_ACTIVE or better
1105772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher                    mCameraState.waitForStates(
1106772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher                            ~(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE - 1));
1107de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                    mCameraHandler.obtainMessage(CameraActions.CAPTURE_PHOTO, picListener)
1108de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                            .sendToTarget();
1109de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                }});
1110de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        }
1111a0842b40441db5332a5290f941021636b1182761Sol Boucher
1112a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1113a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1114a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {}
1115a0842b40441db5332a5290f941021636b1182761Sol Boucher
1116a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1117a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1118a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback)
1119a0842b40441db5332a5290f941021636b1182761Sol Boucher                {}
1120a0842b40441db5332a5290f941021636b1182761Sol Boucher
1121a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Remove this method override once we handle this message
1122a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1123a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void startFaceDetection() {}
1124a0842b40441db5332a5290f941021636b1182761Sol Boucher
1125a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // TODO: Remove this method override once we handle this message
1126a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        @Override
1127a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        public void stopFaceDetection() {}
1128a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher
1129a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1130a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1131a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setErrorCallback(Handler handler, CameraErrorCallback cb) {}
1132a0842b40441db5332a5290f941021636b1182761Sol Boucher
1133a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1134a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1135a0842b40441db5332a5290f941021636b1182761Sol Boucher        public void setParameters(android.hardware.Camera.Parameters params) {}
1136a0842b40441db5332a5290f941021636b1182761Sol Boucher
1137a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1138a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1139a0842b40441db5332a5290f941021636b1182761Sol Boucher        public android.hardware.Camera.Parameters getParameters() { return null; }
1140a0842b40441db5332a5290f941021636b1182761Sol Boucher
1141a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1142a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraSettings getSettings() {
114380cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher            if (mLastSettings == null) {
114480cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher                mLastSettings = mCameraHandler.buildSettings(mCapabilities);
114580cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher            }
114680cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher            return mLastSettings;
1147a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1148a0842b40441db5332a5290f941021636b1182761Sol Boucher
1149a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1150a0842b40441db5332a5290f941021636b1182761Sol Boucher        public boolean applySettings(CameraSettings settings) {
1151de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            if (settings == null) {
1152de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                Log.w(TAG, "null parameters in applySettings()");
1153de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                return false;
1154de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            }
1155de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            if (!(settings instanceof AndroidCamera2Settings)) {
1156de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                Log.e(TAG, "Provided settings not compatible with the backing framework API");
1157de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher                return false;
1158de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher            }
1159de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher
1160772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher            // Wait for any state that isn't OPENED
1161772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher            if (applySettingsHelper(settings, ~AndroidCamera2StateHolder.CAMERA_UNOPENED)) {
116280cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher                mLastSettings = settings;
116380cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher                return true;
116480cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher            }
116580cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher            return false;
1166a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1167a0842b40441db5332a5290f941021636b1182761Sol Boucher
1168a0842b40441db5332a5290f941021636b1182761Sol Boucher        // TODO: Implement
1169a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1170a0842b40441db5332a5290f941021636b1182761Sol Boucher        public String dumpDeviceSettings() { return null; }
1171a0842b40441db5332a5290f941021636b1182761Sol Boucher
1172a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1173a0842b40441db5332a5290f941021636b1182761Sol Boucher        public Handler getCameraHandler() {
1174a0842b40441db5332a5290f941021636b1182761Sol Boucher            return AndroidCamera2AgentImpl.this.getCameraHandler();
1175a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1176a0842b40441db5332a5290f941021636b1182761Sol Boucher
1177a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1178a0842b40441db5332a5290f941021636b1182761Sol Boucher        public DispatchThread getDispatchThread() {
1179a0842b40441db5332a5290f941021636b1182761Sol Boucher            return AndroidCamera2AgentImpl.this.getDispatchThread();
1180a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1181a0842b40441db5332a5290f941021636b1182761Sol Boucher
1182a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1183a0842b40441db5332a5290f941021636b1182761Sol Boucher        public CameraStateHolder getCameraState() {
1184a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mCameraState;
1185a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1186a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
1187a0842b40441db5332a5290f941021636b1182761Sol Boucher
1188a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher    /** A linear state machine: each state entails all the states below it. */
1189a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static class AndroidCamera2StateHolder extends CameraStateHolder {
1190a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() ->
1191a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        //             autoFocus() -> takePicture()
1192772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        // States are mutually exclusive, but must be separate bits so that they can be used with
1193772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        // the StateHolder#waitForStates() and StateHolder#waitToAvoidStates() methods.
1194772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        // Do not set the state to be a combination of these values!
1195a0842b40441db5332a5290f941021636b1182761Sol Boucher        /* Camera states */
1196a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** No camera device is opened. */
1197772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        public static final int CAMERA_UNOPENED = 1 << 0;
1198a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A camera is opened, but no settings have been provided. */
1199772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        public static final int CAMERA_UNCONFIGURED = 1 << 1;
1200a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** The open camera has been configured by providing it with settings. */
1201772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        public static final int CAMERA_CONFIGURED = 1 << 2;
1202a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A capture session is ready to stream a preview, but still has no repeating request. */
1203772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        public static final int CAMERA_PREVIEW_READY = 1 << 3;
1204a0842b40441db5332a5290f941021636b1182761Sol Boucher        /** A preview is currently being streamed. */
1205772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        public static final int CAMERA_PREVIEW_ACTIVE = 1 << 4;
1206a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher        /** The lens is locked on a particular region. */
1207772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher        public static final int CAMERA_FOCUS_LOCKED = 1 << 5;
1208a0842b40441db5332a5290f941021636b1182761Sol Boucher
1209a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2StateHolder() {
1210a0842b40441db5332a5290f941021636b1182761Sol Boucher            this(CAMERA_UNOPENED);
1211a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1212a0842b40441db5332a5290f941021636b1182761Sol Boucher
1213a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2StateHolder(int state) {
12147e0d39bf7b6e0f0df606e3f6c15f673f70fed3f7Sol Boucher            super(state);
1215a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1216a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
1217a0842b40441db5332a5290f941021636b1182761Sol Boucher
1218a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo {
1219a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final CameraManager mCameraManager;
1220a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final String[] mCameraIds;
1221a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mNumberOfCameras;
1222a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mFirstBackCameraId;
1223a0842b40441db5332a5290f941021636b1182761Sol Boucher        private final int mFirstFrontCameraId;
1224a0842b40441db5332a5290f941021636b1182761Sol Boucher
1225a0842b40441db5332a5290f941021636b1182761Sol Boucher        public AndroidCamera2DeviceInfo(CameraManager cameraManager,
1226a0842b40441db5332a5290f941021636b1182761Sol Boucher                                        String[] cameraIds, int numberOfCameras) {
1227a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraManager = cameraManager;
1228a0842b40441db5332a5290f941021636b1182761Sol Boucher            mCameraIds = cameraIds;
1229a0842b40441db5332a5290f941021636b1182761Sol Boucher            mNumberOfCameras = numberOfCameras;
1230a0842b40441db5332a5290f941021636b1182761Sol Boucher
1231a0842b40441db5332a5290f941021636b1182761Sol Boucher            int firstBackId = NO_DEVICE;
1232a0842b40441db5332a5290f941021636b1182761Sol Boucher            int firstFrontId = NO_DEVICE;
1233a0842b40441db5332a5290f941021636b1182761Sol Boucher            for (int id = 0; id < cameraIds.length; ++id) {
1234a0842b40441db5332a5290f941021636b1182761Sol Boucher                try {
1235a0842b40441db5332a5290f941021636b1182761Sol Boucher                    int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id])
1236a0842b40441db5332a5290f941021636b1182761Sol Boucher                            .get(CameraCharacteristics.LENS_FACING);
1237a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (firstBackId == NO_DEVICE &&
1238a0842b40441db5332a5290f941021636b1182761Sol Boucher                            lensDirection == CameraCharacteristics.LENS_FACING_BACK) {
1239a0842b40441db5332a5290f941021636b1182761Sol Boucher                        firstBackId = id;
1240a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
1241a0842b40441db5332a5290f941021636b1182761Sol Boucher                    if (firstFrontId == NO_DEVICE &&
1242a0842b40441db5332a5290f941021636b1182761Sol Boucher                            lensDirection == CameraCharacteristics.LENS_FACING_FRONT) {
1243a0842b40441db5332a5290f941021636b1182761Sol Boucher                        firstFrontId = id;
1244a0842b40441db5332a5290f941021636b1182761Sol Boucher                    }
1245a0842b40441db5332a5290f941021636b1182761Sol Boucher                } catch (CameraAccessException ex) {
1246a0842b40441db5332a5290f941021636b1182761Sol Boucher                    Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex);
1247a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
1248a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1249a0842b40441db5332a5290f941021636b1182761Sol Boucher            mFirstBackCameraId = firstBackId;
1250a0842b40441db5332a5290f941021636b1182761Sol Boucher            mFirstFrontCameraId = firstFrontId;
1251a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1252a0842b40441db5332a5290f941021636b1182761Sol Boucher
1253a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1254a0842b40441db5332a5290f941021636b1182761Sol Boucher        public Characteristics getCharacteristics(int cameraId) {
1255a0842b40441db5332a5290f941021636b1182761Sol Boucher            String actualId = mCameraIds[cameraId];
1256a0842b40441db5332a5290f941021636b1182761Sol Boucher            try {
1257a0842b40441db5332a5290f941021636b1182761Sol Boucher                CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId);
1258a0842b40441db5332a5290f941021636b1182761Sol Boucher                return new AndroidCharacteristics2(info);
1259a0842b40441db5332a5290f941021636b1182761Sol Boucher            } catch (CameraAccessException ex) {
1260a0842b40441db5332a5290f941021636b1182761Sol Boucher                return null;
1261a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1262a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1263a0842b40441db5332a5290f941021636b1182761Sol Boucher
1264a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1265a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getNumberOfCameras() {
1266a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mNumberOfCameras;
1267a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1268a0842b40441db5332a5290f941021636b1182761Sol Boucher
1269a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1270a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getFirstBackCameraId() {
1271a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mFirstBackCameraId;
1272a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1273a0842b40441db5332a5290f941021636b1182761Sol Boucher
1274a0842b40441db5332a5290f941021636b1182761Sol Boucher        @Override
1275a0842b40441db5332a5290f941021636b1182761Sol Boucher        public int getFirstFrontCameraId() {
1276a0842b40441db5332a5290f941021636b1182761Sol Boucher            return mFirstFrontCameraId;
1277a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1278a0842b40441db5332a5290f941021636b1182761Sol Boucher
1279de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher        private static class AndroidCharacteristics2 extends Characteristics {
1280a0842b40441db5332a5290f941021636b1182761Sol Boucher            private CameraCharacteristics mCameraInfo;
1281a0842b40441db5332a5290f941021636b1182761Sol Boucher
1282a0842b40441db5332a5290f941021636b1182761Sol Boucher            AndroidCharacteristics2(CameraCharacteristics cameraInfo) {
1283a0842b40441db5332a5290f941021636b1182761Sol Boucher                mCameraInfo = cameraInfo;
1284a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1285a0842b40441db5332a5290f941021636b1182761Sol Boucher
1286a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1287a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean isFacingBack() {
1288a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
1289a0842b40441db5332a5290f941021636b1182761Sol Boucher                        .equals(CameraCharacteristics.LENS_FACING_BACK);
1290a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1291a0842b40441db5332a5290f941021636b1182761Sol Boucher
1292a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1293a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean isFacingFront() {
1294a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.LENS_FACING)
1295a0842b40441db5332a5290f941021636b1182761Sol Boucher                        .equals(CameraCharacteristics.LENS_FACING_FRONT);
1296a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1297a0842b40441db5332a5290f941021636b1182761Sol Boucher
1298a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1299a0842b40441db5332a5290f941021636b1182761Sol Boucher            public int getSensorOrientation() {
1300a0842b40441db5332a5290f941021636b1182761Sol Boucher                return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION);
1301a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1302a0842b40441db5332a5290f941021636b1182761Sol Boucher
1303a0842b40441db5332a5290f941021636b1182761Sol Boucher            @Override
1304f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            public Matrix getPreviewTransform(int currentDisplayOrientation,
1305f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                                              RectF surfaceDimensions,
1306f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                                              RectF desiredBounds) {
1307f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                if (!orientationIsValid(currentDisplayOrientation)) {
1308f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                    return new Matrix();
1309f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                }
1310f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
1311f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                // The system transparently transforms the image to fill the surface
1312f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                // when the device is in its natural orientation. We rotate the
1313f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                // coordinates of the rectangle's corners to be relative to the
1314f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                // original image, instead of to the current screen orientation.
1315f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                float[] surfacePolygon = rotate(convertRectToPoly(surfaceDimensions),
1316f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                        2 * currentDisplayOrientation / 90);
1317f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                float[] desiredPolygon = convertRectToPoly(desiredBounds);
1318f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
1319f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                Matrix transform = new Matrix();
1320f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                // Use polygons instead of rectangles so that rotation will be
1321f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                // calculated, since that is not done by the new camera API.
1322f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                transform.setPolyToPoly(surfacePolygon, 0, desiredPolygon, 0, 4);
1323f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return transform;
1324f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            }
1325f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
1326f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            @Override
1327a0842b40441db5332a5290f941021636b1182761Sol Boucher            public boolean canDisableShutterSound() {
1328a0842b40441db5332a5290f941021636b1182761Sol Boucher                // The new API doesn't support this operation, so don't encourage people to try it.
1329a0842b40441db5332a5290f941021636b1182761Sol Boucher                // TODO: What kind of assumptions have callers made about this result's meaning?
1330a0842b40441db5332a5290f941021636b1182761Sol Boucher                return false;
1331a0842b40441db5332a5290f941021636b1182761Sol Boucher            }
1332f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
1333f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            private static float[] convertRectToPoly(RectF rf) {
1334f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return new float[] {rf.left, rf.top, rf.right, rf.top,
1335f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                        rf.right, rf.bottom, rf.left, rf.bottom};
1336f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            }
1337f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
1338f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            private static float[] rotate(float[] arr, int times) {
1339f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                if (times < 0) {
1340f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                    times = times % arr.length + arr.length;
1341f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                }
1342f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher
1343f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                float[] res = new float[arr.length];
1344f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                for (int offset = 0; offset < arr.length; ++offset) {
1345f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                    res[offset] = arr[(times + offset) % arr.length];
1346f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                }
1347f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher                return res;
1348f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher            }
1349a0842b40441db5332a5290f941021636b1182761Sol Boucher        }
1350a0842b40441db5332a5290f941021636b1182761Sol Boucher    }
1351a0842b40441db5332a5290f941021636b1182761Sol Boucher
1352a0842b40441db5332a5290f941021636b1182761Sol Boucher    private static final CameraExceptionCallback sCameraExceptionCallback =
1353a0842b40441db5332a5290f941021636b1182761Sol Boucher            new CameraExceptionCallback() {
1354a0842b40441db5332a5290f941021636b1182761Sol Boucher                @Override
1355a0842b40441db5332a5290f941021636b1182761Sol Boucher                public synchronized void onCameraException(RuntimeException e) {
1356a0842b40441db5332a5290f941021636b1182761Sol Boucher                    throw e;
1357a0842b40441db5332a5290f941021636b1182761Sol Boucher                }
1358a0842b40441db5332a5290f941021636b1182761Sol Boucher            };
1359a0842b40441db5332a5290f941021636b1182761Sol Boucher}
1360