OSDN Git Service

Fix bug in counting open images
authorPuneet Lall <puneetl@google.com>
Fri, 30 Jan 2015 03:09:30 +0000 (19:09 -0800)
committerPuneet Lall <puneetl@google.com>
Fri, 30 Jan 2015 17:41:45 +0000 (09:41 -0800)
Bug: 19156045

AndroidImageReaderProxy previously would return an instance of itself
via onImageAvailable.  This caused a problem because it bypassed the
LoggingImageReaderProxy and CloseWhenDoneImageReaderProxy decorators.

This change also includes additional minor fixes for potential issues,
specifically, it also synchronizes access to each android.media.Image
and ImageReader because they are not thread-safe.

Change-Id: I0d76c07ae37b09cdec40f7d7789b49f7397fb414

15 files changed:
src/com/android/camera/debug/Loggers.java
src/com/android/camera/one/v2/CloseWhenDoneImageReader.java
src/com/android/camera/one/v2/LoggingImageReader.java
src/com/android/camera/one/v2/SimpleOneCameraFactory.java
src/com/android/camera/one/v2/ZslOneCameraFactory.java
src/com/android/camera/one/v2/camera2proxy/AndroidImageProxy.java
src/com/android/camera/one/v2/camera2proxy/AndroidImageReaderProxy.java
src/com/android/camera/one/v2/camera2proxy/ForwardingImageProxy.java
src/com/android/camera/one/v2/camera2proxy/ImageProxy.java
src/com/android/camera/one/v2/camera2proxy/ImageReaderProxy.java
src/com/android/camera/one/v2/sharedimagereader/imagedistributor/ImageDistributorFactory.java
src/com/android/camera/one/v2/sharedimagereader/imagedistributor/ImageDistributorOnImageAvailableListener.java
src/com/android/camera/one/v2/sharedimagereader/imagedistributor/RefCountedImageProxy.java
src/com/android/camera/one/v2/sharedimagereader/metadatasynchronizer/MetadataReleasingImageQueue.java
src/com/android/camera/one/v2/sharedimagereader/util/TicketImageProxy.java

index 6c32ba8..9d594e3 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.camera.debug;
 
 import com.android.camera.debug.Log.Tag;
+import com.google.common.annotations.VisibleForTesting;
 
 import javax.annotation.ParametersAreNonnullByDefault;
 
