AndroidCamera2AgentImpl.java revision 25ee73acd2dbd6f60deef5306994fbf3a7997936
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 163bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala extends CameraCaptureSession.CaptureCallback 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 } 234bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala mCameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, 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), 300bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala /*listener*/mCameraResultStateCallback, /*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; 382bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala CameraCaptureSession.CaptureCallback deferredCallbackSetter = 383bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala new CameraCaptureSession.CaptureCallback() { 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) { 403bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala // Now our mCameraResultStateCallback 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. 409bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala mCameraResultStateCallback.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, 49625ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu // capture in the sensor's physical orientation. (e.g., JPEG rotation is 49725ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu // necessary in auto-rotate mode. 498de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg2 > 0 ? 499de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCameraProxy.getCharacteristics().getJpegOrientation(msg.arg1) : 0); 500a0842b40441db5332a5290f941021636b1182761Sol Boucher break; 501a0842b40441db5332a5290f941021636b1182761Sol Boucher } 502a0842b40441db5332a5290f941021636b1182761Sol Boucher 50325ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu case CameraActions.SET_JPEG_ORIENTATION: { 50425ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu mPersistentSettings.set(CaptureRequest.JPEG_ORIENTATION, msg.arg1); 50525ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu break; 50625ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu } 50725ee73acd2dbd6f60deef5306994fbf3a7997936Senpo Hu 508a0842b40441db5332a5290f941021636b1182761Sol Boucher case CameraActions.CAPTURE_PHOTO: { 509de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (mCameraState.getState() < 510de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 511de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.e(TAG, "Photos may only be taken when a preview is active"); 512de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher break; 513de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 514de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (mCameraState.getState() != 515de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED) { 516de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.w(TAG, "Taking a (likely blurry) photo without the lens locked"); 517de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 518de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 519de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher final CaptureAvailableListener listener = 520de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher (CaptureAvailableListener) msg.obj; 521984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (mLegacyDevice || 522984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher (mCurrentAeState == CaptureResult.CONTROL_AE_STATE_CONVERGED && 523984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher !mPersistentSettings.matches(CaptureRequest.CONTROL_AE_MODE, 524984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH) && 525984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher !mPersistentSettings.matches(CaptureRequest.FLASH_MODE, 526984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher CaptureRequest.FLASH_MODE_SINGLE))) 527984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher { 528984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // Legacy devices don't support the precapture state keys and instead 529984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // perform autoexposure convergence automatically upon capture. 530984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 531984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // On other devices, as long as it has already converged, it determined 532984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // that flash was not required, and we're not going to invalidate the 533984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // current exposure levels by forcing the force on, we can save 534984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // significant capture time by not forcing a recalculation. 535984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher Log.i(TAG, "Skipping pre-capture autoexposure convergence"); 536de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCaptureReader.setOnImageAvailableListener(listener, /*handler*/this); 537de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher try { 538de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mSession.capture( 539de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPersistentSettings.createRequest(mCamera, 540de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CameraDevice.TEMPLATE_STILL_CAPTURE, 541de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCaptureReader.getSurface()), 542de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher listener, /*handler*/this); 543de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } catch (CameraAccessException ex) { 544984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher Log.e(TAG, "Unable to initiate immediate capture", ex); 545de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 546de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } else { 547984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // We need to let AE converge before capturing. Once our one-time 548984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // trigger capture has made it into the pipeline, we'll start checking 549984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // for the completion of that convergence, capturing when that happens. 550984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher Log.i(TAG, "Forcing pre-capture autoexposure convergence"); 551bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala CameraCaptureSession.CaptureCallback deferredCallbackSetter = 552bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala new CameraCaptureSession.CaptureCallback() { 553984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher private boolean mAlreadyDispatched = false; 554984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 555984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher @Override 556984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher public void onCaptureProgressed(CameraCaptureSession session, 557984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher CaptureRequest request, 558984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher CaptureResult result) { 559984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher checkAeState(result); 560984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 561984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 562de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 563de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void onCaptureCompleted(CameraCaptureSession session, 564de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CaptureRequest request, 565de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher TotalCaptureResult result) { 566984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher checkAeState(result); 567984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 568984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 569984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher private void checkAeState(CaptureResult result) { 570984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (result.get(CaptureResult.CONTROL_AE_STATE) != null && 571984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher !mAlreadyDispatched) { 572bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala // Now our mCameraResultStateCallback will invoke the 573984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // callback once the autoexposure routine has converged. 574984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mAlreadyDispatched = true; 575984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mOneshotCaptureCallback = listener; 576984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // This is an optimization: check the AE state of this frame 577984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // instead of simply waiting for the next. 578bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala mCameraResultStateCallback.monitorControlStates(result); 579984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 580de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 581de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 582de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 583de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void onCaptureFailed(CameraCaptureSession session, 584de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CaptureRequest request, 585de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CaptureFailure failure) { 586de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.e(TAG, "Autoexposure and capture failed with reason " + 587de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher failure.getReason()); 588de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher // TODO: Make an error callback? 589de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher }}; 590de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 591de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher // Set a one-time capture to trigger the camera driver's autoexposure: 592de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Camera2RequestSettingsSet expose = 593de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher new Camera2RequestSettingsSet(mPersistentSettings); 594de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher expose.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 595de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); 596de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher try { 597de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mSession.capture( 598de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher expose.createRequest(mCamera, CameraDevice.TEMPLATE_PREVIEW, 599de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPreviewSurface), 600de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher /*listener*/deferredCallbackSetter, /*handler*/this); 601de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } catch (CameraAccessException ex) { 602de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.e(TAG, "Unable to run autoexposure and perform capture", ex); 603de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 604de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 605a0842b40441db5332a5290f941021636b1182761Sol Boucher break; 606de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 607a0842b40441db5332a5290f941021636b1182761Sol Boucher 608a0842b40441db5332a5290f941021636b1182761Sol Boucher default: { 609a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Rephrase once everything has been implemented 610a0842b40441db5332a5290f941021636b1182761Sol Boucher throw new RuntimeException("Unimplemented CameraProxy message=" + msg.what); 611a0842b40441db5332a5290f941021636b1182761Sol Boucher } 612a0842b40441db5332a5290f941021636b1182761Sol Boucher } 613a0842b40441db5332a5290f941021636b1182761Sol Boucher } catch (final Exception ex) { 614a0842b40441db5332a5290f941021636b1182761Sol Boucher if (msg.what != CameraActions.RELEASE && mCamera != null) { 615a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // TODO: Handle this better 616a0842b40441db5332a5290f941021636b1182761Sol Boucher mCamera.close(); 617a0842b40441db5332a5290f941021636b1182761Sol Boucher mCamera = null; 618a0842b40441db5332a5290f941021636b1182761Sol Boucher } else if (mCamera == null) { 619a0842b40441db5332a5290f941021636b1182761Sol Boucher if (msg.what == CameraActions.OPEN_CAMERA) { 620a0842b40441db5332a5290f941021636b1182761Sol Boucher if (mOpenCallback != null) { 621a0842b40441db5332a5290f941021636b1182761Sol Boucher mOpenCallback.onDeviceOpenFailure(mCameraIndex, 622a0842b40441db5332a5290f941021636b1182761Sol Boucher generateHistoryString(mCameraIndex)); 623a0842b40441db5332a5290f941021636b1182761Sol Boucher } 624a0842b40441db5332a5290f941021636b1182761Sol Boucher } else { 625a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.w(TAG, "Cannot handle message " + msg.what + ", mCamera is null"); 626a0842b40441db5332a5290f941021636b1182761Sol Boucher } 627a0842b40441db5332a5290f941021636b1182761Sol Boucher return; 628a0842b40441db5332a5290f941021636b1182761Sol Boucher } 629a0842b40441db5332a5290f941021636b1182761Sol Boucher 630a0842b40441db5332a5290f941021636b1182761Sol Boucher if (ex instanceof RuntimeException) { 631a0842b40441db5332a5290f941021636b1182761Sol Boucher post(new Runnable() { 632a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 633a0842b40441db5332a5290f941021636b1182761Sol Boucher public void run() { 634a0842b40441db5332a5290f941021636b1182761Sol Boucher sCameraExceptionCallback.onCameraException((RuntimeException) ex); 635a0842b40441db5332a5290f941021636b1182761Sol Boucher }}); 636a0842b40441db5332a5290f941021636b1182761Sol Boucher } 637a0842b40441db5332a5290f941021636b1182761Sol Boucher } 638a0842b40441db5332a5290f941021636b1182761Sol Boucher } 639a0842b40441db5332a5290f941021636b1182761Sol Boucher 640a0842b40441db5332a5290f941021636b1182761Sol Boucher public CameraSettings buildSettings(AndroidCamera2Capabilities caps) { 641de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher try { 642de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher return new AndroidCamera2Settings(mCamera, CameraDevice.TEMPLATE_PREVIEW, 643de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mActiveArray, mPreviewSize, mPhotoSize); 644de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } catch (CameraAccessException ex) { 645de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.e(TAG, "Unable to query camera device to build settings representation"); 646de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher return null; 647de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 648a0842b40441db5332a5290f941021636b1182761Sol Boucher } 649a0842b40441db5332a5290f941021636b1182761Sol Boucher 650a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher /** 651a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * Simply propagates settings from provided {@link CameraSettings} 652a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * object to our {@link CaptureRequest.Builder} for use in captures. 653a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * <p>Most conversions to match the API 2 formats are performed by 654a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * {@link AndroidCamera2Capabilities.IntegralStringifier}; otherwise 655a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * any final adjustments are done here before updating the builder.</p> 656a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * 657a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher * @param settings The new/updated settings 658a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher */ 659de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher private void applyToRequest(AndroidCamera2Settings settings) { 660a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: If invoked when in PREVIEW_READY state, a new preview size will not take effect 661de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 662de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPersistentSettings.union(settings.getRequestSettings()); 663a0842b40441db5332a5290f941021636b1182761Sol Boucher mPreviewSize = settings.getCurrentPreviewSize(); 664a0842b40441db5332a5290f941021636b1182761Sol Boucher mPhotoSize = settings.getCurrentPhotoSize(); 665a0842b40441db5332a5290f941021636b1182761Sol Boucher 666a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (mCameraState.getState() >= AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 667a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // If we're already previewing, reflect most settings immediately 668a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher try { 669de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mSession.setRepeatingRequest( 670de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPersistentSettings.createRequest(mCamera, 671de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CameraDevice.TEMPLATE_PREVIEW, mPreviewSurface), 672bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala /*listener*/mCameraResultStateCallback, /*handler*/this); 673a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } catch (CameraAccessException ex) { 674a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher Log.e(TAG, "Failed to apply updated request settings", ex); 675a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 676a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } else if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_PREVIEW_READY) { 677a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // If we're already ready to preview, this doesn't regress our state 678984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED); 679a0842b40441db5332a5290f941021636b1182761Sol Boucher } 680a0842b40441db5332a5290f941021636b1182761Sol Boucher } 681a0842b40441db5332a5290f941021636b1182761Sol Boucher 682a0842b40441db5332a5290f941021636b1182761Sol Boucher private void setPreviewTexture(SurfaceTexture surfaceTexture) { 683a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Must be called after providing a .*Settings populated with sizes 684a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: We don't technically offer a selection of sizes tailored to SurfaceTextures! 685a0842b40441db5332a5290f941021636b1182761Sol Boucher 686a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Handle this error condition with a callback or exception 687a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (mCameraState.getState() < AndroidCamera2StateHolder.CAMERA_CONFIGURED) { 688a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher Log.w(TAG, "Ignoring texture setting at inappropriate time"); 689a0842b40441db5332a5290f941021636b1182761Sol Boucher return; 690a0842b40441db5332a5290f941021636b1182761Sol Boucher } 691a0842b40441db5332a5290f941021636b1182761Sol Boucher 692a0842b40441db5332a5290f941021636b1182761Sol Boucher // Avoid initializing another capture session unless we absolutely have to 693a0842b40441db5332a5290f941021636b1182761Sol Boucher if (surfaceTexture == mPreviewTexture) { 694a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.i(TAG, "Optimizing out redundant preview texture setting"); 695a0842b40441db5332a5290f941021636b1182761Sol Boucher return; 696a0842b40441db5332a5290f941021636b1182761Sol Boucher } 697a0842b40441db5332a5290f941021636b1182761Sol Boucher 698a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (mSession != null) { 699a0842b40441db5332a5290f941021636b1182761Sol Boucher closePreviewSession(); 700a0842b40441db5332a5290f941021636b1182761Sol Boucher } 701a0842b40441db5332a5290f941021636b1182761Sol Boucher 702a0842b40441db5332a5290f941021636b1182761Sol Boucher mPreviewTexture = surfaceTexture; 703a0842b40441db5332a5290f941021636b1182761Sol Boucher surfaceTexture.setDefaultBufferSize(mPreviewSize.width(), mPreviewSize.height()); 704a0842b40441db5332a5290f941021636b1182761Sol Boucher 705a0842b40441db5332a5290f941021636b1182761Sol Boucher if (mPreviewSurface != null) { 706a0842b40441db5332a5290f941021636b1182761Sol Boucher mPreviewSurface.release(); 707a0842b40441db5332a5290f941021636b1182761Sol Boucher } 708a0842b40441db5332a5290f941021636b1182761Sol Boucher mPreviewSurface = new Surface(surfaceTexture); 709de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 710de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (mCaptureReader != null) { 711de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCaptureReader.close(); 712de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 713de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCaptureReader = ImageReader.newInstance( 714de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPhotoSize.width(), mPhotoSize.height(), ImageFormat.JPEG, 1); 715a0842b40441db5332a5290f941021636b1182761Sol Boucher 716a0842b40441db5332a5290f941021636b1182761Sol Boucher try { 717de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCamera.createCaptureSession( 718de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Arrays.asList(mPreviewSurface, mCaptureReader.getSurface()), 719bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala mCameraPreviewStateCallback, this); 720a0842b40441db5332a5290f941021636b1182761Sol Boucher } catch (CameraAccessException ex) { 721a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.e(TAG, "Failed to create camera capture session", ex); 722a0842b40441db5332a5290f941021636b1182761Sol Boucher } 723a0842b40441db5332a5290f941021636b1182761Sol Boucher } 724a0842b40441db5332a5290f941021636b1182761Sol Boucher 725a0842b40441db5332a5290f941021636b1182761Sol Boucher private void closePreviewSession() { 726a0842b40441db5332a5290f941021636b1182761Sol Boucher try { 727a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mSession.abortCaptures(); 728a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mSession = null; 729a0842b40441db5332a5290f941021636b1182761Sol Boucher } catch (CameraAccessException ex) { 730a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.e(TAG, "Failed to close existing camera capture session", ex); 731a0842b40441db5332a5290f941021636b1182761Sol Boucher } 732984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher changeState(AndroidCamera2StateHolder.CAMERA_CONFIGURED); 733984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 734984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 735984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher private void changeState(int newState) { 736984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (mCameraState.getState() != newState) { 737984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCameraState.setState(newState); 738984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (newState < AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE) { 739984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCurrentAeState = CaptureResult.CONTROL_AE_STATE_INACTIVE; 740bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala mCameraResultStateCallback.resetState(); 741984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 742984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 743a0842b40441db5332a5290f941021636b1182761Sol Boucher } 744a0842b40441db5332a5290f941021636b1182761Sol Boucher 745bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala // This callback monitors our connection to and disconnection from camera devices. 746bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala private CameraDevice.StateCallback mCameraDeviceStateCallback = 747bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala new CameraDevice.StateCallback() { 748a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 749a0842b40441db5332a5290f941021636b1182761Sol Boucher public void onOpened(CameraDevice camera) { 750a0842b40441db5332a5290f941021636b1182761Sol Boucher mCamera = camera; 751a0842b40441db5332a5290f941021636b1182761Sol Boucher if (mOpenCallback != null) { 752a0842b40441db5332a5290f941021636b1182761Sol Boucher try { 753a0842b40441db5332a5290f941021636b1182761Sol Boucher CameraCharacteristics props = 754a0842b40441db5332a5290f941021636b1182761Sol Boucher mCameraManager.getCameraCharacteristics(mCameraId); 755a0842b40441db5332a5290f941021636b1182761Sol Boucher mCameraProxy = new AndroidCamera2ProxyImpl(mCameraIndex, mCamera, 756a0842b40441db5332a5290f941021636b1182761Sol Boucher getCameraDeviceInfo().getCharacteristics(mCameraIndex), props); 757de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mPersistentSettings = new Camera2RequestSettingsSet(); 758a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mActiveArray = 759a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher props.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE); 760de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mLegacyDevice = 761de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher props.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL) == 762de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY; 763984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher changeState(AndroidCamera2StateHolder.CAMERA_UNCONFIGURED); 764a0842b40441db5332a5290f941021636b1182761Sol Boucher mOpenCallback.onCameraOpened(mCameraProxy); 765a0842b40441db5332a5290f941021636b1182761Sol Boucher } catch (CameraAccessException ex) { 766a0842b40441db5332a5290f941021636b1182761Sol Boucher mOpenCallback.onDeviceOpenFailure(mCameraIndex, 767a0842b40441db5332a5290f941021636b1182761Sol Boucher generateHistoryString(mCameraIndex)); 768a0842b40441db5332a5290f941021636b1182761Sol Boucher } 769a0842b40441db5332a5290f941021636b1182761Sol Boucher } 770a0842b40441db5332a5290f941021636b1182761Sol Boucher } 771a0842b40441db5332a5290f941021636b1182761Sol Boucher 772a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 773a0842b40441db5332a5290f941021636b1182761Sol Boucher public void onDisconnected(CameraDevice camera) { 774a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.w(TAG, "Camera device '" + mCameraIndex + "' was disconnected"); 775a0842b40441db5332a5290f941021636b1182761Sol Boucher } 776a0842b40441db5332a5290f941021636b1182761Sol Boucher 777a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 778a0842b40441db5332a5290f941021636b1182761Sol Boucher public void onError(CameraDevice camera, int error) { 779a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.e(TAG, "Camera device '" + mCameraIndex + "' encountered error code '" + 780a0842b40441db5332a5290f941021636b1182761Sol Boucher error + '\''); 781a0842b40441db5332a5290f941021636b1182761Sol Boucher if (mOpenCallback != null) { 782a0842b40441db5332a5290f941021636b1182761Sol Boucher mOpenCallback.onDeviceOpenFailure(mCameraIndex, 783a0842b40441db5332a5290f941021636b1182761Sol Boucher generateHistoryString(mCameraIndex)); 784a0842b40441db5332a5290f941021636b1182761Sol Boucher } 785a0842b40441db5332a5290f941021636b1182761Sol Boucher }}; 786a0842b40441db5332a5290f941021636b1182761Sol Boucher 787bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala // This callback monitors our camera session (i.e. our transition into and out of preview). 788bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala private CameraCaptureSession.StateCallback mCameraPreviewStateCallback = 789bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala new CameraCaptureSession.StateCallback() { 790a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 791a0842b40441db5332a5290f941021636b1182761Sol Boucher public void onConfigured(CameraCaptureSession session) { 792a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mSession = session; 793984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher changeState(AndroidCamera2StateHolder.CAMERA_PREVIEW_READY); 794a0842b40441db5332a5290f941021636b1182761Sol Boucher } 795a0842b40441db5332a5290f941021636b1182761Sol Boucher 796a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 797a0842b40441db5332a5290f941021636b1182761Sol Boucher public void onConfigureFailed(CameraCaptureSession session) { 798a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Invoke a callback 799a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.e(TAG, "Failed to configure the camera for capture"); 800a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 801a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 802a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 803a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void onActive(CameraCaptureSession session) { 804a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (mOneshotPreviewingCallback != null) { 805a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // The session is up and processing preview requests. Inform the caller. 806a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mOneshotPreviewingCallback.onPreviewStarted(); 807a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mOneshotPreviewingCallback = null; 808a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 809a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}; 810a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 811bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala private abstract class CameraResultStateCallback 812bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala extends CameraCaptureSession.CaptureCallback { 813984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher public abstract void monitorControlStates(CaptureResult result); 814984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 815984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher public abstract void resetState(); 816984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 817984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 818bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala // This callback monitors requested captures and notifies any relevant callbacks. 819bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala private CameraResultStateCallback mCameraResultStateCallback = 820bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala new CameraResultStateCallback() { 821a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher private int mLastAfState = -1; 822984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher private long mLastAfFrameNumber = -1; 823984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher private long mLastAeFrameNumber = -1; 824984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 825984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher @Override 826984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, 827984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher CaptureResult result) { 828984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher monitorControlStates(result); 829984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 830a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 831a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 832a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, 833a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher TotalCaptureResult result) { 834984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher monitorControlStates(result); 835984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 836984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 837984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher @Override 838984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher public void monitorControlStates(CaptureResult result) { 839a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher Integer afStateMaybe = result.get(CaptureResult.CONTROL_AF_STATE); 840a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (afStateMaybe != null) { 841a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher int afState = afStateMaybe; 842984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // Since we handle both partial and total results for multiple frames here, we 843984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // might get the final callbacks for an earlier frame after receiving one or 844984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // more that correspond to the next one. To prevent our data from oscillating, 845984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // we never consider AF states that are older than the last one we've seen. 846984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (result.getFrameNumber() > mLastAfFrameNumber) { 847984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher boolean afStateChanged = afState != mLastAfState; 848a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mLastAfState = afState; 849984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mLastAfFrameNumber = result.getFrameNumber(); 850984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 851984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher switch (afState) { 852984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: 853984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: 854984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: { 855984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (afStateChanged && mPassiveAfCallback != null) { 856984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // A CameraAFMoveCallback is attached. If we just started to 857984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // scan, the motor is moving; otherwise, it has settled. 858984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mPassiveAfCallback.onAutoFocusMoving( 859984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN, 860984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCameraProxy); 861984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 862984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher break; 863a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 864a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 865984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: 866984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: { 8677d71703202c2fba36653293eba2772745db46c00Sol Boucher // This check must be made regardless of whether the focus state has 8687d71703202c2fba36653293eba2772745db46c00Sol Boucher // changed recently to avoid infinite waiting during autoFocus() 8697d71703202c2fba36653293eba2772745db46c00Sol Boucher // when the algorithm has already either converged or failed to. 870984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (mOneshotAfCallback != null) { 871984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // A call to autoFocus() was just made to request a focus lock. 872984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // Notify the caller that the lens is now indefinitely fixed, 873984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // and report whether the image we're stuck with is in focus. 874984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mOneshotAfCallback.onAutoFocus( 875984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED, 876984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCameraProxy); 877984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mOneshotAfCallback = null; 878984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 879984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher break; 880a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 881a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 882a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 883a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 884de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 885de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Integer aeStateMaybe = result.get(CaptureResult.CONTROL_AE_STATE); 886de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (aeStateMaybe != null) { 887de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher int aeState = aeStateMaybe; 888984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // Since we handle both partial and total results for multiple frames here, we 889984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // might get the final callbacks for an earlier frame after receiving one or 890984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // more that correspond to the next one. To prevent our data from oscillating, 891984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // we never consider AE states that are older than the last one we've seen. 8927d71703202c2fba36653293eba2772745db46c00Sol Boucher if (result.getFrameNumber() > mLastAeFrameNumber) { 893984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCurrentAeState = aeStateMaybe; 894984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mLastAeFrameNumber = result.getFrameNumber(); 895984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 896984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher switch (aeState) { 897984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AE_STATE_CONVERGED: 898984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED: 899984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher case CaptureResult.CONTROL_AE_STATE_LOCKED: { 9007d71703202c2fba36653293eba2772745db46c00Sol Boucher // This check must be made regardless of whether the exposure state 9017d71703202c2fba36653293eba2772745db46c00Sol Boucher // has changed recently to avoid infinite waiting during 9027d71703202c2fba36653293eba2772745db46c00Sol Boucher // takePicture() when the algorithm has already converged. 903984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher if (mOneshotCaptureCallback != null) { 904984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // A call to takePicture() was just made, and autoexposure 905984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher // converged so it's time to initiate the capture! 906984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCaptureReader.setOnImageAvailableListener( 907de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher /*listener*/mOneshotCaptureCallback, 908de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher /*handler*/Camera2Handler.this); 909984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher try { 910984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mSession.capture( 911984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mPersistentSettings.createRequest(mCamera, 912984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher CameraDevice.TEMPLATE_STILL_CAPTURE, 913984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mCaptureReader.getSurface()), 914bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala /*callback*/mOneshotCaptureCallback, 915984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher /*handler*/Camera2Handler.this); 916984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } catch (CameraAccessException ex) { 917984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher Log.e(TAG, "Unable to initiate capture", ex); 918984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } finally { 919984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mOneshotCaptureCallback = null; 920984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 921de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 922984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher break; 923de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 924de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 925de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 926de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 927a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 928a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 929a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 930984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher public void resetState() { 931984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mLastAfState = -1; 932984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mLastAfFrameNumber = -1; 933984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher mLastAeFrameNumber = -1; 934984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher } 935984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher 936984a086412a94ebea1bd9af8cd8bbf4afab38034Sol Boucher @Override 937a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, 938a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher CaptureFailure failure) { 939a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher Log.e(TAG, "Capture attempt failed with reason " + failure.getReason()); 940a0842b40441db5332a5290f941021636b1182761Sol Boucher }}; 941a0842b40441db5332a5290f941021636b1182761Sol Boucher } 942a0842b40441db5332a5290f941021636b1182761Sol Boucher 943a0842b40441db5332a5290f941021636b1182761Sol Boucher private class AndroidCamera2ProxyImpl extends CameraAgent.CameraProxy { 944a0842b40441db5332a5290f941021636b1182761Sol Boucher private final int mCameraIndex; 945a0842b40441db5332a5290f941021636b1182761Sol Boucher private final CameraDevice mCamera; 946a0842b40441db5332a5290f941021636b1182761Sol Boucher private final CameraDeviceInfo.Characteristics mCharacteristics; 947a0842b40441db5332a5290f941021636b1182761Sol Boucher private final AndroidCamera2Capabilities mCapabilities; 94880cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher private CameraSettings mLastSettings; 949415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher private boolean mShutterSoundEnabled; 950a0842b40441db5332a5290f941021636b1182761Sol Boucher 951a0842b40441db5332a5290f941021636b1182761Sol Boucher public AndroidCamera2ProxyImpl(int cameraIndex, CameraDevice camera, 952a0842b40441db5332a5290f941021636b1182761Sol Boucher CameraDeviceInfo.Characteristics characteristics, 953a0842b40441db5332a5290f941021636b1182761Sol Boucher CameraCharacteristics properties) { 954a0842b40441db5332a5290f941021636b1182761Sol Boucher mCameraIndex = cameraIndex; 955a0842b40441db5332a5290f941021636b1182761Sol Boucher mCamera = camera; 956a0842b40441db5332a5290f941021636b1182761Sol Boucher mCharacteristics = characteristics; 957a0842b40441db5332a5290f941021636b1182761Sol Boucher mCapabilities = new AndroidCamera2Capabilities(properties); 95880cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher mLastSettings = null; 959415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher mShutterSoundEnabled = true; 960a0842b40441db5332a5290f941021636b1182761Sol Boucher } 961a0842b40441db5332a5290f941021636b1182761Sol Boucher 962a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 963a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 964a0842b40441db5332a5290f941021636b1182761Sol Boucher public android.hardware.Camera getCamera() { return null; } 965a0842b40441db5332a5290f941021636b1182761Sol Boucher 966a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 967a0842b40441db5332a5290f941021636b1182761Sol Boucher public int getCameraId() { 968a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCameraIndex; 969a0842b40441db5332a5290f941021636b1182761Sol Boucher } 970a0842b40441db5332a5290f941021636b1182761Sol Boucher 971a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 972a0842b40441db5332a5290f941021636b1182761Sol Boucher public CameraDeviceInfo.Characteristics getCharacteristics() { 973a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCharacteristics; 974a0842b40441db5332a5290f941021636b1182761Sol Boucher } 975a0842b40441db5332a5290f941021636b1182761Sol Boucher 976a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 977a0842b40441db5332a5290f941021636b1182761Sol Boucher public CameraCapabilities getCapabilities() { 978a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCapabilities; 979a0842b40441db5332a5290f941021636b1182761Sol Boucher } 980a0842b40441db5332a5290f941021636b1182761Sol Boucher 981a0842b40441db5332a5290f941021636b1182761Sol Boucher private AndroidCamera2Capabilities getSpecializedCapabilities() { 982a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCapabilities; 983a0842b40441db5332a5290f941021636b1182761Sol Boucher } 984a0842b40441db5332a5290f941021636b1182761Sol Boucher 9852569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // FIXME: Unlock the sizes in stopPreview(), as per the corresponding 9862569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // explanation on the STOP_PREVIEW case in the handler. 9872569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher @Override 9882569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher public void setPreviewTexture(SurfaceTexture surfaceTexture) { 9892569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // Once the Surface has been selected, we configure the session and 9902569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // are no longer able to change the sizes. 9912569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher getSettings().setSizesLocked(true); 9922569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher super.setPreviewTexture(surfaceTexture); 9932569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher } 9942569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher 9952569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // FIXME: Unlock the sizes in stopPreview(), as per the corresponding 9962569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // explanation on the STOP_PREVIEW case in the handler. 9972569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher @Override 9982569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher public void setPreviewTextureSync(SurfaceTexture surfaceTexture) { 9992569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // Once the Surface has been selected, we configure the session and 10002569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher // are no longer able to change the sizes. 10012569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher getSettings().setSizesLocked(true); 10022569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher super.setPreviewTexture(surfaceTexture); 10032569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher } 10042569329d6cff25bfe9941df539df14a0aeb4c4f4Sol Boucher 1005a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1006a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1007a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setPreviewDataCallback(Handler handler, CameraPreviewDataCallback cb) {} 1008a0842b40441db5332a5290f941021636b1182761Sol Boucher 1009a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1010a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1011a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setOneShotPreviewCallback(Handler handler, CameraPreviewDataCallback cb) {} 1012a0842b40441db5332a5290f941021636b1182761Sol Boucher 1013a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1014a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1015a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setPreviewDataCallbackWithBuffer(Handler handler, CameraPreviewDataCallback cb) 1016a0842b40441db5332a5290f941021636b1182761Sol Boucher {} 1017a0842b40441db5332a5290f941021636b1182761Sol Boucher 101850f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher // TODO: Implement 101950f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher public void addCallbackBuffer(final byte[] callbackBuffer) {} 102050f5b019ba3f333a09a1beb9667fd7290082dc31Sol Boucher 1021a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1022a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void autoFocus(final Handler handler, final CameraAFCallback cb) { 1023a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mDispatchThread.runJob(new Runnable() { 1024a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1025a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void run() { 1026a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher CameraAFCallback cbForward = null; 1027a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (cb != null) { 1028a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher cbForward = new CameraAFCallback() { 1029a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1030a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void onAutoFocus(final boolean focused, 1031a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher final CameraProxy camera) { 1032a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher handler.post(new Runnable() { 1033a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1034a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void run() { 1035a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher cb.onAutoFocus(focused, camera); 1036a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}); 1037a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}; 1038a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 1039a0842b40441db5332a5290f941021636b1182761Sol Boucher 1040a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mCameraState.waitForStates(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE | 1041a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher AndroidCamera2StateHolder.CAMERA_FOCUS_LOCKED); 1042a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mCameraHandler.obtainMessage(CameraActions.AUTO_FOCUS, cbForward) 1043a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher .sendToTarget(); 1044a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}); 1045a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 1046a0842b40441db5332a5290f941021636b1182761Sol Boucher 1047a0842b40441db5332a5290f941021636b1182761Sol Boucher @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 1048a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1049a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void setAutoFocusMoveCallback(final Handler handler, final CameraAFMoveCallback cb) { 1050a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mDispatchThread.runJob(new Runnable() { 1051a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1052a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void run() { 1053a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher CameraAFMoveCallback cbForward = null; 1054a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher if (cb != null) { 1055a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher cbForward = new CameraAFMoveCallback() { 1056a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1057a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void onAutoFocusMoving(final boolean moving, 1058a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher final CameraProxy camera) { 1059a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher handler.post(new Runnable() { 1060a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1061a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void run() { 1062a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher cb.onAutoFocusMoving(moving, camera); 1063a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}); 1064a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}; 1065a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 1066a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 1067a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher mCameraHandler.obtainMessage(CameraActions.SET_AUTO_FOCUS_MOVE_CALLBACK, 1068a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher cbForward).sendToTarget(); 1069a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher }}); 1070a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher } 1071a0842b40441db5332a5290f941021636b1182761Sol Boucher 1072a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1073de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void takePicture(final Handler handler, 1074de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher final CameraShutterCallback shutter, 1075a0842b40441db5332a5290f941021636b1182761Sol Boucher CameraPictureCallback raw, 1076a0842b40441db5332a5290f941021636b1182761Sol Boucher CameraPictureCallback postview, 1077de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher final CameraPictureCallback jpeg) { 1078de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher // TODO: We never call raw or postview 1079de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher final CaptureAvailableListener picListener = 1080de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher new CaptureAvailableListener() { 1081de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 1082de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, 1083de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher long timestamp) { 1084de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (shutter != null) { 1085de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher handler.post(new Runnable() { 1086de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 1087de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void run() { 1088415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher if (mShutterSoundEnabled) { 1089415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher mNoisemaker.play(MediaActionSound.SHUTTER_CLICK); 1090415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher } 1091de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher shutter.onShutter(AndroidCamera2ProxyImpl.this); 1092de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher }}); 1093de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1094de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1095a0842b40441db5332a5290f941021636b1182761Sol Boucher 1096de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 1097de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void onImageAvailable(ImageReader reader) { 1098de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher try (Image image = reader.acquireNextImage()) { 1099de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (jpeg != null) { 1100de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 1101de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher final byte[] pixels = new byte[buffer.remaining()]; 1102de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher buffer.get(pixels); 1103de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher handler.post(new Runnable() { 1104de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 1105de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void run() { 1106de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher jpeg.onPictureTaken(pixels, AndroidCamera2ProxyImpl.this); 1107de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher }}); 1108de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1109de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1110de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher }}; 1111de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mDispatchThread.runJob(new Runnable() { 1112de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher @Override 1113de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher public void run() { 1114772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher // Wait until PREVIEW_ACTIVE or better 1115772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher mCameraState.waitForStates( 1116772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher ~(AndroidCamera2StateHolder.CAMERA_PREVIEW_ACTIVE - 1)); 1117de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher mCameraHandler.obtainMessage(CameraActions.CAPTURE_PHOTO, picListener) 1118de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher .sendToTarget(); 1119de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher }}); 1120de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1121a0842b40441db5332a5290f941021636b1182761Sol Boucher 1122a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1123a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1124a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setZoomChangeListener(android.hardware.Camera.OnZoomChangeListener listener) {} 1125a0842b40441db5332a5290f941021636b1182761Sol Boucher 1126a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1127a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1128a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setFaceDetectionCallback(Handler handler, CameraFaceDetectionCallback callback) 1129a0842b40441db5332a5290f941021636b1182761Sol Boucher {} 1130a0842b40441db5332a5290f941021636b1182761Sol Boucher 1131a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Remove this method override once we handle this message 1132a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1133a0842b40441db5332a5290f941021636b1182761Sol Boucher public void startFaceDetection() {} 1134a0842b40441db5332a5290f941021636b1182761Sol Boucher 1135a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // TODO: Remove this method override once we handle this message 1136a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher @Override 1137a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher public void stopFaceDetection() {} 1138a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher 1139a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1140a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1141a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setErrorCallback(Handler handler, CameraErrorCallback cb) {} 1142a0842b40441db5332a5290f941021636b1182761Sol Boucher 1143a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1144a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1145a0842b40441db5332a5290f941021636b1182761Sol Boucher public void setParameters(android.hardware.Camera.Parameters params) {} 1146a0842b40441db5332a5290f941021636b1182761Sol Boucher 1147a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1148a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1149a0842b40441db5332a5290f941021636b1182761Sol Boucher public android.hardware.Camera.Parameters getParameters() { return null; } 1150a0842b40441db5332a5290f941021636b1182761Sol Boucher 1151a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1152a0842b40441db5332a5290f941021636b1182761Sol Boucher public CameraSettings getSettings() { 115380cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher if (mLastSettings == null) { 115480cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher mLastSettings = mCameraHandler.buildSettings(mCapabilities); 115580cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher } 115680cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher return mLastSettings; 1157a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1158a0842b40441db5332a5290f941021636b1182761Sol Boucher 1159a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1160a0842b40441db5332a5290f941021636b1182761Sol Boucher public boolean applySettings(CameraSettings settings) { 1161de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (settings == null) { 1162de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.w(TAG, "null parameters in applySettings()"); 1163de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher return false; 1164de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1165de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher if (!(settings instanceof AndroidCamera2Settings)) { 1166de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher Log.e(TAG, "Provided settings not compatible with the backing framework API"); 1167de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher return false; 1168de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher } 1169de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher 1170772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher // Wait for any state that isn't OPENED 1171772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher if (applySettingsHelper(settings, ~AndroidCamera2StateHolder.CAMERA_UNOPENED)) { 117280cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher mLastSettings = settings; 117380cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher return true; 117480cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher } 117580cda8dae801f09c2ce928d0f3feb8a569939fc2Sol Boucher return false; 1176a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1177a0842b40441db5332a5290f941021636b1182761Sol Boucher 1178415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher @Override 1179415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher public void enableShutterSound(boolean enable) { 1180415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher mShutterSoundEnabled = enable; 1181415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher } 1182415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher 1183a0842b40441db5332a5290f941021636b1182761Sol Boucher // TODO: Implement 1184a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1185a0842b40441db5332a5290f941021636b1182761Sol Boucher public String dumpDeviceSettings() { return null; } 1186a0842b40441db5332a5290f941021636b1182761Sol Boucher 1187a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1188a0842b40441db5332a5290f941021636b1182761Sol Boucher public Handler getCameraHandler() { 1189a0842b40441db5332a5290f941021636b1182761Sol Boucher return AndroidCamera2AgentImpl.this.getCameraHandler(); 1190a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1191a0842b40441db5332a5290f941021636b1182761Sol Boucher 1192a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1193a0842b40441db5332a5290f941021636b1182761Sol Boucher public DispatchThread getDispatchThread() { 1194a0842b40441db5332a5290f941021636b1182761Sol Boucher return AndroidCamera2AgentImpl.this.getDispatchThread(); 1195a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1196a0842b40441db5332a5290f941021636b1182761Sol Boucher 1197a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1198a0842b40441db5332a5290f941021636b1182761Sol Boucher public CameraStateHolder getCameraState() { 1199a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCameraState; 1200a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1201a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1202a0842b40441db5332a5290f941021636b1182761Sol Boucher 1203a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher /** A linear state machine: each state entails all the states below it. */ 1204a0842b40441db5332a5290f941021636b1182761Sol Boucher private static class AndroidCamera2StateHolder extends CameraStateHolder { 1205a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // Usage flow: openCamera() -> applySettings() -> setPreviewTexture() -> startPreview() -> 1206a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher // autoFocus() -> takePicture() 1207772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher // States are mutually exclusive, but must be separate bits so that they can be used with 1208772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher // the StateHolder#waitForStates() and StateHolder#waitToAvoidStates() methods. 1209772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher // Do not set the state to be a combination of these values! 1210a0842b40441db5332a5290f941021636b1182761Sol Boucher /* Camera states */ 1211a0842b40441db5332a5290f941021636b1182761Sol Boucher /** No camera device is opened. */ 1212772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher public static final int CAMERA_UNOPENED = 1 << 0; 1213a0842b40441db5332a5290f941021636b1182761Sol Boucher /** A camera is opened, but no settings have been provided. */ 1214772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher public static final int CAMERA_UNCONFIGURED = 1 << 1; 1215a0842b40441db5332a5290f941021636b1182761Sol Boucher /** The open camera has been configured by providing it with settings. */ 1216772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher public static final int CAMERA_CONFIGURED = 1 << 2; 1217a0842b40441db5332a5290f941021636b1182761Sol Boucher /** A capture session is ready to stream a preview, but still has no repeating request. */ 1218772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher public static final int CAMERA_PREVIEW_READY = 1 << 3; 1219a0842b40441db5332a5290f941021636b1182761Sol Boucher /** A preview is currently being streamed. */ 1220772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher public static final int CAMERA_PREVIEW_ACTIVE = 1 << 4; 1221a97b7d1192e246a5f738991adca37cce282e1382Sol Boucher /** The lens is locked on a particular region. */ 1222772fcce3e51a9c7d33df6a9c278a908ac6902880Sol Boucher public static final int CAMERA_FOCUS_LOCKED = 1 << 5; 1223a0842b40441db5332a5290f941021636b1182761Sol Boucher 1224a0842b40441db5332a5290f941021636b1182761Sol Boucher public AndroidCamera2StateHolder() { 1225a0842b40441db5332a5290f941021636b1182761Sol Boucher this(CAMERA_UNOPENED); 1226a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1227a0842b40441db5332a5290f941021636b1182761Sol Boucher 1228a0842b40441db5332a5290f941021636b1182761Sol Boucher public AndroidCamera2StateHolder(int state) { 12297e0d39bf7b6e0f0df606e3f6c15f673f70fed3f7Sol Boucher super(state); 1230a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1231a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1232a0842b40441db5332a5290f941021636b1182761Sol Boucher 1233a0842b40441db5332a5290f941021636b1182761Sol Boucher private static class AndroidCamera2DeviceInfo implements CameraDeviceInfo { 1234a0842b40441db5332a5290f941021636b1182761Sol Boucher private final CameraManager mCameraManager; 1235a0842b40441db5332a5290f941021636b1182761Sol Boucher private final String[] mCameraIds; 1236a0842b40441db5332a5290f941021636b1182761Sol Boucher private final int mNumberOfCameras; 1237a0842b40441db5332a5290f941021636b1182761Sol Boucher private final int mFirstBackCameraId; 1238a0842b40441db5332a5290f941021636b1182761Sol Boucher private final int mFirstFrontCameraId; 1239a0842b40441db5332a5290f941021636b1182761Sol Boucher 1240a0842b40441db5332a5290f941021636b1182761Sol Boucher public AndroidCamera2DeviceInfo(CameraManager cameraManager, 1241a0842b40441db5332a5290f941021636b1182761Sol Boucher String[] cameraIds, int numberOfCameras) { 1242a0842b40441db5332a5290f941021636b1182761Sol Boucher mCameraManager = cameraManager; 1243a0842b40441db5332a5290f941021636b1182761Sol Boucher mCameraIds = cameraIds; 1244a0842b40441db5332a5290f941021636b1182761Sol Boucher mNumberOfCameras = numberOfCameras; 1245a0842b40441db5332a5290f941021636b1182761Sol Boucher 1246a0842b40441db5332a5290f941021636b1182761Sol Boucher int firstBackId = NO_DEVICE; 1247a0842b40441db5332a5290f941021636b1182761Sol Boucher int firstFrontId = NO_DEVICE; 1248a0842b40441db5332a5290f941021636b1182761Sol Boucher for (int id = 0; id < cameraIds.length; ++id) { 1249a0842b40441db5332a5290f941021636b1182761Sol Boucher try { 1250a0842b40441db5332a5290f941021636b1182761Sol Boucher int lensDirection = cameraManager.getCameraCharacteristics(cameraIds[id]) 1251a0842b40441db5332a5290f941021636b1182761Sol Boucher .get(CameraCharacteristics.LENS_FACING); 1252a0842b40441db5332a5290f941021636b1182761Sol Boucher if (firstBackId == NO_DEVICE && 1253a0842b40441db5332a5290f941021636b1182761Sol Boucher lensDirection == CameraCharacteristics.LENS_FACING_BACK) { 1254a0842b40441db5332a5290f941021636b1182761Sol Boucher firstBackId = id; 1255a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1256a0842b40441db5332a5290f941021636b1182761Sol Boucher if (firstFrontId == NO_DEVICE && 1257a0842b40441db5332a5290f941021636b1182761Sol Boucher lensDirection == CameraCharacteristics.LENS_FACING_FRONT) { 1258a0842b40441db5332a5290f941021636b1182761Sol Boucher firstFrontId = id; 1259a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1260a0842b40441db5332a5290f941021636b1182761Sol Boucher } catch (CameraAccessException ex) { 1261a0842b40441db5332a5290f941021636b1182761Sol Boucher Log.w(TAG, "Couldn't get characteristics of camera '" + id + "'", ex); 1262a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1263a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1264a0842b40441db5332a5290f941021636b1182761Sol Boucher mFirstBackCameraId = firstBackId; 1265a0842b40441db5332a5290f941021636b1182761Sol Boucher mFirstFrontCameraId = firstFrontId; 1266a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1267a0842b40441db5332a5290f941021636b1182761Sol Boucher 1268a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1269a0842b40441db5332a5290f941021636b1182761Sol Boucher public Characteristics getCharacteristics(int cameraId) { 1270a0842b40441db5332a5290f941021636b1182761Sol Boucher String actualId = mCameraIds[cameraId]; 1271a0842b40441db5332a5290f941021636b1182761Sol Boucher try { 1272a0842b40441db5332a5290f941021636b1182761Sol Boucher CameraCharacteristics info = mCameraManager.getCameraCharacteristics(actualId); 1273a0842b40441db5332a5290f941021636b1182761Sol Boucher return new AndroidCharacteristics2(info); 1274a0842b40441db5332a5290f941021636b1182761Sol Boucher } catch (CameraAccessException ex) { 1275a0842b40441db5332a5290f941021636b1182761Sol Boucher return null; 1276a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1277a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1278a0842b40441db5332a5290f941021636b1182761Sol Boucher 1279a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1280a0842b40441db5332a5290f941021636b1182761Sol Boucher public int getNumberOfCameras() { 1281a0842b40441db5332a5290f941021636b1182761Sol Boucher return mNumberOfCameras; 1282a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1283a0842b40441db5332a5290f941021636b1182761Sol Boucher 1284a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1285a0842b40441db5332a5290f941021636b1182761Sol Boucher public int getFirstBackCameraId() { 1286a0842b40441db5332a5290f941021636b1182761Sol Boucher return mFirstBackCameraId; 1287a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1288a0842b40441db5332a5290f941021636b1182761Sol Boucher 1289a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1290a0842b40441db5332a5290f941021636b1182761Sol Boucher public int getFirstFrontCameraId() { 1291a0842b40441db5332a5290f941021636b1182761Sol Boucher return mFirstFrontCameraId; 1292a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1293a0842b40441db5332a5290f941021636b1182761Sol Boucher 1294de48004068f8c16f9a56c60b0ed2485a67687b4bSol Boucher private static class AndroidCharacteristics2 extends Characteristics { 1295a0842b40441db5332a5290f941021636b1182761Sol Boucher private CameraCharacteristics mCameraInfo; 1296a0842b40441db5332a5290f941021636b1182761Sol Boucher 1297a0842b40441db5332a5290f941021636b1182761Sol Boucher AndroidCharacteristics2(CameraCharacteristics cameraInfo) { 1298a0842b40441db5332a5290f941021636b1182761Sol Boucher mCameraInfo = cameraInfo; 1299a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1300a0842b40441db5332a5290f941021636b1182761Sol Boucher 1301a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1302a0842b40441db5332a5290f941021636b1182761Sol Boucher public boolean isFacingBack() { 1303a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCameraInfo.get(CameraCharacteristics.LENS_FACING) 1304a0842b40441db5332a5290f941021636b1182761Sol Boucher .equals(CameraCharacteristics.LENS_FACING_BACK); 1305a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1306a0842b40441db5332a5290f941021636b1182761Sol Boucher 1307a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1308a0842b40441db5332a5290f941021636b1182761Sol Boucher public boolean isFacingFront() { 1309a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCameraInfo.get(CameraCharacteristics.LENS_FACING) 1310a0842b40441db5332a5290f941021636b1182761Sol Boucher .equals(CameraCharacteristics.LENS_FACING_FRONT); 1311a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1312a0842b40441db5332a5290f941021636b1182761Sol Boucher 1313a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1314a0842b40441db5332a5290f941021636b1182761Sol Boucher public int getSensorOrientation() { 1315a0842b40441db5332a5290f941021636b1182761Sol Boucher return mCameraInfo.get(CameraCharacteristics.SENSOR_ORIENTATION); 1316a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1317a0842b40441db5332a5290f941021636b1182761Sol Boucher 1318a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1319f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher public Matrix getPreviewTransform(int currentDisplayOrientation, 1320f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher RectF surfaceDimensions, 1321f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher RectF desiredBounds) { 1322f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher if (!orientationIsValid(currentDisplayOrientation)) { 1323f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher return new Matrix(); 1324f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher } 1325f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 1326f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher // The system transparently transforms the image to fill the surface 1327f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher // when the device is in its natural orientation. We rotate the 1328f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher // coordinates of the rectangle's corners to be relative to the 1329f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher // original image, instead of to the current screen orientation. 1330f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher float[] surfacePolygon = rotate(convertRectToPoly(surfaceDimensions), 1331f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 2 * currentDisplayOrientation / 90); 1332f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher float[] desiredPolygon = convertRectToPoly(desiredBounds); 1333f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 1334f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher Matrix transform = new Matrix(); 1335f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher // Use polygons instead of rectangles so that rotation will be 1336f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher // calculated, since that is not done by the new camera API. 1337f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher transform.setPolyToPoly(surfacePolygon, 0, desiredPolygon, 0, 4); 1338f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher return transform; 1339f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher } 1340f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 1341f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher @Override 1342a0842b40441db5332a5290f941021636b1182761Sol Boucher public boolean canDisableShutterSound() { 1343415cf3ee18640ad0799e5c9a738afd1d19c14883Sol Boucher return true; 1344a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1345f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 1346f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher private static float[] convertRectToPoly(RectF rf) { 1347f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher return new float[] {rf.left, rf.top, rf.right, rf.top, 1348f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher rf.right, rf.bottom, rf.left, rf.bottom}; 1349f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher } 1350f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 1351f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher private static float[] rotate(float[] arr, int times) { 1352f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher if (times < 0) { 1353f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher times = times % arr.length + arr.length; 1354f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher } 1355f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher 1356f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher float[] res = new float[arr.length]; 1357f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher for (int offset = 0; offset < arr.length; ++offset) { 1358f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher res[offset] = arr[(times + offset) % arr.length]; 1359f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher } 1360f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher return res; 1361f9feab9a826e5b33d811e757bdfdbfa0738fcfa5Sol Boucher } 1362a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1363a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1364a0842b40441db5332a5290f941021636b1182761Sol Boucher 1365a0842b40441db5332a5290f941021636b1182761Sol Boucher private static final CameraExceptionCallback sCameraExceptionCallback = 1366a0842b40441db5332a5290f941021636b1182761Sol Boucher new CameraExceptionCallback() { 1367a0842b40441db5332a5290f941021636b1182761Sol Boucher @Override 1368a0842b40441db5332a5290f941021636b1182761Sol Boucher public synchronized void onCameraException(RuntimeException e) { 1369a0842b40441db5332a5290f941021636b1182761Sol Boucher throw e; 1370a0842b40441db5332a5290f941021636b1182761Sol Boucher } 1371a0842b40441db5332a5290f941021636b1182761Sol Boucher }; 1372a0842b40441db5332a5290f941021636b1182761Sol Boucher} 1373