OSDN Git Service

Change CaptureSession.saveAndFinish to return a future for the URI.
authorSascha Haeberling <haeberling@google.com>
Wed, 25 Mar 2015 22:08:34 +0000 (15:08 -0700)
committerSascha Haeberling <haeberling@google.com>
Wed, 25 Mar 2015 23:35:20 +0000 (16:35 -0700)
  Bug: 19665531

Most callers of saveAndFinish never provided the callback. In addition
it's unclear on what thread the callback is called. This cleans this up
a bit and moves the responsibility to the caller to decide on which
thread the URI should be received. Callers that don't care don't have to
do anything.

Also fixes a bug where we wouldn't even supply a URI for when there was
no placeholder.

Change-Id: I1a186b470d2cca8f34a674e9eb5c533fc01a4409

src/com/android/camera/CaptureModule.java
src/com/android/camera/captureintent/CaptureIntentSession.java
src/com/android/camera/one/v2/OneCameraImpl.java
src/com/android/camera/one/v2/OneCameraZslImpl.java
src/com/android/camera/processing/imagebackend/TaskCompressImageToJpeg.java
src/com/android/camera/session/CaptureSession.java
src/com/android/camera/session/CaptureSessionImpl.java

index 96a0f85..884fee7 100644 (file)
@@ -47,7 +47,6 @@ import com.android.camera.captureintent.PreviewTransformCalculator;
 import com.android.camera.debug.DebugPropertyHelper;
 import com.android.camera.debug.Log;
 import com.android.camera.debug.Log.Tag;
-import com.android.camera.device.ActiveCameraDeviceTracker;
 import com.android.camera.device.CameraId;
 import com.android.camera.hardware.HardwareSpec;
 import com.android.camera.hardware.HeadingSensor;
index ab18eaf..bd78dce 100644 (file)
 
 package com.android.camera.captureintent;
 
-import com.android.camera.app.MediaSaver;
+import android.graphics.Bitmap;
+import android.location.Location;
+import android.net.Uri;
+
 import com.android.camera.debug.Log;
 import com.android.camera.exif.ExifInterface;
 import com.android.camera.session.CaptureSession;
@@ -26,10 +29,9 @@ import com.android.camera.session.StackSaver;
 import com.android.camera.session.TemporarySessionFile;
 import com.android.camera.stats.CaptureSessionStatsCollector;
 import com.android.camera.util.Size;
-
-import android.graphics.Bitmap;
-import android.location.Location;
-import android.net.Uri;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * An implementation of {@link CaptureSession} which is used by
@@ -140,9 +142,10 @@ public class CaptureIntentSession implements CaptureSession {
     }
 
     @Override
