177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin/*
277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * Copyright 2014 The Android Open Source Project
377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *
477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * you may not use this file except in compliance with the License.
677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * You may obtain a copy of the License at
777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *
877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *
1077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * Unless required by applicable law or agreed to in writing, software
1177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
1277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * See the License for the specific language governing permissions and
1477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * limitations under the License.
1577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin */
1677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinpackage com.android.ex.camera2.blocking;
1777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
1877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport android.hardware.camera2.CameraCaptureSession;
1977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport android.os.ConditionVariable;
2039c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yehimport android.os.SystemClock;
2177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport android.util.Log;
22ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvalaimport android.view.Surface;
2377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
2477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport com.android.ex.camera2.exceptions.TimeoutRuntimeException;
2577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport com.android.ex.camera2.utils.StateChangeListener;
2677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport com.android.ex.camera2.utils.StateWaiter;
2777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
2839c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yehimport java.util.List;
2977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport java.util.ArrayList;
3039c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yehimport java.util.HashMap;
3177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport java.util.concurrent.Future;
3277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport java.util.concurrent.TimeUnit;
3377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkinimport java.util.concurrent.TimeoutException;
3477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
3577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
3677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin/**
3777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * A camera session listener that implements blocking operations on session state changes.
3877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *
3977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * <p>Provides a waiter that can be used to block until the next unobserved state of the
4077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * requested type arrives.</p>
4177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *
42bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala * <p>Pass-through all StateCallback changes to the proxy.</p>
4377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin *
4477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin * @see #getStateWaiter
4577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin */
46bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvalapublic class BlockingSessionCallback extends CameraCaptureSession.StateCallback {
4777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
4877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Session is configured, ready for captures
4977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
5077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public static final int SESSION_CONFIGURED = 0;
5177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
5277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
5377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Session has failed to configure, can't do any captures
5477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
5577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public static final int SESSION_CONFIGURE_FAILED = 1;
5677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
5777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
5877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Session is ready
5977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
6077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public static final int SESSION_READY = 2;
6177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
6277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
6377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Session is active (transitory)
6477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
6577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public static final int SESSION_ACTIVE = 3;
6677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
6777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
6877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Session is closed
6977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
7077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public static final int SESSION_CLOSED = 4;
7177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
72046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen    private static final int NUM_STATES = 5;
7377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
7477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /*
7577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Private fields
7677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
77bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala    private static final String TAG = "BlockingSessionCallback";
7877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
7977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
80bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala    private final CameraCaptureSession.StateCallback mProxy;
8177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    private final SessionFuture mSessionFuture = new SessionFuture();
8277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
839b5facd03adbb55f6a1faa49788308f763a54ff0Ruben Brunk    private final StateWaiter mStateWaiter = new StateWaiter(sStateNames);
8477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    private final StateChangeListener mStateChangeListener = mStateWaiter.getListener();
8539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh    private final HashMap<CameraCaptureSession, List<Surface> > mPreparedSurfaces = new HashMap<>();
8677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
879b5facd03adbb55f6a1faa49788308f763a54ff0Ruben Brunk    private static final String[] sStateNames = {
8877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        "SESSION_CONFIGURED",
8977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        "SESSION_CONFIGURE_FAILED",
9077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        "SESSION_READY",
9177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        "SESSION_ACTIVE",
9277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        "SESSION_CLOSED"
9377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    };
9477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
9577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
9677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Create a blocking session listener without forwarding the session listener invocations
9777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * to another session listener.
9877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
99bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala    public BlockingSessionCallback() {
10077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mProxy = null;
10177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
10277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
10377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
10477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Create a blocking session listener; forward original listener invocations
10577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * into {@code listener}.
10677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     *
10777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * @param listener a non-{@code null} listener to forward invocations into
10877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     *
10977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * @throws NullPointerException if {@code listener} was {@code null}
11077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
111bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala    public BlockingSessionCallback(CameraCaptureSession.StateCallback listener) {
11277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        if (listener == null) {
11377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            throw new NullPointerException("listener must not be null");
11477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
11577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mProxy = listener;
11677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
11777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
11877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
11977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Acquire the state waiter; can be used to block until a set of state transitions have
12077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * been reached.
12177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     *
12277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * <p>Only one thread should wait at a time.</p>
12377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
12477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public StateWaiter getStateWaiter() {
12577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        return mStateWaiter;
12677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
12777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
12877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /**
12977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * Return session if already have it; otherwise wait until any of the session listener
13077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * invocations fire and the session is available.
13177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     *
13277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * <p>Does not consume any of the states from the state waiter.</p>
13377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     *
13477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * @param timeoutMs how many milliseconds to wait for
13577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * @return a non-{@code null} {@link CameraCaptureSession} instance
13677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     *
13777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     * @throws TimeoutRuntimeException if waiting for more than {@long timeoutMs}
13877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
13977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public CameraCaptureSession waitAndGetSession(long timeoutMs) {
14077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        try {
14177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            return mSessionFuture.get(timeoutMs, TimeUnit.MILLISECONDS);
14277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        } catch (TimeoutException e) {
14377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            throw new TimeoutRuntimeException(
14477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin                    String.format("Failed to get session after %s milliseconds", timeoutMs), e);
14577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
14677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
14777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
14877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    /*
149bb013aa3e197e881756be5ad13e6ad30bfb4aeffEino-Ville Talvala     * CameraCaptureSession.StateCallback implementation
15077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin     */
15177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
15277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    @Override
15377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public void onActive(CameraCaptureSession session) {
15477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mSessionFuture.setSession(session);
15577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        if (mProxy != null) mProxy.onActive(session);
15677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mStateChangeListener.onStateChanged(SESSION_ACTIVE);
15777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
15877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
15977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    @Override
16077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public void onClosed(CameraCaptureSession session) {
16177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mSessionFuture.setSession(session);
16277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        if (mProxy != null) mProxy.onClosed(session);
16377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mStateChangeListener.onStateChanged(SESSION_CLOSED);
16439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh        synchronized (mPreparedSurfaces) {
16539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            mPreparedSurfaces.remove(session);
16639c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh        }
16777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
16877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
16977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    @Override
17077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public void onConfigured(CameraCaptureSession session) {
17177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mSessionFuture.setSession(session);
172046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen        if (mProxy != null) {
173046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen            mProxy.onConfigured(session);
174046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen        }
17577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mStateChangeListener.onStateChanged(SESSION_CONFIGURED);
17677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
17777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
17877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    @Override
17977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public void onConfigureFailed(CameraCaptureSession session) {
18077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mSessionFuture.setSession(session);
181046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen        if (mProxy != null) {
182046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen            mProxy.onConfigureFailed(session);
183046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen        }
18477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mStateChangeListener.onStateChanged(SESSION_CONFIGURE_FAILED);
18577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
18677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
18777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    @Override
18877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    public void onReady(CameraCaptureSession session) {
18977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mSessionFuture.setSession(session);
190046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen        if (mProxy != null) {
191046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen            mProxy.onReady(session);
192046ba28a082f30d56a1ac63eaa13b5cf95093db6Jiawen Chen        }
19377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        mStateChangeListener.onStateChanged(SESSION_READY);
19477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
19577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
196ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala    @Override
197ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala    public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
198ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala        mSessionFuture.setSession(session);
199ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala        if (mProxy != null) {
200ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala            mProxy.onSurfacePrepared(session, surface);
201ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala        }
202ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala        // Surface prepared doesn't cause a session state change, so don't trigger the
203ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala        // state change listener
20439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh        synchronized (mPreparedSurfaces) {
20539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            List<Surface> preparedSurfaces = mPreparedSurfaces.get(session);
20639c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            if (preparedSurfaces == null) {
20739c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                preparedSurfaces = new ArrayList<Surface>();
20839c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            }
20939c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            preparedSurfaces.add(surface);
21039c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            mPreparedSurfaces.put(session, preparedSurfaces);
21139c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            mPreparedSurfaces.notifyAll();
21239c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh        }
21339c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh    }
21439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh
2153308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang    @Override
2163308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang    public void onCaptureQueueEmpty(CameraCaptureSession session) {
2173308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang        mSessionFuture.setSession(session);
2183308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang        if (mProxy != null) {
2193308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang            mProxy.onCaptureQueueEmpty(session);
2203308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang        }
2213308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang    }
2223308f56e9af5f38f4b03e8b7700d3e8bf400fb38Shuzhen Wang
22339c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh    /**
22439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     * Wait until the designated surface is prepared by the camera capture session.
22539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     *
22639c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     * @param session the input {@link CameraCaptureSession} to wait for
22739c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     * @param surface the input {@link Surface} to wait for
22839c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     * @param timeoutMs how many milliseconds to wait for
22939c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     *
23039c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     * @throws TimeoutRuntimeException if waiting for more than {@long timeoutMs}
23139c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh     */
23239c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh    public void waitForSurfacePrepared(
23339c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            CameraCaptureSession session, Surface surface, long timeoutMs) {
23439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh        synchronized (mPreparedSurfaces) {
23539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            List<Surface> preparedSurfaces = mPreparedSurfaces.get(session);
23639c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            if (preparedSurfaces != null && preparedSurfaces.contains(surface)) {
23739c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                return;
23839c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            }
23939c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            try {
24039c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                long waitTimeRemaining = timeoutMs;
24139c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                while (waitTimeRemaining > 0) {
24239c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    long waitStartTime = SystemClock.elapsedRealtime();
24339c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    mPreparedSurfaces.wait(timeoutMs);
24439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    long waitTime = SystemClock.elapsedRealtime() - waitStartTime;
24539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    waitTimeRemaining -= waitTime;
24639c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    preparedSurfaces = mPreparedSurfaces.get(session);
24739c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    if (waitTimeRemaining >= 0 && preparedSurfaces != null &&
24839c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                            preparedSurfaces.contains(surface)) {
24939c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                        return;
25039c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                    }
25139c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                }
25239c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                throw new TimeoutRuntimeException(
25339c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                        "Unable to get Surface prepared in " + timeoutMs + "ms");
25439c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            } catch (InterruptedException ie) {
25539c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh                throw new AssertionError();
25639c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh            }
25739c31d49ce38158b7708581df0813b03e32d6eeaYin-Chia Yeh        }
258ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala    }
259ebb6c5111f287a8cf55f1dcac7d7c5b76d9260ffEino-Ville Talvala
26077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    private static class SessionFuture implements Future<CameraCaptureSession> {
26177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        private volatile CameraCaptureSession mSession;
26277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        ConditionVariable mCondVar = new ConditionVariable(/*opened*/false);
26377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
26477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        public void setSession(CameraCaptureSession session) {
26577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            mSession = session;
26677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            mCondVar.open();
26777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
26877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
26977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        @Override
27077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        public boolean cancel(boolean mayInterruptIfRunning) {
27177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            return false; // don't allow canceling this task
27277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
27377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
27477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        @Override
27577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        public boolean isCancelled() {
27677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            return false; // can never cancel this task
27777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
27877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
27977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        @Override
28077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        public boolean isDone() {
28177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            return mSession != null;
28277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
28377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
28477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        @Override
28577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        public CameraCaptureSession get() {
28677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            mCondVar.block();
28777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            return mSession;
28877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
28977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
29077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        @Override
29177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        public CameraCaptureSession get(long timeout, TimeUnit unit) throws TimeoutException {
29277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            long timeoutMs = unit.convert(timeout, TimeUnit.MILLISECONDS);
29377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            if (!mCondVar.block(timeoutMs)) {
29477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin                throw new TimeoutException(
29577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin                        "Failed to receive session after " + timeout + " " + unit);
29677b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            }
29777b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
29877b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            if (mSession == null) {
29977b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin                throw new AssertionError();
30077b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            }
30177b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin            return mSession;
30277b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin        }
30377b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin
30477b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin    }
30577b7bbe039393c2d8c1107c07c65028886eef252Igor Murashkin}
306