public class

SafeCloseImageReaderProxy

extends java.lang.Object

implements ImageReaderProxy

 java.lang.Object

↳androidx.camera.core.SafeCloseImageReaderProxy

Gradle dependencies

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

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

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

Overview

An ImageReaderProxy that wraps another ImageReaderProxy to safely wait until all produced ImageProxy are closed before closing the ImageReaderProxy.

Summary

Constructors
publicSafeCloseImageReaderProxy(ImageReaderProxy imageReaderProxy)

Methods
public ImageProxyacquireLatestImage()

public ImageProxyacquireNextImage()

public voidclearOnImageAvailableListener()

public voidclose()

public intgetCapacity()

Returns the number of empty slots in the queue.

public intgetHeight()

public intgetImageFormat()

public ImageReaderProxygetImageReaderProxy()

Returns the underlying ImageReaderProxy for testing.

public intgetMaxImages()

public SurfacegetSurface()

public intgetWidth()

public booleanisClosed()

Check if the SafeCloseImageReaderProxy is closed for testing.

public voidsafeClose()

Close the underlying ImageReaderProxy safely by deferring the close until the last ImageProxy has been closed.

public voidsetOnImageAvailableListener(ImageReaderProxy.OnImageAvailableListener listener, java.util.concurrent.Executor executor)

public voidsetOnImageCloseListener(ForwardingImageProxy.OnImageCloseListener listener)

Sets a listener for close calls on this image.

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

Constructors

public SafeCloseImageReaderProxy(ImageReaderProxy imageReaderProxy)

Methods

public ImageProxy acquireLatestImage()

public ImageProxy acquireNextImage()

public void close()

public void safeClose()

Close the underlying ImageReaderProxy safely by deferring the close until the last ImageProxy has been closed.

Once this has been called, no more additional ImageProxy can be acquired from the SafeCloseImageReaderProxy.

public boolean isClosed()

Check if the SafeCloseImageReaderProxy is closed for testing.

public int getCapacity()

Returns the number of empty slots in the queue.

public void setOnImageCloseListener(ForwardingImageProxy.OnImageCloseListener listener)

Sets a listener for close calls on this image.

Parameters:

listener: to set

public int getHeight()

public int getWidth()

public int getImageFormat()

public int getMaxImages()

public Surface getSurface()

public void setOnImageAvailableListener(ImageReaderProxy.OnImageAvailableListener listener, java.util.concurrent.Executor executor)

public void clearOnImageAvailableListener()

public ImageReaderProxy getImageReaderProxy()

Returns the underlying ImageReaderProxy for testing.

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.core;

import android.view.Surface;

import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.VisibleForTesting;
import androidx.camera.core.ForwardingImageProxy.OnImageCloseListener;
import androidx.camera.core.impl.ImageReaderProxy;

import java.util.concurrent.Executor;