-    public synchronized void saveAndFinish(byte[] data, int width, int height, int orientation,
-            ExifInterface exif, final MediaSaver.OnMediaSavedListener listener) {
+    public synchronized ListenableFuture<Optional<Uri>> saveAndFinish(byte[] data, int width,
+            int height, int orientation, ExifInterface exif) {
         mSessionNotifier.notifySessionPictureDataAvailable(data, orientation);
+        return Futures.immediateFuture(Optional.<Uri> absent());
     }
 
     @Override
index 6c139ad..d4c7cba 100644 (file)
@@ -45,7 +45,6 @@ import android.view.Surface;
 import com.android.camera.CaptureModuleUtil;
 import com.android.camera.Exif;
 import com.android.camera.Storage;
-import com.android.camera.app.MediaSaver.OnMediaSavedListener;
 import com.android.camera.debug.DebugPropertyHelper;
 import com.android.camera.debug.Log;
 import com.android.camera.debug.Log.Tag;
@@ -69,6 +68,9 @@ import com.android.camera.util.ExifUtil;
 import com.android.camera.util.JpegUtilNative;
 import com.android.camera.util.Size;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -498,10 +500,17 @@ public class OneCameraImpl extends AbstractOneCamera {
             Log.w(TAG, "Could not read exif from gcam jpeg", e);
             exif = null;
         }
-        session.saveAndFinish(jpegData, width, height, rotation, exif, new OnMediaSavedListener() {
+        ListenableFuture<Optional<Uri>> futureUri = session.saveAndFinish(jpegData, width, height,
+                rotation, exif);
+        Futures.addCallback(futureUri, new FutureCallback<Optional<Uri>>() {
             @Override
-            public void onMediaSaved(Uri uri) {
-                captureParams.callback.onPictureSaved(uri);
+            public void onSuccess(Optional<Uri> uriOptional) {
+                captureParams.callback.onPictureSaved(uriOptional.orNull());
+            }
+
+            @Override
+            public void onFailure(Throwable throwable) {
+                captureParams.callback.onPictureSaved(null);
             }
         });
     }
index c8a4a00..6bdad44 100644 (file)
@@ -43,7 +43,6 @@ import android.support.v4.util.Pools;
 import android.view.Surface;
 
 import com.android.camera.CaptureModuleUtil;
-import com.android.camera.app.MediaSaver.OnMediaSavedListener;
 import com.android.camera.debug.Log;
 import com.android.camera.debug.Log.Tag;
 import com.android.camera.exif.ExifInterface;
@@ -69,6 +68,9 @@ import com.android.camera.util.JpegUtilNative;
 import com.android.camera.util.ListenerCombiner;
 import com.android.camera.util.Size;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 import java.nio.ByteBuffer;
 import java.security.InvalidParameterException;
@@ -634,13 +636,20 @@ public class OneCameraZslImpl extends AbstractOneCamera {
         new ExifUtil(exif).populateExif(Optional.<TaskImageContainer.TaskImage>absent(),
                 Optional.of((CaptureResultProxy) new AndroidCaptureResultProxy(result)),
                 Optional.<Location>absent());
-        session.saveAndFinish(acquireJpegBytes(image, degrees),
-                size.getWidth(), size.getHeight(), 0, exif, new OnMediaSavedListener() {
-                        @Override
-                    public void onMediaSaved(Uri uri) {
-                        captureParams.callback.onPictureSaved(uri);
-                    }
-                });
+        ListenableFuture<Optional<Uri>> futureUri = session.saveAndFinish(
+                acquireJpegBytes(image, degrees),
+                size.getWidth(), size.getHeight(), 0, exif);
+        Futures.addCallback(futureUri, new FutureCallback<Optional<Uri>>() {
+            @Override
+            public void onSuccess(Optional<Uri> uriOptional) {
+                captureParams.callback.onPictureSaved(uriOptional.orNull());
+            }
+
+            @Override
+            public void onFailure(Throwable throwable) {
+                captureParams.callback.onPictureSaved(null);
+            }
+        });
     }
 
     /**
index 023bfd7..b5120e5 100644 (file)
@@ -23,9 +23,7 @@ import android.media.CameraProfile;
 import android.net.Uri;
 
 import com.android.camera.Exif;
-import com.android.camera.app.MediaSaver;
 import com.android.camera.app.OrientationManager.DeviceOrientation;
-import com.android.camera.async.Listenable;
 import com.android.camera.debug.Log;
 import com.android.camera.exif.ExifInterface;
 import com.android.camera.one.v2.camera2proxy.CaptureResultProxy;
@@ -36,6 +34,8 @@ import com.android.camera.util.ExifUtil;
 import com.android.camera.util.JpegUtilNative;
 import com.android.camera.util.Size;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 
 import java.nio.ByteBuffer;
@@ -288,15 +288,21 @@ public class TaskCompressImageToJpeg extends TaskJpegEncode {
         final ExifInterface exif = createExif(Optional.fromNullable(exifData), resultImage,
                 img.metadata);
         mSession.getCollector().decorateAtTimeWriteToDisk(exif);
-        mSession.saveAndFinish(writeOut, resultImage.width, resultImage.height,
-                resultImage.orientation.getDegrees(), exif,
-                new MediaSaver.OnMediaSavedListener() {
-                    @Override
-                    public void onMediaSaved(Uri uri) {
-                        onUriResolved(mId, finalInput, finalResult, uri,
-                                TaskInfo.Destination.FINAL_IMAGE);
-                    }
-                });
+        ListenableFuture<Optional<Uri>> futureUri = mSession.saveAndFinish(writeOut,
+                resultImage.width, resultImage.height, resultImage.orientation.getDegrees(), exif);
+        Futures.addCallback(futureUri, new FutureCallback<Optional<Uri>>() {
+            @Override
+            public void onSuccess(Optional<Uri> uriOptional) {
+                if (uriOptional.isPresent()) {
+                    onUriResolved(mId, finalInput, finalResult, uriOptional.get(),
+                            TaskInfo.Destination.FINAL_IMAGE);
+                }
+            }
+
+            @Override
+            public void onFailure(Throwable throwable) {
+            }
+        });
 
         final ListenableFuture<TotalCaptureResultProxy> requestMetadata = img.metadata;
         // If TotalCaptureResults are available add them to the capture event.
index 53e71e7..7b28089 100644 (file)
@@ -20,10 +20,11 @@ import android.graphics.Bitmap;
 import android.location.Location;
 import android.net.Uri;
 
-import com.android.camera.app.MediaSaver.OnMediaSavedListener;
 import com.android.camera.exif.ExifInterface;
 import com.android.camera.stats.CaptureSessionStatsCollector;
 import com.android.camera.util.Size;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
 
 /**
  * A session is an item that is in progress of being created and saved, such as
@@ -154,9 +155,20 @@ public interface CaptureSession {
     /**
      * Finish the session by saving the image to disk. Will add the final item
      * in the film strip and remove the progress notifications.
-     */
-    public void saveAndFinish(byte[] data, int width, int height, int orientation,
-            ExifInterface exif, OnMediaSavedListener listener);
+     *
+     * @param data the data of the data (e.g. JPEG bytes) that should be written
+     *            to disk.
+     * @param width the width of the media item, in pixels.
+     * @param height the height of the media item, in pixels.
+     * @param orientation the orientaiton of the media item, in degrees.
+     * @param exif the EXIF information for this media item.
+     * @return A future that will provide the URI once the item is saved. URI
+     *         might be absent if the data could not be saved successfull, which
+     *         in turn means if a URI is returned it is guaranteed that the
+     *         media item was successfully written to disk.
+     */
+    public ListenableFuture<Optional<Uri>> saveAndFinish(byte[] data, int width, int height,
+            int orientation, ExifInterface exif);
 
     /**
      * Will create and return a {@link StackSaver} for saving out a number of
index 60086ab..8602d73 100644 (file)
@@ -30,6 +30,8 @@ import com.android.camera.stats.CaptureSessionStatsCollector;
 import com.android.camera.util.FileUtil;
 import com.android.camera.util.Size;
 import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 
 import java.io.File;
 import java.io.IOException;
@@ -236,25 +238,33 @@ public class CaptureSessionImpl implements CaptureSession {
     }
 
     @Override
-    public synchronized void saveAndFinish(byte[] data, int width, int height, int orientation,
-            ExifInterface exif, final MediaSaver.OnMediaSavedListener listener) {
+    public synchronized ListenableFuture<Optional<Uri>> saveAndFinish(byte[] data, int width, int height,
+            int orientation, ExifInterface exif) {
+        final SettableFuture<Optional<Uri>> futureResult = SettableFuture.create();
+
         mIsFinished = true;
         if (mPlaceHolderSession == null) {
             mMediaSaver.addImage(
                     data, mTitle, mSessionStartMillis, mLocation, width, height,
-                    orientation, exif, listener);
-            return;
-        }
-        try {
-            mContentUri = mPlaceholderManager.finishPlaceholder(mPlaceHolderSession, mLocation,
-                    orientation, exif, data, width, height, FilmstripItemData.MIME_TYPE_JPEG);
-            mSessionNotifier.notifyTaskDone(mUri);
-        } catch (IOException e) {
-            Log.e(TAG, "IOException", e);
-            // TODO: Replace with a sensisble description
-            // Placeholder string R.string.reason_storage_failure
-            finishWithFailure(-1, true);
+                    orientation, exif, new MediaSaver.OnMediaSavedListener() {
+                        @Override
+                        public void onMediaSaved(Uri uri) {
+                            futureResult.set(Optional.fromNullable(uri));
+                        }
+                    });
+        } else {
+            try {
+                mContentUri = mPlaceholderManager.finishPlaceholder(mPlaceHolderSession, mLocation,
+                        orientation, exif, data, width, height, FilmstripItemData.MIME_TYPE_JPEG);
+                mSessionNotifier.notifyTaskDone(mUri);
+                futureResult.set(Optional.fromNullable(mUri));
+            } catch (IOException e) {
+                Log.e(TAG, "Could not write file", e);
+                finishWithFailure(-1, true);
+                futureResult.setException(e);
+            }
         }
+        return futureResult;
     }
 
     @Override
@@ -299,8 +309,7 @@ public class CaptureSessionImpl implements CaptureSession {
                     Log.w(TAG, "Could not read exif", e);
                     exif = null;
                 }
-                CaptureSessionImpl.this.saveAndFinish(jpegData, width, height, rotation, exif,
-                        null);
+                CaptureSessionImpl.this.saveAndFinish(jpegData, width, height, rotation, exif);
             }
         });