Merge "Interface ImageTaskManager for Image-based Tasks" into ub-camera-haleakala
diff --git a/src/com/android/camera/processing/imagebackend/ImageBackend.java b/src/com/android/camera/processing/imagebackend/ImageBackend.java
index 381f611..3fe1a41 100644
--- a/src/com/android/camera/processing/imagebackend/ImageBackend.java
+++ b/src/com/android/camera/processing/imagebackend/ImageBackend.java
@@ -69,7 +69,7 @@
  * respective task {@link TaskLuckyShotSession} {@link LuckyShotSession}</li>
  * </ol>
  */
-public class ImageBackend implements ImageConsumer {
+public class ImageBackend implements ImageConsumer, ImageTaskManager {
 
     protected static final int FAST_THREAD_PRIORITY = Thread.MAX_PRIORITY;
 
@@ -79,8 +79,6 @@
 
     protected static final int NUM_THREADS_SLOW = 2;
 
-    protected final SimpleCache mSimpleCache;
-
     protected final Map<ImageToProcess, ImageReleaseProtocol> mImageSemaphoreMap;
 
     protected final ExecutorService mThreadPoolFast;
@@ -106,7 +104,6 @@
         mThreadPoolSlow = Executors.newFixedThreadPool(NUM_THREADS_SLOW, new SlowThreadFactory());
         mProxyListener = new ImageProcessorProxyListener();
         mImageSemaphoreMap = new HashMap<>();
-        mSimpleCache = new SimpleCache(NUM_THREADS_SLOW);
     }
 
     /**
@@ -122,7 +119,6 @@
         mThreadPoolSlow = slowService;
         mProxyListener = imageProcessorProxyListener;
         mImageSemaphoreMap = new HashMap<>();
-        mSimpleCache = new SimpleCache(NUM_THREADS_SLOW);
     }
 
     // REMOVE When plumbed properly
@@ -175,20 +171,9 @@
         return mCameraAppUI;
     }
 
-    /**
-     * Simple getter for the simple cache functionality associated with this
-     * instantiation. Needs to be accessed by the tasks in order to get/return
-     * memory. TODO: Replace with something better.
-     *
-     * @return cache object that implements a simple memory pool for this
-     *         object.
-     */
-    public SimpleCache getCache() {
-        return mSimpleCache;
-    }
 
     /**
-     * Simple getting for the associated listener object associated with this
+     * Simple getter for the associated listener object associated with this
      * instantiation that handles registration of events listeners.
      *
      * @return listener proxy that handles events messaging for this object.
@@ -236,6 +221,7 @@
      *            image close is run by the calling thread (usually the main
      *            task thread).
      */
+    @Override
     public void releaseSemaphoreReference(final ImageToProcess img, Executor executor) {
         synchronized (mImageSemaphoreMap) {
             ImageReleaseProtocol protocol = mImageSemaphoreMap.get(img);
@@ -276,16 +262,17 @@
     }
 
     /**
-     * Spawns dependent tasks from internal implementation of a task. If a
-     * dependent task does NOT require the image reference, it should be passed
-     * a null pointer as an image reference. In general, this method should be
-     * called after the task has completed its own computations, but before it
-     * has released its own image reference (via the releaseSemaphoreReference
-     * call).
+     * Spawns dependent tasks from internal implementation of a set of tasks. If
+     * a dependent task does NOT require the image reference, it should be
+     * passed a null pointer as an image reference. In general, this method
+     * should be called after the task has completed its own computations, but
+     * before it has released its own image reference (via the
+     * releaseSemaphoreReference call).
      *
      * @param tasks The set of tasks to be run
      * @return whether tasks are successfully submitted.
      */
+    @Override
     public boolean appendTasks(ImageToProcess img, Set<TaskImageContainer> tasks) {
         // Make sure that referred images are all the same, if it exists.
         // And count how image references need to be kept track of.
@@ -307,6 +294,7 @@
      * @param task The task to be run
      * @return whether tasks are successfully submitted.
      */
+    @Override
     public boolean appendTasks(ImageToProcess img, TaskImageContainer task) {
         Set<TaskImageContainer> tasks = new HashSet<TaskImageContainer>(1);
         tasks.add(task);
@@ -330,11 +318,11 @@
      */
     @Override
     public boolean receiveImage(ImageToProcess img, TaskImageContainer task,
-            boolean blockUntilImageRelease, boolean closeOnImageRelease, CaptureSession session)
+            boolean blockUntilImageRelease, boolean closeOnImageRelease)
             throws InterruptedException {
         Set<TaskImageContainer> passTasks = new HashSet<TaskImageContainer>(1);
         passTasks.add(task);
-        return receiveImage(img, passTasks, blockUntilImageRelease, closeOnImageRelease, session);
+        return receiveImage(img, passTasks, blockUntilImageRelease, closeOnImageRelease);
     }
 
     /**
@@ -355,7 +343,7 @@
      */
     @Override
     public boolean receiveImage(ImageToProcess img, Set<TaskImageContainer> tasks,
-            boolean blockUntilImageRelease, boolean closeOnImageRelease, CaptureSession session)
+            boolean blockUntilImageRelease, boolean closeOnImageRelease)
             throws InterruptedException {
 
         // Short circuit if no tasks submitted.
@@ -435,7 +423,7 @@
 
         receiveImage(img, tasksToExecute,
                 processingFlags.contains(ImageTaskFlags.BLOCK_UNTIL_IMAGE_RELEASE),
-                processingFlags.contains(ImageTaskFlags.CLOSE_IMAGE_ON_RELEASE), session);
+                processingFlags.contains(ImageTaskFlags.CLOSE_IMAGE_ON_RELEASE));
 
         return true;
     }
@@ -515,8 +503,6 @@
      * Increments the semaphore count for the image. Should ONLY be internally
      * via appendTasks by internal tasks. Otherwise, image references could get
      * out of whack.
-     *
-     * @return Number of Image references currently held by this instance
      */
     protected void incrementSemaphoreReferenceCount(ImageToProcess img, int count)
             throws RuntimeException {
@@ -634,10 +620,11 @@
                     // Spin to deal with spurious signals.
                     mSignal.await();
                 }
-                mLock.unlock();
             } catch (InterruptedException e) {
                 // TODO: on interruption, figure out what to do.
                 throw (e);
+            } finally {
+                mLock.unlock();
             }
         }
 
