public final class

LifecycleCamera

extends java.lang.Object

implements LifecycleObserver, Camera

 java.lang.Object

↳androidx.camera.lifecycle.LifecycleCamera

Gradle dependencies

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

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

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

Overview

A CameraUseCaseAdapter whose starting and stopping is controlled by a Lifecycle.

Summary

Methods
public CameraControlgetCameraControl()

public CameraInfogetCameraInfo()

public CameraUseCaseAdaptergetCameraUseCaseAdapter()

public CameraConfiggetExtendedConfig()

public LifecycleOwnergetLifecycleOwner()

Retrieves the lifecycle owner.

public java.util.List<UseCase>getUseCases()

public booleanisActive()

public booleanisBound(UseCase useCase)

public booleanisUseCasesCombinationSupported(boolean withStreamSharing, UseCase useCases[])

public voidonDestroy(LifecycleOwner lifecycleOwner)

public voidonPause(LifecycleOwner lifecycleOwner)

public voidonResume(LifecycleOwner lifecycleOwner)

public voidonStart(LifecycleOwner lifecycleOwner)

public voidonStop(LifecycleOwner lifecycleOwner)

public voidsuspend()

Suspend the camera so that it ignore lifecycle events.

public voidunsuspend()

Unsuspend the camera so it will start listening to lifecycle events.

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

Methods

public void onStart(LifecycleOwner lifecycleOwner)

public void onStop(LifecycleOwner lifecycleOwner)

public void onDestroy(LifecycleOwner lifecycleOwner)

public void onResume(LifecycleOwner lifecycleOwner)

public void onPause(LifecycleOwner lifecycleOwner)

public void suspend()

Suspend the camera so that it ignore lifecycle events.

This will also close the CameraUseCaseAdapter.

This will be idempotent if the camera is already suspended.

public void unsuspend()

Unsuspend the camera so it will start listening to lifecycle events.

This will also open the CameraUseCaseAdapter if the lifecycle is in a STARTED state or above.

This will be idempotent if the camera is already in an unsuspended state.

public boolean isActive()

public boolean isBound(UseCase useCase)

public java.util.List<UseCase> getUseCases()

public LifecycleOwner getLifecycleOwner()

Retrieves the lifecycle owner.

public CameraUseCaseAdapter getCameraUseCaseAdapter()

public CameraControl getCameraControl()

public CameraInfo getCameraInfo()

public CameraConfig getExtendedConfig()

public boolean isUseCasesCombinationSupported(boolean withStreamSharing, UseCase useCases[])

Source

/*
 * Copyright 2020 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.lifecycle;

import android.annotation.SuppressLint;
import android.os.Build;

import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraControl;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.UseCase;
import androidx.camera.core.impl.CameraConfig;
import androidx.camera.core.internal.CameraUseCaseAdapter;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.Lifecycle.State;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * A {@link CameraUseCaseAdapter} whose starting and stopping is controlled by a
 *  {@link Lifecycle}.
 */