@@ -33,14 +34,26 @@ public class Loggers {
     }
 
     /**
-     * This creates a factory that will use the standard android
-     * static log methods.
+     * This creates a factory that will use the standard android static log
+     * methods.
      */
     public static Logger.Factory tagFactory() {
         return TagLoggerFactory.instance();
     }
 
     /**
+     * Creates a logger factory which always returns the given logger.
+     */
+    public static Logger.Factory factoryFor(final Logger logger) {
+        return new Logger.Factory() {
+            @Override
+            public Logger create(Tag tag) {
+                return logger;
+            }
+        };
+    }
+
+    /**
      * Creates loggers that eat all input and does nothing.
      */
     private static class NoOpLoggerFactory implements Logger.Factory {
@@ -48,7 +61,9 @@ public class Loggers {
             private static final NoOpLoggerFactory INSTANCE = new NoOpLoggerFactory();
         }
 
-        public static NoOpLoggerFactory instance() { return Singleton.INSTANCE; }
+        public static NoOpLoggerFactory instance() {
+            return Singleton.INSTANCE;
+        }
 
         private final NoOpLogger mNoOpLogger;
 
@@ -63,15 +78,17 @@ public class Loggers {
     }
 
     /**
-     * Creates loggers that use tag objects to write to standard
-     * android log output.
+     * Creates loggers that use tag objects to write to standard android log
+     * output.
      */
     private static class TagLoggerFactory implements Logger.Factory {
         private static class Singleton {
             private static final TagLoggerFactory INSTANCE = new TagLoggerFactory();
         }
 
-        public static TagLoggerFactory instance() { return Singleton.INSTANCE; }
+        public static TagLoggerFactory instance() {
+            return Singleton.INSTANCE;
+        }
 
         @Override
         public Logger create(Tag tag) {
@@ -84,39 +101,49 @@ public class Loggers {
      */
     private static class NoOpLogger implements Logger {
         @Override
-        public void d(String msg) { }
+        public void d(String msg) {
+        }
 
         @Override
-        public void d(String msg, Throwable tr) { }
+        public void d(String msg, Throwable tr) {
+        }
 
         @Override
-        public void e(String msg) { }
+        public void e(String msg) {
+        }
 
         @Override
-        public void e(String msg, Throwable tr) { }
+        public void e(String msg, Throwable tr) {
+        }
 
         @Override
-        public void i(String msg) { }
+        public void i(String msg) {
+        }
 
         @Override
-        public void i(String msg, Throwable tr) { }
+        public void i(String msg, Throwable tr) {
+        }
 
         @Override
-        public void v(String msg) { }
+        public void v(String msg) {
+        }
 
         @Override
-        public void v(String msg, Throwable tr) { }
+        public void v(String msg, Throwable tr) {
+        }
 
         @Override
-        public void w(String msg) { }
+        public void w(String msg) {
+        }
 
         @Override
-        public void w(String msg, Throwable tr) { }
+        public void w(String msg, Throwable tr) {
+        }
     }
 
     /**
-     * TagLogger logger writes to the standard static log output with the
-     * given tag object.
+     * TagLogger logger writes to the standard static log output with the given
+     * tag object.
      */
     private static class TagLogger implements Logger {
         private final Log.Tag mTag;
@@ -175,4 +202,4 @@ public class Loggers {
             Log.w(mTag, msg, tr);
         }
     }
-}
\ No newline at end of file
+}
index 89e2169..efaedc6 100644 (file)
@@ -55,6 +55,8 @@ public final class CloseWhenDoneImageReader extends ForwardingImageReader implem
 
     private final Object mLock;
     @GuardedBy("mLock")
+    private boolean mClosePending;
+    @GuardedBy("mLock")
     private boolean mClosed;
     @GuardedBy("mLock")
     private int mOpenImages;
@@ -69,7 +71,8 @@ public final class CloseWhenDoneImageReader extends ForwardingImageReader implem
     private void decrementImageCount() {
         synchronized (mLock) {
             mOpenImages--;
-            if (mClosed && mOpenImages == 0) {
+            if (mClosePending && !mClosed && mOpenImages == 0) {
+                mClosed = true;
                 super.close();
             }
         }
@@ -79,7 +82,7 @@ public final class CloseWhenDoneImageReader extends ForwardingImageReader implem
     @Nullable
     public ImageProxy acquireNextImage() {
         synchronized (mLock) {
-            if (!mClosed) {
+            if (!mClosePending && !mClosed) {
                 ImageProxy image = super.acquireNextImage();
                 if (image != null) {
                     mOpenImages++;
@@ -94,7 +97,7 @@ public final class CloseWhenDoneImageReader extends ForwardingImageReader implem
     @Nullable
     public ImageProxy acquireLatestImage() {
         synchronized (mLock) {
-            if (!mClosed) {
+            if (!mClosePending && !mClosed) {
                 ImageProxy image = super.acquireLatestImage();
                 if (image != null) {
                     mOpenImages++;
@@ -108,8 +111,12 @@ public final class CloseWhenDoneImageReader extends ForwardingImageReader implem
     @Override
     public void close() {
         synchronized (mLock) {
-            mClosed = true;
+            if (mClosed || mClosePending) {
+                return;
+            }
+            mClosePending = true;
             if (mOpenImages == 0) {
+                mClosed = true;
                 super.close();
             }
         }
index e806dbb..9aeb3d6 100644 (file)
@@ -18,43 +18,43 @@ package com.android.camera.one.v2;
 
 import com.android.camera.debug.Log.Tag;
 import com.android.camera.debug.Logger;
-import com.android.camera.debug.Loggers;
 import com.android.camera.one.v2.camera2proxy.ForwardingImageProxy;
 import com.android.camera.one.v2.camera2proxy.ForwardingImageReader;
 import com.android.camera.one.v2.camera2proxy.ImageProxy;
 import com.android.camera.one.v2.camera2proxy.ImageReaderProxy;
 
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.annotation.Nullable;
 
 final class LoggingImageReader extends ForwardingImageReader {
-    private static Tag TAG = new Tag("LoggingImageReader");
-
     private class LoggingImageProxy extends ForwardingImageProxy {
+        private final AtomicBoolean mClosed;
+
         public LoggingImageProxy(ImageProxy proxy) {
             super(proxy);
+            mClosed = new AtomicBoolean(false);
         }
 
         @Override
         public void close() {
-            super.close();
-            decrementOpenImageCount();
+            if (!mClosed.getAndSet(true)) {
+                super.close();
+                decrementOpenImageCount();
+            }
         }
     }
-    private final Logger mLogger;
+
+    private final Logger mLog;
     private final AtomicInteger mNumOpenImages;
 
-    LoggingImageReader(ImageReaderProxy delegate, Logger.Factory logFactory) {
+    public LoggingImageReader(ImageReaderProxy delegate, Logger.Factory logFactory) {
         super(delegate);
-        mLogger = logFactory.create(TAG);
+        mLog = logFactory.create(new Tag("LoggingImageReader"));
         mNumOpenImages = new AtomicInteger(0);
     }
 
-    public static LoggingImageReader create(ImageReaderProxy imageReader) {
-        return new LoggingImageReader(imageReader, Loggers.tagFactory());
-    }
-
     @Override
     @Nullable
     public ImageProxy acquireNextImage() {
@@ -78,20 +78,19 @@ final class LoggingImageReader extends ForwardingImageReader {
 
     @Override
     public void close() {
-        mLogger.d("Closing: " + toString());
+        mLog.d("Closing: " + toString());
         super.close();
     }
 
     private void incrementOpenImageCount() {
         int numOpenImages = mNumOpenImages.incrementAndGet();
         if (numOpenImages >= getMaxImages()) {
-            mLogger.e(String.format("Open Image Count (%d) exceeds maximum (%d)!",
+            mLog.e(String.format("Open Image Count (%d) exceeds maximum (%d)!",
                     numOpenImages, getMaxImages()));
         }
     }
 
     private void decrementOpenImageCount() {
         int numOpenImages = mNumOpenImages.decrementAndGet();
-        mLogger.v("Open Image Count = " + numOpenImages);
     }
 }
index 27ae44a..a31e34c 100644 (file)
@@ -27,6 +27,7 @@ import com.android.camera.async.Lifetime;
 import com.android.camera.async.MainThread;
 import com.android.camera.async.Observable;
 import com.android.camera.async.Updatable;
+import com.android.camera.debug.Loggers;
 import com.android.camera.one.OneCamera;
 import com.android.camera.one.OneCameraCharacteristics;
 import com.android.camera.one.v2.camera2proxy.AndroidImageReaderProxy;
@@ -84,10 +85,12 @@ public class SimpleOneCameraFactory implements OneCameraFactory {
             final Observable<OneCamera.PhotoCaptureParameters.Flash> flashSetting) {
         Lifetime lifetime = new Lifetime();
 
-        final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(
-                LoggingImageReader.create(
-                        AndroidImageReaderProxy.newInstance(pictureSize.getWidth(),
-                                pictureSize.getHeight(), mImageFormat, mMaxImageCount)));
+        final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(new LoggingImageReader(
+                AndroidImageReaderProxy.newInstance(
+                        pictureSize.getWidth(), pictureSize.getHeight(),
+                        mImageFormat, mMaxImageCount),
+                Loggers.tagFactory()));
+
         lifetime.add(imageReader);
 
         List<Surface> outputSurfaces = new ArrayList<>();
index d30da02..12894fa 100644 (file)
@@ -102,9 +102,9 @@ public class ZslOneCameraFactory implements OneCameraFactory {
         Lifetime lifetime = new Lifetime();
 
         final ImageReaderProxy imageReader = new CloseWhenDoneImageReader(
-                LoggingImageReader.create(AndroidImageReaderProxy.newInstance(
+                new LoggingImageReader(AndroidImageReaderProxy.newInstance(
                         pictureSize.getWidth(), pictureSize.getHeight(),
-                        mImageFormat, mMaxImageCount)));
+                        mImageFormat, mMaxImageCount), Loggers.tagFactory()));
 
         lifetime.add(imageReader);
         lifetime.add(device);
index 805950d..ccca98d 100644 (file)
@@ -25,9 +25,13 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.annotation.concurrent.GuardedBy;
+import javax.annotation.concurrent.ThreadSafe;
+
 /**
  * An {@link ImageProxy} backed by an {@link android.media.Image}.
  */
+@ThreadSafe
 public class AndroidImageProxy implements ImageProxy {
 
     /**
@@ -35,6 +39,12 @@ public class AndroidImageProxy implements ImageProxy {
      * {@link android.media.Image.Plane}.
      */
     public class Plane implements ImageProxy.Plane {
+        /**
+         * {@link android.media.Image} is not thread-safe, and the resulting
+         * {@link Image.Plane} objects are not-necessarily thread-safe either,
+         * so all interaction must be guarded by {@link #mLock}.
+         */
+        @GuardedBy("mLock")
         private final Image.Plane mPlane;
 
         public Plane(Image.Plane imagePlane) {
@@ -46,7 +56,9 @@ public class AndroidImageProxy implements ImageProxy {
          */
         @Override
         public int getRowStride() {
-            return mPlane.getRowStride();
+            synchronized (mLock) {
+                return mPlane.getRowStride();
+            }
         }
 
         /**
@@ -54,7 +66,9 @@ public class AndroidImageProxy implements ImageProxy {
          */
         @Override
         public int getPixelStride() {
-            return mPlane.getPixelStride();
+            synchronized (mLock) {
+                return mPlane.getPixelStride();
+            }
         }
 
         /**
@@ -62,14 +76,23 @@ public class AndroidImageProxy implements ImageProxy {
          */
         @Override
         public ByteBuffer getBuffer() {
-            return mPlane.getBuffer();
+            synchronized (mLock) {
+                return mPlane.getBuffer();
+            }
         }
 
     }
 
+    private final Object mLock;
+    /**
+     * {@link android.media.Image} is not thread-safe, so all interactions must
+     * be guarded by {@link #mLock}.
+     */
+    @GuardedBy("mLock")
     private final android.media.Image mImage;
 
     public AndroidImageProxy(android.media.Image image) {
+        mLock = new Object();
         mImage = image;
     }
 
@@ -78,7 +101,9 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public Rect getCropRect() {
-        return mImage.getCropRect();
+        synchronized (mLock) {
+            return mImage.getCropRect();
+        }
     }
 
     /**
@@ -86,7 +111,9 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public void setCropRect(Rect cropRect) {
-        mImage.setCropRect(cropRect);
+        synchronized (mLock) {
+            mImage.setCropRect(cropRect);
+        }
     }
 
     /**
@@ -94,7 +121,9 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public int getFormat() {
-        return mImage.getFormat();
+        synchronized (mLock) {
+            return mImage.getFormat();
+        }
     }
 
     /**
@@ -102,7 +131,9 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public int getHeight() {
-        return mImage.getHeight();
+        synchronized (mLock) {
+            return mImage.getHeight();
+        }
     }
 
     /**
@@ -117,11 +148,16 @@ public class AndroidImageProxy implements ImageProxy {
      * object needs to be. So, just consider the performance when using this
      * function wrapper.
      * </p>
+     *
      * @see {@link android.media.Image#getPlanes}
      */
     @Override
     public List<ImageProxy.Plane> getPlanes() {
-        Image.Plane[] planes = mImage.getPlanes();
+        Image.Plane[] planes;
+
+        synchronized (mLock) {
+            planes = mImage.getPlanes();
+        }
 
         List<ImageProxy.Plane> wrappedPlanes = new ArrayList<>(planes.length);
 
@@ -136,7 +172,9 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public long getTimestamp() {
-        return mImage.getTimestamp();
+        synchronized (mLock) {
+            return mImage.getTimestamp();
+        }
     }
 
     /**
@@ -144,7 +182,9 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public int getWidth() {
-        return mImage.getWidth();
+        synchronized (mLock) {
+            return mImage.getWidth();
+        }
     }
 
     /**
@@ -152,13 +192,19 @@ public class AndroidImageProxy implements ImageProxy {
      */
     @Override
     public void close() {
-        mImage.close();
+        synchronized (mLock) {
+            mImage.close();
+        }
     }
 
     @Override
     public String toString() {
-        return Objects.toStringHelper(mImage)
-                .add("timestamp", getTimestamp())
+        Objects.ToStringHelper tsh;
+
+        synchronized (mImage) {
+            tsh = Objects.toStringHelper(mImage);
+        }
+        return tsh.add("timestamp", getTimestamp())
                 .toString();
     }
 }
index 8877ccc..8a59c83 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.camera.one.v2.camera2proxy;
 
 import android.graphics.ImageFormat;
+import android.media.Image;
 import android.os.Handler;
 import android.view.Surface;
 
@@ -24,14 +25,18 @@ import com.google.common.base.Objects;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.annotation.concurrent.GuardedBy;
 
 /**
  * A replacement for {@link android.media.ImageReader}.
  */
 public final class AndroidImageReaderProxy implements ImageReaderProxy {
+    private final Object mLock;
+    @GuardedBy("mLock")
     private final android.media.ImageReader mDelegate;
 
     public AndroidImageReaderProxy(android.media.ImageReader delegate) {
+        mLock = new Object();
         mDelegate = delegate;
     }
 
@@ -71,64 +76,95 @@ public final class AndroidImageReaderProxy implements ImageReaderProxy {
 
     @Override
     public int getWidth() {
-        return mDelegate.getWidth();
+        synchronized (mLock) {
+            return mDelegate.getWidth();
+        }
     }
 
     @Override
     public int getHeight() {
-        return mDelegate.getHeight();
+        synchronized (mLock) {
+            return mDelegate.getHeight();
+        }
     }
 
     @Override
     public int getImageFormat() {
-        return mDelegate.getImageFormat();
+        synchronized (mLock) {
+            return mDelegate.getImageFormat();
+        }
     }
 
     @Override
     public int getMaxImages() {
-        return mDelegate.getMaxImages();
+        synchronized (mLock) {
+            return mDelegate.getMaxImages();
+        }
     }
 
     @Override
     @Nonnull
     public Surface getSurface() {
-        return mDelegate.getSurface();
+        synchronized (mLock) {
+            return mDelegate.getSurface();
+        }
     }
 
     @Override
     @Nullable
     public ImageProxy acquireLatestImage() {
-        return new AndroidImageProxy(mDelegate.acquireLatestImage());
+        synchronized (mLock) {
+            Image image = mDelegate.acquireLatestImage();
+            if (image == null) {
+                return null;
+            } else {
+                return new AndroidImageProxy(image);
+            }
+        }
     }
 
     @Override
     @Nullable
     public ImageProxy acquireNextImage() {
-        return new AndroidImageProxy(mDelegate.acquireNextImage());
+        synchronized (mLock) {
+            Image image = mDelegate.acquireNextImage();
+            if (image == null) {
+                return null;
+            } else {
+                return new AndroidImageProxy(image);
+            }
+        }
     }
 
     @Override
     public void setOnImageAvailableListener(@Nonnull
     final ImageReaderProxy.OnImageAvailableListener listener,
             Handler handler) {
-        mDelegate.setOnImageAvailableListener(
-                new android.media.ImageReader.OnImageAvailableListener() {
-                    @Override
-                    public void onImageAvailable(android.media.ImageReader imageReader) {
-                        listener.onImageAvailable(AndroidImageReaderProxy.this);
-                    }
-                }, handler);
+        synchronized (mLock) {
+            mDelegate.setOnImageAvailableListener(
+                    new android.media.ImageReader.OnImageAvailableListener() {
+                        @Override
+                        public void onImageAvailable(android.media.ImageReader imageReader) {
+                            listener.onImageAvailable();
+                        }
+                    }, handler);
+        }
     }
 
     @Override
     public void close() {
-        mDelegate.close();
+        synchronized (mLock) {
+            mDelegate.close();
+        }
     }
 
     @Override
     public String toString() {
-        return Objects.toStringHelper(mDelegate)
-                .add("width", getWidth())
+        Objects.ToStringHelper tsh;
+        synchronized (mLock) {
+            tsh = Objects.toStringHelper(mDelegate);
+        }
+        return tsh.add("width", getWidth())
                 .add("height", getHeight())
                 .add("format", imageFormatToString(getImageFormat()))
                 .toString();
index 675b05f..16d9ad0 100644 (file)
@@ -20,9 +20,12 @@ import android.graphics.Rect;
 
 import java.util.List;
 
+import javax.annotation.concurrent.ThreadSafe;
+
 /**
  * Forwards all {@link ImageProxy} methods.
  */
+@ThreadSafe
 public abstract class ForwardingImageProxy implements ImageProxy {
     private final ImageProxy mImpl;
 
index 27470c3..694813c 100644 (file)
 package com.android.camera.one.v2.camera2proxy;
 
 import android.graphics.Rect;
-import android.media.Image;
 
 import com.android.camera.async.SafeCloseable;
 
 import java.nio.ByteBuffer;
 import java.util.List;
 
+import javax.annotation.concurrent.ThreadSafe;
+
 /**
  * Wraps {@link android.media.Image} with a mockable interface.
+ * <p>
+ * Implementations must be thread-safe.
  */
+@ThreadSafe
 public interface ImageProxy extends SafeCloseable {
 
     /**
-     * Wraps the inner class {@link android.media.Image} with a mockable interface.
+     * Wraps the inner class {@link android.media.Image} with a mockable
+     * interface.
      */
     public interface Plane {
 
index d7f36cd..36aa7da 100644 (file)
@@ -38,7 +38,7 @@ public interface ImageReaderProxy extends SafeCloseable {
         /**
          * See {@link ImageReader.OnImageAvailableListener#onImageAvailable}
          */
-        public void onImageAvailable(@Nonnull ImageReaderProxy imageReader);
+        public void onImageAvailable();
     }
 
     /**
index 02ae351..86c4e6e 100644 (file)
@@ -46,7 +46,7 @@ public class ImageDistributorFactory {
         Handler imageReaderHandler = handlerFactory.create(lifetime, "ImageDistributor");
 
         imageReader.setOnImageAvailableListener(
-                new ImageDistributorOnImageAvailableListener(mImageDistributor),
+                new ImageDistributorOnImageAvailableListener(imageReader, mImageDistributor),
                 imageReaderHandler);
     }
 
index 3bbfbd4..8b1ea58 100644 (file)
 
 package com.android.camera.one.v2.sharedimagereader.imagedistributor;
 
-import com.android.camera.debug.Log;
-import com.android.camera.one.v2.camera2proxy.ForwardingImageProxy;
 import com.android.camera.one.v2.camera2proxy.ImageProxy;
 import com.android.camera.one.v2.camera2proxy.ImageReaderProxy;
 
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNonnullByDefault;
 
 /**
- * Connects an {@link ImageReaderProxy} to an {@link ImageDistributor} with a new
- * thread to handle image availability callbacks.
+ * Connects an {@link ImageReaderProxy} to an {@link ImageDistributor} with a
+ * new thread to handle image availability callbacks.
  */
 @ParametersAreNonnullByDefault
 class ImageDistributorOnImageAvailableListener implements
         ImageReaderProxy.OnImageAvailableListener {
     private final ImageDistributorImpl mImageDistributor;
+    private final ImageReaderProxy mImageReader;
 
     /**
+     * @param imageReader The image reader to retrieve images from.
      * @param imageDistributor The image distributor to send images to.
      */
-    public ImageDistributorOnImageAvailableListener(ImageDistributorImpl imageDistributor) {
+    public ImageDistributorOnImageAvailableListener(ImageReaderProxy imageReader,
+            ImageDistributorImpl imageDistributor) {
         mImageDistributor = imageDistributor;
+        mImageReader = imageReader;
     }
 
     @Override
-    public void onImageAvailable(@Nonnull ImageReaderProxy imageReader) {
-        ImageProxy nextImage = imageReader.acquireNextImage();
+    public void onImageAvailable() {
+        ImageProxy nextImage = mImageReader.acquireNextImage();
         if (nextImage != null) {
             mImageDistributor.distributeImage(new SingleCloseImageProxy(nextImage));
         }
index 03e53f3..40f6b60 100644 (file)
@@ -20,10 +20,13 @@ import com.android.camera.async.RefCountBase;
 import com.android.camera.one.v2.camera2proxy.ForwardingImageProxy;
 import com.android.camera.one.v2.camera2proxy.ImageProxy;
 
+import javax.annotation.concurrent.ThreadSafe;
+
 /**
  * Wraps ImageProxy with reference counting, starting with a fixed number of
  * references.
  */
+@ThreadSafe
 class RefCountedImageProxy extends ForwardingImageProxy {
     private final RefCountBase<ImageProxy> mRefCount;
 
index 30613e2..9225b8a 100644 (file)
@@ -22,12 +22,14 @@ import com.android.camera.one.v2.camera2proxy.ImageProxy;
 
 import javax.annotation.Nonnull;
 import javax.annotation.ParametersAreNonnullByDefault;
+import javax.annotation.concurrent.ThreadSafe;
 
 /**
  * Wraps an output queue of images by wrapping each image to track when they are
  * closed. When images are closed, their associated metadata entry is freed to
  * not leak memory.
  */
+@ThreadSafe
 @ParametersAreNonnullByDefault
 public class MetadataReleasingImageQueue implements BufferQueueController<ImageProxy> {
     private class MetadataReleasingImageProxy extends ForwardingImageProxy {
index 1db24dc..328d5c6 100644 (file)
@@ -22,9 +22,12 @@ import com.android.camera.one.v2.sharedimagereader.ticketpool.Ticket;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import javax.annotation.concurrent.ThreadSafe;
+
 /**
  * Combines an {@link ImageProxy} with a {@link Ticket}.
  */
+@ThreadSafe
 public class TicketImageProxy extends ForwardingImageProxy {
     private final Ticket mTicket;
     private final AtomicBoolean mClosed;