public class

ForceCloseCaptureSession

extends java.lang.Object

 java.lang.Object

↳androidx.camera.camera2.internal.compat.workaround.ForceCloseCaptureSession

Gradle dependencies

compile group: 'androidx.camera', name: 'camera-camera2', version: '1.5.0-alpha01'

  • groupId: androidx.camera
  • artifactId: camera-camera2
  • version: 1.5.0-alpha01

Artifact androidx.camera:camera-camera2:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

The workaround is used to set the androidx.camera.camera2.internal.CaptureSession to closed state since the may not be called after the android.hardware.camera2.CameraCaptureSession is closed.

Summary

Constructors
publicForceCloseCaptureSession(Quirks deviceQuirks)

Constructor of the ForceCloseCaptureSession workaround

Methods
public voidonSessionConfigured(SynchronizedCaptureSession session, java.util.List<SynchronizedCaptureSession> creatingSessions, java.util.List<SynchronizedCaptureSession> sessions, ForceCloseCaptureSession.OnConfigured onConfigured)

For b/144817309, the onClosed() callback on might not be invoked if the capture session is not the latest one.

public booleanshouldForceClose()

Return true if the obsolete non-closed capture sessions should be forced closed.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ForceCloseCaptureSession(Quirks deviceQuirks)

Constructor of the ForceCloseCaptureSession workaround

Methods

public boolean shouldForceClose()

Return true if the obsolete non-closed capture sessions should be forced closed.

public void onSessionConfigured(SynchronizedCaptureSession session, java.util.List<SynchronizedCaptureSession> creatingSessions, java.util.List<SynchronizedCaptureSession> sessions, ForceCloseCaptureSession.OnConfigured onConfigured)

For b/144817309, the onClosed() callback on might not be invoked if the capture session is not the latest one. To align the fixed framework behavior, we manually call the onClosed() when a new CameraCaptureSession is created.

Source

/*
 * Copyright 2022 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 androidx.camera.camera2.internal.compat.workaround;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.camera2.internal.SynchronizedCaptureSession;
import androidx.camera.camera2.internal.compat.quirk.CaptureSessionOnClosedNotCalledQuirk;
import androidx.camera.core.impl.Quirks;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * The workaround is used to set the {@link androidx.camera.camera2.internal.CaptureSession} to
 * closed state since the
 * {@link android.hardware.camera2.CameraCaptureSession.StateCallback#onClosed} may not be called
 * after the {@link android.hardware.camera2.CameraCaptureSession} is closed.
 *
 * @see CaptureSessionOnClosedNotCalledQuirk
 */
public class ForceCloseCaptureSession {

    @Nullable
    private final CaptureSessionOnClosedNotCalledQuirk mCaptureSessionOnClosedNotCalledQuirk;

    /** Constructor of the ForceCloseCaptureSession workaround */
    public ForceCloseCaptureSession(@NonNull Quirks deviceQuirks) {
        mCaptureSessionOnClosedNotCalledQuirk =
                deviceQuirks.get(CaptureSessionOnClosedNotCalledQuirk.class);
    }

    /** Return true if the obsolete non-closed capture sessions should be forced closed. */
    public boolean shouldForceClose() {
        return mCaptureSessionOnClosedNotCalledQuirk != null;
    }

    /**
     * For b/144817309, the onClosed() callback on
     * {@link android.hardware.camera2.CameraCaptureSession.StateCallback}
     * might not be invoked if the capture session is not the latest one. To align the fixed
     * framework behavior, we manually call the onClosed() when a new CameraCaptureSession is
     * created.
     */
    public void onSessionConfigured(@NonNull SynchronizedCaptureSession session,
            @NonNull List<SynchronizedCaptureSession> creatingSessions,
            @NonNull List<SynchronizedCaptureSession> sessions,
            @NonNull OnConfigured onConfigured) {
        if (shouldForceClose()) {
            Set<SynchronizedCaptureSession> staleCreatingSessions = new LinkedHashSet<>();
            for (SynchronizedCaptureSession s : creatingSessions) {
                // Collect the sessions that started configuring before the current session. The
                // current session and the session that starts configure after the current session
                // are not included since they don't need to be closed.
                if (s == session) {
                    break;
                }
                staleCreatingSessions.add(s);
            }
            // Once the CaptureSession is configured, the stale CaptureSessions should not have
            // chance to complete the configuration flow. Force change to configure fail since
            // the configureFail will treat the CaptureSession is closed. More detail please see
            // b/158540776.
            forceOnConfigureFailed(staleCreatingSessions);
        }

        onConfigured.run(session);

        // Once the new CameraCaptureSession is created, all the previous opened
        // CameraCaptureSession can be treated as closed (more detail in b/144817309),
        // trigger its associated StateCallback#onClosed callback to finish the
        // session close flow.
        if (shouldForceClose()) {
            Set<SynchronizedCaptureSession> openedSessions = new LinkedHashSet<>();
            for (SynchronizedCaptureSession s : sessions) {

                // The entrySet keys of the LinkedHashMap should be insertion-ordered, so we
                // get the previous capture sessions by iterate it from the beginning.
                if (s == session) {
                    break;
                }
                openedSessions.add(s);
            }

            forceOnClosed(openedSessions);
        }
    }

    private void forceOnConfigureFailed(@NonNull Set<SynchronizedCaptureSession> sessions) {
        for (SynchronizedCaptureSession session : sessions) {
            session.getStateCallback().onConfigureFailed(session);
        }
    }

    private void forceOnClosed(@NonNull Set<SynchronizedCaptureSession> sessions) {
        for (SynchronizedCaptureSession session : sessions) {
            session.getStateCallback().onClosed(session);
        }
    }

    /** Interface to forward call of the onConfigured() method. */
    @FunctionalInterface
    public interface OnConfigured {
        /** Run the onConfigured() method. */
        void run(@NonNull SynchronizedCaptureSession session);
    }
}