@SuppressLint("UsesNonDefaultVisibleForTesting")
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public final class LifecycleCamera implements LifecycleObserver, Camera {
    private final Object mLock = new Object();

    @GuardedBy("mLock")
    // The lifecycle that controls the LifecycleCamera
    private final LifecycleOwner mLifecycleOwner;

    private final CameraUseCaseAdapter mCameraUseCaseAdapter;

    @GuardedBy("mLock")
    private volatile boolean mIsActive = false;

    @GuardedBy("mLock")
    private boolean mSuspended = false;

    @GuardedBy("mLock")
    private boolean mReleased = false;

    /**
     * Wraps an existing {@link CameraUseCaseAdapter} so it is controlled by lifecycle transitions.
     */
    LifecycleCamera(LifecycleOwner lifecycleOwner, CameraUseCaseAdapter cameraUseCaseAdaptor) {
        mLifecycleOwner = lifecycleOwner;
        mCameraUseCaseAdapter = cameraUseCaseAdaptor;

        // Make sure that the attach state of mCameraUseCaseAdapter matches that of the lifecycle
        if (mLifecycleOwner.getLifecycle().getCurrentState().isAtLeast(State.STARTED)) {
            mCameraUseCaseAdapter.attachUseCases();
        } else {
            mCameraUseCaseAdapter.detachUseCases();
        }
        lifecycleOwner.getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart(@NonNull LifecycleOwner lifecycleOwner) {
        synchronized (mLock) {
            if (!mSuspended && !mReleased) {
                mCameraUseCaseAdapter.attachUseCases();
                mIsActive = true;
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop(@NonNull LifecycleOwner lifecycleOwner) {
        synchronized (mLock) {
            if (!mSuspended && !mReleased) {
                mCameraUseCaseAdapter.detachUseCases();
                mIsActive = false;
            }
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy(@NonNull LifecycleOwner lifecycleOwner) {
        synchronized (mLock) {
            mCameraUseCaseAdapter.removeUseCases(mCameraUseCaseAdapter.getUseCases());
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void onResume(@NonNull LifecycleOwner lifecycleOwner) {
        // ActiveResumingMode is required for Multi-window which is supported since Android 7(N).
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mCameraUseCaseAdapter.setActiveResumingMode(true);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void onPause(@NonNull LifecycleOwner lifecycleOwner) {
        // ActiveResumingMode is required for Multi-window which is supported since Android 7(N).
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mCameraUseCaseAdapter.setActiveResumingMode(false);
        }
    }


    /**
     * Suspend the camera so that it ignore lifecycle events.
     *
     * <p> This will also close the {@link CameraUseCaseAdapter}.
     *
     * <p> This will be idempotent if the camera is already suspended.
     */
    public void suspend() {
        synchronized (mLock) {
            if (mSuspended) {
                return;
            }

            onStop(mLifecycleOwner);
            mSuspended = true;
        }
    }

    /**
     * Unsuspend the camera so it will start listening to lifecycle events.
     *
     * <p> This will also open the {@link CameraUseCaseAdapter} if the lifecycle is in a STARTED
     * state or above.
     *
     * <p> This will be idempotent if the camera is already in an unsuspended state.
     */
    public void unsuspend() {
        synchronized (mLock) {
            if (!mSuspended) {
                return;
            }

            mSuspended = false;
            if (mLifecycleOwner.getLifecycle().getCurrentState().isAtLeast(State.STARTED)) {
                onStart(mLifecycleOwner);
            }
        }
    }

    // TODO(b/154939118) remove when Extension.setExtension() is implemented since there no
    //  longer is a need to check if the camera is active.
    public boolean isActive() {
        synchronized (mLock) {
            return mIsActive;
        }
    }

    public boolean isBound(@NonNull UseCase useCase) {
        synchronized (mLock) {
            return mCameraUseCaseAdapter.getUseCases().contains(useCase);
        }
    }

    @NonNull
    public List<UseCase> getUseCases() {
        synchronized (mLock) {
            return Collections.unmodifiableList(mCameraUseCaseAdapter.getUseCases());
        }
    }

    /**
     * Retrieves the lifecycle owner.
     */
    @NonNull
    public LifecycleOwner getLifecycleOwner() {
        synchronized (mLock) {
            return mLifecycleOwner;
        }
    }

    @NonNull
    public CameraUseCaseAdapter getCameraUseCaseAdapter() {
        return mCameraUseCaseAdapter;
    }

    /**
     * Bind the UseCases to the lifecycle camera.
     *
     * <>This will attach the UseCases to the CameraUseCaseAdapter if successful.
     *
     * @throws CameraUseCaseAdapter.CameraException if unable to attach the UseCase to the camera.
     */
    void bind(Collection<UseCase> useCases) throws CameraUseCaseAdapter.CameraException {
        synchronized (mLock) {
            mCameraUseCaseAdapter.addUseCases(useCases);
        }
    }

    /**
     * Unbind the UseCases from the lifecycle camera.
     *
     * <>This will detach the UseCases from the CameraUseCaseAdapter.
     */
    void unbind(Collection<UseCase> useCases) {
        synchronized (mLock) {
            List<UseCase> useCasesToRemove = new ArrayList<>(useCases);
            useCasesToRemove.retainAll(mCameraUseCaseAdapter.getUseCases());
            mCameraUseCaseAdapter.removeUseCases(useCasesToRemove);
        }
    }

    /**
     * Unbind all of the UseCases from the lifecycle camera.
     *
     * <p>This will detach all UseCases from the CameraUseCaseAdapter.
     */
    void unbindAll() {
        synchronized (mLock) {
            mCameraUseCaseAdapter.removeUseCases(mCameraUseCaseAdapter.getUseCases());
        }
    }

    /**
     * Stops observing lifecycle changes.
     *
     * <p>Once released the wrapped {@link LifecycleCamera} is still valid, but will no longer be
     * triggered by lifecycle state transitions. In order to observe lifecycle changes again a new
     * {@link LifecycleCamera} instance should be created.
     *
     * <p>Calls subsequent to the first time will do nothing.
     */
    void release() {
        synchronized (mLock) {
            mReleased = true;
            mIsActive = false;
            mLifecycleOwner.getLifecycle().removeObserver(this);
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // Camera interface
    ////////////////////////////////////////////////////////////////////////////////////////////////
    @NonNull
    @Override
    public CameraControl getCameraControl() {
        return mCameraUseCaseAdapter.getCameraControl();
    }

    @NonNull
    @Override
    public CameraInfo getCameraInfo() {
        return mCameraUseCaseAdapter.getCameraInfo();
    }

    @Nullable
    CameraInfo getSecondaryCameraInfo() {
        return mCameraUseCaseAdapter.getSecondaryCameraInfo();
    }

    @NonNull
    @Override
    public CameraConfig getExtendedConfig() {
        return mCameraUseCaseAdapter.getExtendedConfig();
    }

    @Override
    public boolean isUseCasesCombinationSupported(boolean withStreamSharing,
            @NonNull UseCase... useCases) {
        return mCameraUseCaseAdapter.isUseCasesCombinationSupported(withStreamSharing, useCases);
    }
}