107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin/* 207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Copyright 2013 The Android Open Source Project 307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Licensed under the Apache License, Version 2.0 (the "License"); 507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * you may not use this file except in compliance with the License. 607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * You may obtain a copy of the License at 707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * http://www.apache.org/licenses/LICENSE-2.0 907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 1007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Unless required by applicable law or agreed to in writing, software 1107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * distributed under the License is distributed on an "AS IS" BASIS, 1207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * See the License for the specific language governing permissions and 1407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * limitations under the License. 1507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 1607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinpackage com.android.ex.camera2.blocking; 1707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 1807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.hardware.camera2.CameraAccessException; 1907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.hardware.camera2.CameraDevice; 2007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.hardware.camera2.CameraManager; 2107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.os.ConditionVariable; 2207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.os.Handler; 2307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.os.Looper; 2407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport android.util.Log; 2507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 2607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport com.android.ex.camera2.exceptions.TimeoutRuntimeException; 2707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 2807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinimport java.util.Objects; 2907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 3007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin/** 3107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Expose {@link CameraManager} functionality with blocking functions. 3207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 3307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * <p>Safe to use at the same time as the regular CameraManager, so this does not 3407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * duplicate any functionality that is already blocking.</p> 3507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 3607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * <p>Be careful when using this from UI thread! This function will typically block 375a772174d14175474e76701b07cc0be86c3df32aJiawen Chen * for about 500ms when successful, and as long as {@value #OPEN_TIME_OUT_MS}ms when timing out.</p> 3807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 3907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkinpublic class BlockingCameraManager { 4007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 415a772174d14175474e76701b07cc0be86c3df32aJiawen Chen private static final String TAG = "BlockingCameraManager"; 4207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 4307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 445a772174d14175474e76701b07cc0be86c3df32aJiawen Chen private static final int OPEN_TIME_OUT_MS = 2000; // ms time out for openCamera 4507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 4607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 4707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Exception thrown by {@link #openCamera} if the open fails asynchronously. 4807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 4907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public static class BlockingOpenException extends Exception { 5007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 515a772174d14175474e76701b07cc0be86c3df32aJiawen Chen * Suppress Eclipse warning 5207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 5307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private static final long serialVersionUID = 12397123891238912L; 5407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 5507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public static final int ERROR_DISCONNECTED = 0; // Does not clash with ERROR_... 5607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 5707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private final int mError; 5807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 5907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public boolean wasDisconnected() { 6007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return mError == ERROR_DISCONNECTED; 6107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 6207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 6307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public boolean wasError() { 6407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return mError != ERROR_DISCONNECTED; 6507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 6607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 6707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 6807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Returns the error code {@link ERROR_DISCONNECTED} if disconnected, or one of 69bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala * {@code CameraDevice.StateCallback#ERROR_*} if there was another error. 7007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 7107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @return int Disconnect/error code 7207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 7307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public int getCode() { 7407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return mError; 7507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 7607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 7707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 7807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Thrown when camera device enters error state during open, or if 7907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * it disconnects. 8007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 8107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @param errorCode 8207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @param message 8307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 84bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala * @see {@link CameraDevice.StateCallback#ERROR_CAMERA_DEVICE} 8507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 8607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public BlockingOpenException(int errorCode, String message) { 8707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin super(message); 8807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mError = errorCode; 8907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 9007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 9107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 9207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private final CameraManager mManager; 9307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 9407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 9507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Create a new blocking camera manager. 9607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 9707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @param manager 9807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * CameraManager returned by 9907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * {@code Context.getSystemService(Context.CAMERA_SERVICE)} 10007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 10107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public BlockingCameraManager(CameraManager manager) { 10207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (manager == null) { 10307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new IllegalArgumentException("manager must not be null"); 10407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 10507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mManager = manager; 10607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 10707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 10807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 10907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Open the camera, blocking it until it succeeds or fails. 11007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 11107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * <p>Note that the Handler provided must not be null. Furthermore, if there is a handler, 11207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * its Looper must not be the current thread's Looper. Otherwise we'd never receive 11307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * the callbacks from the CameraDevice since this function would prevent them from being 11407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * processed.</p> 11507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 11607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * <p>Throws {@link CameraAccessException} for the same reason {@link CameraManager#openCamera} 11707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * does.</p> 11807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 11907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * <p>Throws {@link BlockingOpenException} when the open fails asynchronously (due to 120bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala * {@link CameraDevice.StateCallback#onDisconnected(CameraDevice)} or 121bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala * ({@link CameraDevice.StateCallback#onError(CameraDevice)}.</p> 12207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 12307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * <p>Throws {@link TimeoutRuntimeException} if opening times out. This is usually 12407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * highly unrecoverable, and all future calls to opening that camera will fail since the 12507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * service will think it's busy. This class will do its best to clean up eventually.</p> 12607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 12707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @param cameraId 12807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Id of the camera 12907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @param listener 13007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Listener to the camera. onOpened, onDisconnected, onError need not be implemented. 13107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @param handler 13207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Handler which to run the listener on. Must not be null. 13307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 13407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @return CameraDevice 13507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 13607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @throws IllegalArgumentException 13707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * If the handler is null, or if the handler's looper is current. 13807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @throws CameraAccessException 13907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * If open fails immediately. 14007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @throws BlockingOpenException 14107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * If open fails after blocking for some amount of time. 14207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * @throws TimeoutRuntimeException 14307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * If opening times out. Typically unrecoverable. 14407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 145bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala public CameraDevice openCamera(String cameraId, CameraDevice.StateCallback listener, 14607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin Handler handler) throws CameraAccessException, BlockingOpenException { 14707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 14807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (handler == null) { 14907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new IllegalArgumentException("handler must not be null"); 15007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } else if (handler.getLooper() == Looper.myLooper()) { 15107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new IllegalArgumentException("handler's looper must not be the current looper"); 15207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 15307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 15407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return (new OpenListener(mManager, cameraId, listener, handler)).blockUntilOpen(); 15507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 15607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 15707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private static void assertEquals(Object a, Object b) { 15807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (!Objects.equals(a, b)) { 15907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new AssertionError("Expected " + a + ", but got " + b); 16007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 16107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 16207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 16307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 16407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Block until CameraManager#openCamera finishes with onOpened/onError/onDisconnected 16507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 166bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala * <p>Pass-through all StateCallback changes to the proxy.</p> 16707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 1685a772174d14175474e76701b07cc0be86c3df32aJiawen Chen * <p>Time out after {@link #OPEN_TIME_OUT_MS} and unblock. Clean up camera if it arrives 16907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * later.</p> 17007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 171bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala private class OpenListener extends CameraDevice.StateCallback { 17207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private static final int ERROR_UNINITIALIZED = -1; 17307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 17407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private final String mCameraId; 17507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 176bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala private final CameraDevice.StateCallback mProxy; 17707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 17807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private final Object mLock = new Object(); 17907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private final ConditionVariable mDeviceReady = new ConditionVariable(); 18007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 18107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private CameraDevice mDevice = null; 18207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private boolean mSuccess = false; 18307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private int mError = ERROR_UNINITIALIZED; 18407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private boolean mDisconnected = false; 18507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 18607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private boolean mNoReply = true; // Start with no reply until proven otherwise 18707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private boolean mTimedOut = false; 18807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 18907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin OpenListener(CameraManager manager, String cameraId, 190bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala CameraDevice.StateCallback listener, Handler handler) 19107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throws CameraAccessException { 19207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mCameraId = cameraId; 19307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mProxy = listener; 19407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin manager.openCamera(cameraId, this, handler); 19507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 19607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 19707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin // Freebie check to make sure we aren't calling functions multiple times. 19807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin // We should still test the state interactions in a separate more thorough test. 19907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin private void assertInitialState() { 20007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin assertEquals(null, mDevice); 20107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin assertEquals(false, mDisconnected); 20207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin assertEquals(ERROR_UNINITIALIZED, mError); 20307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin assertEquals(false, mSuccess); 20407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 20507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 20607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin @Override 20707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public void onOpened(CameraDevice camera) { 20807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (VERBOSE) { 20907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin Log.v(TAG, "onOpened: camera " + ((camera != null) ? camera.getId() : "null")); 21007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 21107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 21207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin synchronized (mLock) { 21307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin assertInitialState(); 21407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mNoReply = false; 21507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mSuccess = true; 21607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDevice = camera; 21707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDeviceReady.open(); 21807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 21907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mTimedOut && camera != null) { 22007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin camera.close(); 22107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return; 22207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 22307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 22407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 22507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mProxy != null) mProxy.onOpened(camera); 22607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 22707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 22807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin @Override 22907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public void onDisconnected(CameraDevice camera) { 23007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (VERBOSE) { 23107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin Log.v(TAG, "onDisconnected: camera " 23207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin + ((camera != null) ? camera.getId() : "null")); 23307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 23407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 23507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin synchronized (mLock) { 23607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin assertInitialState(); 23707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mNoReply = false; 23807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDisconnected = true; 23907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDevice = camera; 24007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDeviceReady.open(); 24107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 24207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mTimedOut && camera != null) { 24307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin camera.close(); 24407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return; 24507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 24607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 24707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 24807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mProxy != null) mProxy.onDisconnected(camera); 24907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 25007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 25107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin @Override 25207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public void onError(CameraDevice camera, int error) { 25307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (VERBOSE) { 25407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin Log.v(TAG, "onError: camera " + ((camera != null) ? camera.getId() : "null")); 25507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 25607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 25707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (error <= 0) { 25807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new AssertionError("Expected error to be a positive number"); 25907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 26007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 26107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin synchronized (mLock) { 26207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin // Don't assert initial state. Error can happen later. 26307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mNoReply = false; 26407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mError = error; 26507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDevice = camera; 26607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDeviceReady.open(); 26707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 26807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mTimedOut && camera != null) { 26907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin camera.close(); 27007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return; 27107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 27207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 27307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 27407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mProxy != null) mProxy.onError(camera, error); 27507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 27607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 27707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin @Override 27807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin public void onClosed(CameraDevice camera) { 27907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mProxy != null) mProxy.onClosed(camera); 28007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 28107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 28207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin CameraDevice blockUntilOpen() throws BlockingOpenException { 28307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 28407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Block until onOpened, onError, or onDisconnected 28507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 2865a772174d14175474e76701b07cc0be86c3df32aJiawen Chen if (!mDeviceReady.block(OPEN_TIME_OUT_MS)) { 28707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 28807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin synchronized (mLock) { 28907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mNoReply) { // Give the async camera a fighting chance (required) 29007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mTimedOut = true; // Clean up camera if it ever arrives later 29107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new TimeoutRuntimeException(String.format( 29207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin "Timed out after %d ms while trying to open camera device %s", 2935a772174d14175474e76701b07cc0be86c3df32aJiawen Chen OPEN_TIME_OUT_MS, mCameraId)); 29407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 29507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 29607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 29707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 29807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin synchronized (mLock) { 29907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin /** 30007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * Determine which state we ended up in: 30107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * 30207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * - Throw exceptions for onError/onDisconnected 30307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin * - Return device for onOpened 30407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin */ 30507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (!mSuccess && mDevice != null) { 30607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mDevice.close(); 30707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 30807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin 30907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mSuccess) { 31007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin return mDevice; 31107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } else { 31207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin if (mDisconnected) { 31307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new BlockingOpenException( 31407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin BlockingOpenException.ERROR_DISCONNECTED, 31507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin "Failed to open camera device: it is disconnected"); 31607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } else if (mError != ERROR_UNINITIALIZED) { 31707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new BlockingOpenException( 31807f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin mError, 31907f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin "Failed to open camera device: error code " + mError); 32007f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } else { 32107f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin throw new AssertionError("Failed to open camera device (impl bug)"); 32207f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 32307f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 32407f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 32507f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 32607f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin } 32707f09b47112dc1094649da00f7e86024b67d5777Igor Murashkin} 328