/**
 * An {@link ImageReaderProxy} that wraps another ImageReaderProxy to safely wait until all
 * produced {@link ImageProxy} are closed before closing the ImageReaderProxy.
 *
 */
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public class SafeCloseImageReaderProxy implements ImageReaderProxy {
    // Lock to synchronize acquired ImageProxys and close.
    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private int mOutstandingImages = 0;
    @GuardedBy("mLock")
    private boolean mIsClosed = false;

    // The wrapped instance of ImageReaderProxy
    @GuardedBy("mLock")
    private final ImageReaderProxy mImageReaderProxy;

    @Nullable
    private final Surface mSurface;
    private OnImageCloseListener mForwardingImageCloseListener;

    // Called after images are closed to check if the ImageReaderProxy should be closed
    private final OnImageCloseListener mImageCloseListener = (image) -> {
        OnImageCloseListener forwardingListener;
        synchronized (mLock) {
            mOutstandingImages--;
            if (mIsClosed && mOutstandingImages == 0) {
                close();
            }
            forwardingListener = mForwardingImageCloseListener;
        }
        if (forwardingListener != null) {
            forwardingListener.onImageClose(image);
        }
    };

    public SafeCloseImageReaderProxy(@NonNull ImageReaderProxy imageReaderProxy) {
        mImageReaderProxy = imageReaderProxy;
        mSurface = imageReaderProxy.getSurface();
    }

    @Nullable
    @Override
    public ImageProxy acquireLatestImage() {
        synchronized (mLock) {
            return wrapImageProxy(mImageReaderProxy.acquireLatestImage());
        }
    }

    @Nullable
    @Override
    public ImageProxy acquireNextImage() {
        synchronized (mLock) {
            return wrapImageProxy(mImageReaderProxy.acquireNextImage());
        }
    }

    /**
     * @inheritDoc <p>This will directly close the wrapped {@link ImageReaderProxy} without
     * waiting for
     * outstanding {@link ImageProxy} to be closed. Typically, when using {@link
     * SafeCloseImageReaderProxy} this should not be directly called. Instead call {@link
     * #safeClose()} which safely waits for all ImageProxy to close before closing the wrapped
     * ImageReaderProxy.
     */
    @Override
    public void close() {
        synchronized (mLock) {
            if (mSurface != null) {
                mSurface.release();
            }
            mImageReaderProxy.close();
        }
    }

    @GuardedBy("mLock")
    @Nullable
    private ImageProxy wrapImageProxy(@Nullable ImageProxy imageProxy) {
        if (imageProxy != null) {
            mOutstandingImages++;
            SingleCloseImageProxy singleCloseImageProxy =
                    new SingleCloseImageProxy(imageProxy);
            singleCloseImageProxy.addOnImageCloseListener(mImageCloseListener);
            return singleCloseImageProxy;
        } else {
            return null;
        }
    }

    /**
     * Close the underlying {@link ImageReaderProxy} safely by deferring the close until the last
     * {@link ImageProxy} has been closed.
     *
     * <p>Once this has been called, no more additional ImageProxy can be acquired from the
     * {@link SafeCloseImageReaderProxy}.
     */
    public void safeClose() {
        synchronized (mLock) {
            mIsClosed = true;
            mImageReaderProxy.clearOnImageAvailableListener();

            if (mOutstandingImages == 0) {
                close();
            }
        }
    }

    /**
     * Check if the {@link SafeCloseImageReaderProxy} is closed for testing.
     */
    @VisibleForTesting
    public boolean isClosed() {
        synchronized (mLock) {
            return mIsClosed;
        }
    }

    /**
     * Returns the number of empty slots in the queue.
     */
    public int getCapacity() {
        synchronized (mLock) {
            return mImageReaderProxy.getMaxImages() - mOutstandingImages;
        }
    }

    /**
     * Sets a listener for close calls on this image.
     *
     * @param listener to set
     */
    public void setOnImageCloseListener(@NonNull OnImageCloseListener listener) {
        synchronized (mLock) {
            mForwardingImageCloseListener = listener;
        }
    }

    @Override
    public int getHeight() {
        synchronized (mLock) {
            return mImageReaderProxy.getHeight();
        }
    }

    @Override
    public int getWidth() {
        synchronized (mLock) {
            return mImageReaderProxy.getWidth();
        }
    }

    @Override
    public int getImageFormat() {
        synchronized (mLock) {
            return mImageReaderProxy.getImageFormat();
        }
    }

    @Override
    public int getMaxImages() {
        synchronized (mLock) {
            return mImageReaderProxy.getMaxImages();
        }
    }

    @Nullable
    @Override
    public Surface getSurface() {
        synchronized (mLock) {
            return mImageReaderProxy.getSurface();
        }
    }

    @Override
    public void setOnImageAvailableListener(@NonNull OnImageAvailableListener listener,
            @NonNull Executor executor) {
        synchronized (mLock) {
            mImageReaderProxy.setOnImageAvailableListener(
                    imageReader -> listener.onImageAvailable(this), executor);
        }
    }

    @Override
    public void clearOnImageAvailableListener() {
        synchronized (mLock) {
            mImageReaderProxy.clearOnImageAvailableListener();
        }
    }

    /**
     * Returns the underlying {@link ImageReaderProxy} for testing.
     */
    @VisibleForTesting
    @NonNull
    public ImageReaderProxy getImageReaderProxy() {
        synchronized (mLock) {
            return mImageReaderProxy;
        }
    }
}