@@ -668,26 +655,4 @@
         }
     }
 
-    // TODO: Remove with a better implementation. Just to avoid
-    // the GC not getting rid of elements. Should be hooked up to properly
-    // implemented memory pool.
-    public class SimpleCache extends ArrayList<byte[]> {
-
-        public SimpleCache(int numEntries) {
-            super(numEntries);
-        }
-
-        public synchronized void cacheSave(byte[] mem) {
-            add(mem);
-        }
-
-        public synchronized byte[] cacheGet() {
-            if (size() < 1) {
-                return null;
-            } else {
-                return mSimpleCache.remove(0);
-            }
-        }
-    }
-
 }
diff --git a/src/com/android/camera/processing/imagebackend/ImageConsumer.java b/src/com/android/camera/processing/imagebackend/ImageConsumer.java
index 8d18acf..16e5235 100644
--- a/src/com/android/camera/processing/imagebackend/ImageConsumer.java
+++ b/src/com/android/camera/processing/imagebackend/ImageConsumer.java
@@ -48,10 +48,10 @@
     /**
      * Provides the basic functionality of camera processing via a more general-
      * purpose method call. Tasks can be extended off of the TaskImageContainer,
-     * or created from factory method provided by implementor.
+     * or created from factory method provided by implementation.
      *
      * @param img The Image to be Processed
-     * @param sharedTask Set of Tasks to be run on the given image
+     * @param sharedTask a single task to be run
      * @param blockOnImageRelease If true, call blocks until the object img is
      *            no longer referred by any task. If false, call is non-blocking
      * @param closeOnImageRelease If true, images is closed when the object img
@@ -60,14 +60,13 @@
      *         need to clean up image closes manually.
      */
     public boolean receiveImage(ImageToProcess img, TaskImageContainer sharedTask,
-            boolean blockOnImageRelease, boolean closeOnImageRelease,
-            CaptureSession captureSession)
+            boolean blockOnImageRelease, boolean closeOnImageRelease)
             throws InterruptedException;
 
     /**
      * Provides the basic functionality of camera processing via a more general-
      * purpose method call. Tasks can be extended off of the TaskImageContainer,
-     * or created from factory method provided by implementor.
+     * or created from factory method provided by the implementation.
      *
      * @param img The Image to be Processed
      * @param sharedTasks Set of tasks to be run on the given image
@@ -80,8 +79,7 @@
      *         need to clean up image closes manually.
      */
     public boolean receiveImage(ImageToProcess img, Set<TaskImageContainer> sharedTasks,
-            boolean blockOnImageRelease, boolean closeOnImageRelease,
-            CaptureSession captureSession)
+            boolean blockOnImageRelease, boolean closeOnImageRelease)
             throws InterruptedException;
 
     /**
@@ -99,7 +97,7 @@
     public void shutdown();
 
     /**
-     * Getter to the object that manages the ListenerEvents. Reigster listeners
+     * Getter to the object that manages the ListenerEvents. Register listeners
      * to this object.
      */
     public ImageProcessorProxyListener getProxyListener();
