/* * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ex.camera2.blocking; import android.hardware.camera2.CameraCaptureSession; import android.os.ConditionVariable; import android.os.SystemClock; import android.util.Log; import android.view.Surface; import com.android.ex.camera2.exceptions.TimeoutRuntimeException; import com.android.ex.camera2.utils.StateChangeListener; import com.android.ex.camera2.utils.StateWaiter; import java.util.List; import java.util.ArrayList; import java.util.HashMap; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; /** * A camera session listener that implements blocking operations on session state changes. * *
Provides a waiter that can be used to block until the next unobserved state of the * requested type arrives.
* *Pass-through all StateCallback changes to the proxy.
* * @see #getStateWaiter */ public class BlockingSessionCallback extends CameraCaptureSession.StateCallback { /** * Session is configured, ready for captures */ public static final int SESSION_CONFIGURED = 0; /** * Session has failed to configure, can't do any captures */ public static final int SESSION_CONFIGURE_FAILED = 1; /** * Session is ready */ public static final int SESSION_READY = 2; /** * Session is active (transitory) */ public static final int SESSION_ACTIVE = 3; /** * Session is closed */ public static final int SESSION_CLOSED = 4; private static final int NUM_STATES = 5; /* * Private fields */ private static final String TAG = "BlockingSessionCallback"; private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); private final CameraCaptureSession.StateCallback mProxy; private final SessionFuture mSessionFuture = new SessionFuture(); private final StateWaiter mStateWaiter = new StateWaiter(sStateNames); private final StateChangeListener mStateChangeListener = mStateWaiter.getListener(); private final HashMapOnly one thread should wait at a time.
*/ public StateWaiter getStateWaiter() { return mStateWaiter; } /** * Return session if already have it; otherwise wait until any of the session listener * invocations fire and the session is available. * *Does not consume any of the states from the state waiter.
* * @param timeoutMs how many milliseconds to wait for * @return a non-{@code null} {@link CameraCaptureSession} instance * * @throws TimeoutRuntimeException if waiting for more than {@long timeoutMs} */ public CameraCaptureSession waitAndGetSession(long timeoutMs) { try { return mSessionFuture.get(timeoutMs, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { throw new TimeoutRuntimeException( String.format("Failed to get session after %s milliseconds", timeoutMs), e); } } /* * CameraCaptureSession.StateCallback implementation */ @Override public void onActive(CameraCaptureSession session) { mSessionFuture.setSession(session); if (mProxy != null) mProxy.onActive(session); mStateChangeListener.onStateChanged(SESSION_ACTIVE); } @Override public void onClosed(CameraCaptureSession session) { mSessionFuture.setSession(session); if (mProxy != null) mProxy.onClosed(session); mStateChangeListener.onStateChanged(SESSION_CLOSED); synchronized (mPreparedSurfaces) { mPreparedSurfaces.remove(session); } } @Override public void onConfigured(CameraCaptureSession session) { mSessionFuture.setSession(session); if (mProxy != null) { mProxy.onConfigured(session); } mStateChangeListener.onStateChanged(SESSION_CONFIGURED); } @Override public void onConfigureFailed(CameraCaptureSession session) { mSessionFuture.setSession(session); if (mProxy != null) { mProxy.onConfigureFailed(session); } mStateChangeListener.onStateChanged(SESSION_CONFIGURE_FAILED); } @Override public void onReady(CameraCaptureSession session) { mSessionFuture.setSession(session); if (mProxy != null) { mProxy.onReady(session); } mStateChangeListener.onStateChanged(SESSION_READY); } @Override public void onSurfacePrepared(CameraCaptureSession session, Surface surface) { mSessionFuture.setSession(session); if (mProxy != null) { mProxy.onSurfacePrepared(session, surface); } // Surface prepared doesn't cause a session state change, so don't trigger the // state change listener synchronized (mPreparedSurfaces) { List