diff --git a/src/com/android/camera/processing/imagebackend/ImageTaskManager.java b/src/com/android/camera/processing/imagebackend/ImageTaskManager.java
new file mode 100644
index 0000000..773abed
--- /dev/null
+++ b/src/com/android/camera/processing/imagebackend/ImageTaskManager.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 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 com.android.camera.processing.imagebackend;
+
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * The interface by which Task derived off of TaskImageContainer can describe
+ * its task dependencies and manage its image references.
+ *
+ */
+public interface ImageTaskManager {
+
+    /**
+     * Spawns dependent tasks from internal implementation of set of tasks. If a
+     * dependent task does NOT require the image reference, it should be passed
+     * a null pointer as an image reference. In general, this method should be
+     * called after the task has completed its own computations, but before it
+     * has released its own image reference (via the releaseSemaphoreReference
+     * call).
+     *
+     * @param tasks The set of tasks to be run
+     * @return whether tasks are successfully submitted.
+     */
+    public boolean appendTasks(ImageToProcess img, Set<TaskImageContainer> tasks);
+
+    /**
+     * Spawns a single dependent task from internal implementation of a task.
+     *
+     * @param task The task to be run
+     * @return whether tasks are successfully submitted.
+     */
+    public boolean appendTasks(ImageToProcess img, TaskImageContainer task);
+
+    /**
+     * Signals the ImageTaskManager that a task has released a reference to the
+     * image. ImageTaskManager determines whether all references have been
+     * released and applies its specified release protocol of closing image
+     * and/or unblocking the caller. Should ONLY be called by the tasks running
+     * on this manager.
+     *
+     * @param img the image to be released by the task.
+     * @param executor the executor on which the image close is run. if null,
+     *            image close is run by the calling thread (usually the main
+     *            task thread).
+     */
+    public void releaseSemaphoreReference(final ImageToProcess img, Executor executor);
+
+    /**
+     * Simple getter for the associated listener object associated with this
+     * instance that handles registration of event listeners.
+     *
+     * @return listener proxy that handles events messaging for this object.
+     */
+    public ImageProcessorProxyListener getProxyListener();
+}
diff --git a/src/com/android/camera/processing/imagebackend/TaskChainedCompressImageToJpeg.java b/src/com/android/camera/processing/imagebackend/TaskChainedCompressImageToJpeg.java
index 5f6e4df..03e38c7 100644
--- a/src/com/android/camera/processing/imagebackend/TaskChainedCompressImageToJpeg.java
+++ b/src/com/android/camera/processing/imagebackend/TaskChainedCompressImageToJpeg.java
@@ -32,8 +32,8 @@
     private final static Log.Tag TAG = new Log.Tag("TaskChainJpg");
 
     TaskChainedCompressImageToJpeg(ImageToProcess image, Executor executor,
-            ImageBackend imageBackend, CaptureSession captureSession) {
-        super(image, executor, imageBackend, ProcessingPriority.SLOW, captureSession);
+            ImageTaskManager imageTaskManager, CaptureSession captureSession) {
+        super(image, executor, imageTaskManager, ProcessingPriority.SLOW, captureSession);
     }
 
     private void logWrapper(String message) {
@@ -60,15 +60,11 @@
         strides[2] = 2 * img.proxy.getPlanes()[2].getRowStride()
                 / img.proxy.getPlanes()[2].getPixelStride();
 
-        byte[] dataCopy = mImageBackend.getCache().cacheGet();
-        if (dataCopy == null) {
-            dataCopy = convertYUV420ImageToPackedNV21(img.proxy);
-        } else {
-            convertYUV420ImageToPackedNV21(img.proxy, dataCopy);
-        }
+        // TODO: For performance, use a cache subsystem for buffer reuse.
+        byte[] dataCopy = convertYUV420ImageToPackedNV21(img.proxy);
 
         // Release the image now that you have a usable copy
-        mImageBackend.releaseSemaphoreReference(img, mExecutor);
+        mImageTaskManager.releaseSemaphoreReference(img, mExecutor);
 
         final byte[] chainedDataCopy = dataCopy;
         final int[] chainedStrides = strides;
@@ -82,13 +78,12 @@
                 byte[] compressedData = convertNv21toJpeg(chainedDataCopy,
                         resultImage.height, resultImage.width, chainedStrides);
                 onJpegEncodeDone(mId, inputImage, resultImage, compressedData);
-                mImageBackend.getCache().cacheSave(chainedDataCopy);
                 logWrapper("Finished off a chained task now that image is released.");
             }
         };
 
         // Passed null, since the image has already been released.
-        mImageBackend.appendTasks(null, chainedTask);
+        mImageTaskManager.appendTasks(null, chainedTask);
         logWrapper("Kicking off a chained task now that image is released.");
     }
 }
diff --git a/src/com/android/camera/processing/imagebackend/TaskCompressImageToJpeg.java b/src/com/android/camera/processing/imagebackend/TaskCompressImageToJpeg.java
index 0d2360c..2d8ae31 100644
--- a/src/com/android/camera/processing/imagebackend/TaskCompressImageToJpeg.java
+++ b/src/com/android/camera/processing/imagebackend/TaskCompressImageToJpeg.java
@@ -42,12 +42,12 @@
      *
      * @param image Image required for computation
      * @param executor Executor to run events
-     * @param imageBackend Link to ImageBackend for reference counting
+     * @param imageTaskManager Link to ImageBackend for reference counting
      * @param captureSession Handler for UI/Disk events
      */
-    TaskCompressImageToJpeg(ImageToProcess image, Executor executor, ImageBackend imageBackend,
+    TaskCompressImageToJpeg(ImageToProcess image, Executor executor, ImageTaskManager imageTaskManager,
             CaptureSession captureSession) {
-        super(image, executor, imageBackend, ProcessingPriority.SLOW, captureSession);
+        super(image, executor, imageTaskManager, ProcessingPriority.SLOW, captureSession);
     }
 
     private void logWrapper(String message) {
@@ -89,7 +89,7 @@
         compressedData.rewind();
 
         // Release the image now that you have a usable copy
-        mImageBackend.releaseSemaphoreReference(img, mExecutor);
+        mImageTaskManager.releaseSemaphoreReference(img, mExecutor);
 
         mSession.saveAndFinish(writeOut, resultImage.width, resultImage.height,
                 resultImage.orientation.getDegrees(), createExif(resultImage), null);
diff --git a/src/com/android/camera/processing/imagebackend/TaskConvertImageToRGBPreview.java b/src/com/android/camera/processing/imagebackend/TaskConvertImageToRGBPreview.java
index 43f0c36..3586eed 100644
--- a/src/com/android/camera/processing/imagebackend/TaskConvertImageToRGBPreview.java
+++ b/src/com/android/camera/processing/imagebackend/TaskConvertImageToRGBPreview.java
@@ -37,10 +37,23 @@
 
     private int mTargetWidth;
 
+    /**
+     * Constructor
+     *
+     * @param image Image that the computation is dependent on
+     * @param executor Executor to fire off an events
+     * @param imageTaskManager Image task manager that allows reference counting
+     *            and task spawning
+     * @param captureSession Capture session that bound to this image
+     * @param targetWidth Approximate viewable pixel height of the desired
+     *            preview Image (Resultant image may NOT be of this width)
+     * @param targetHeight Approximate viewable pixel width of the desired
+     *            preview Image (Resulant image may NOT be of this height)
+     */
     TaskConvertImageToRGBPreview(ImageToProcess image, Executor executor,
-            ImageBackend imageBackend, CaptureSession captureSession, int targetWidth,
+            ImageTaskManager imageTaskManager, CaptureSession captureSession, int targetWidth,
             int targetHeight) {
-        super(image, executor, imageBackend, ProcessingPriority.FAST, captureSession);
+        super(image, executor, imageTaskManager, ProcessingPriority.FAST, captureSession);
         mTargetWidth = targetWidth;
         mTargetHeight = targetHeight;
     }
@@ -417,7 +430,7 @@
         // dummyColorInscribedDataCircleFromYuvImage
         final int[] convertedImage = colorInscribedDataCircleFromYuvImage(img.proxy, subsample);
         // Signal backend that reference has been released
-        mImageBackend.releaseSemaphoreReference(img, mExecutor);
+        mImageTaskManager.releaseSemaphoreReference(img, mExecutor);
 
         onPreviewDone(resultImage, inputImage, convertedImage);
     }
@@ -431,7 +444,7 @@
      */
     public void onPreviewDone(TaskImage resultImage, TaskImage inputImage, int[] colors) {
         TaskInfo job = new TaskInfo(mId, inputImage, resultImage);
-        final ImageProcessorListener listener = mImageBackend.getProxyListener();
+        final ImageProcessorListener listener = mImageTaskManager.getProxyListener();
 
         listener.onResultUncompressed(job, new UncompressedPayload(colors));
     }
diff --git a/src/com/android/camera/processing/imagebackend/TaskImageContainer.java b/src/com/android/camera/processing/imagebackend/TaskImageContainer.java
index 9857adf..e32b9a0 100644
--- a/src/com/android/camera/processing/imagebackend/TaskImageContainer.java
+++ b/src/com/android/camera/processing/imagebackend/TaskImageContainer.java
@@ -109,7 +109,7 @@
 
     protected final static Log.Tag TAG = new Log.Tag("TaskImgContain");
 
-    final protected ImageBackend mImageBackend;
+    final protected ImageTaskManager mImageTaskManager;
 
     final protected Executor mExecutor;
 
@@ -130,7 +130,7 @@
     public TaskImageContainer(TaskImageContainer otherTask, ProcessingPriority processingPriority) {
         mId = otherTask.mId;
         mExecutor = otherTask.mExecutor;
-        mImageBackend = otherTask.mImageBackend;
+        mImageTaskManager = otherTask.mImageTaskManager;
         mProcessingPriority = processingPriority;
         mSession = otherTask.mSession;
         mImage = null;
@@ -141,16 +141,16 @@
      *
      * @param image Image reference that needs to be released.
      * @param Executor Executor to run the event handling
-     * @param imageBackend a reference to the ImageBackend, in case, you need to spawn other tasks
+     * @param imageTaskManager a reference to the ImageBackend, in case, you need to spawn other tasks
      * @param preferredLane Priority that the derived task will run at
      * @param captureSession Session that handles image processing events
      */
-    public TaskImageContainer(ImageToProcess image, Executor Executor, ImageBackend imageBackend,
+    public TaskImageContainer(ImageToProcess image, Executor Executor, ImageTaskManager imageTaskManager,
             ProcessingPriority preferredLane, CaptureSession captureSession) {
         mImage = image;
         mId = mImage.proxy.getTimestamp();
         mExecutor = Executor;
-        mImageBackend = imageBackend;
+        mImageTaskManager = imageTaskManager;
         mProcessingPriority = preferredLane;
         mSession = captureSession;
     }
@@ -164,7 +164,7 @@
      */
     public void onStart(long id, TaskImage input, TaskImage result) {
         TaskInfo job = new TaskInfo(id, input, result);
-        final ImageProcessorListener listener = mImageBackend.getProxyListener();
+        final ImageProcessorListener listener = mImageTaskManager.getProxyListener();
         listener.onStart(job);
     }
 
diff --git a/src/com/android/camera/processing/imagebackend/TaskJpegEncode.java b/src/com/android/camera/processing/imagebackend/TaskJpegEncode.java
index 2d8470a..4057217 100644
--- a/src/com/android/camera/processing/imagebackend/TaskJpegEncode.java
+++ b/src/com/android/camera/processing/imagebackend/TaskJpegEncode.java
@@ -52,13 +52,13 @@
      *
      * @param image Image reference that is required for computation
      * @param executor Executor to avoid thread control leakage
-     * @param imageBackend ImageBackend associated with
+     * @param imageTaskManager ImageBackend associated with
      * @param preferredLane Preferred processing priority for this task
      * @param captureSession Session associated for UI handling
      */
-    public TaskJpegEncode(ImageToProcess image, Executor executor, ImageBackend imageBackend,
+    public TaskJpegEncode(ImageToProcess image, Executor executor, ImageTaskManager imageTaskManager,
             TaskImageContainer.ProcessingPriority preferredLane, CaptureSession captureSession) {
-        super(image, executor, imageBackend, preferredLane, captureSession);
+        super(image, executor, imageTaskManager, preferredLane, captureSession);
     }
 
     /**
@@ -178,7 +178,7 @@
      */
     public void onJpegEncodeDone(long id, TaskImage input, TaskImage result, byte[] data) {
         TaskInfo job = new TaskInfo(id, input, result);
-        final ImageProcessorListener listener = mImageBackend.getProxyListener();
+        final ImageProcessorListener listener = mImageTaskManager.getProxyListener();
         listener.onResultCompressed(job, new CompressedPayload(data));
     }
 
diff --git a/src/com/android/camera/processing/imagebackend/TaskWriteImageToDisk.java b/src/com/android/camera/processing/imagebackend/TaskWriteImageToDisk.java
deleted file mode 100644
index d4e1a44..0000000
--- a/src/com/android/camera/processing/imagebackend/TaskWriteImageToDisk.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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 com.android.camera.processing.imagebackend;
-
-import com.android.camera.session.CaptureSession;
-
-import java.util.concurrent.Executor;
-
-/**
- *  Placeholder for writing an image to disk.
- */
-public class TaskWriteImageToDisk extends TaskImageContainer {
-
-    public TaskWriteImageToDisk(ImageToProcess image, Executor executor,
-                                ImageBackend imageBackend, CaptureSession captureSession) {
-        super(image, executor, imageBackend, ProcessingPriority.SLOW, captureSession);
-    }
-
-    @Override
-    public void run() {
-        // TODO: Make a dependency on JPEG_COMPRESSION
-
-    }
-}