OSDN Git Service

Add proper support for canceling sessions.
authorSascha Haeberling <haeberling@google.com>
Mon, 13 Apr 2015 21:06:16 +0000 (14:06 -0700)
committerSascha Haeberling <haeberling@google.com>
Mon, 13 Apr 2015 22:30:34 +0000 (15:30 -0700)
  Bug: 19384186

Change-Id: I45b0262947dcd4257d54e706f3cffc69b6bd4bc9

src/com/android/camera/CameraActivity.java
src/com/android/camera/Storage.java
src/com/android/camera/captureintent/state/StateReadyForCapture.java
src/com/android/camera/captureintent/state/StateReviewingPicture.java
src/com/android/camera/data/SessionItem.java
src/com/android/camera/session/CaptureSessionImpl.java
src/com/android/camera/session/CaptureSessionManager.java
src/com/android/camera/session/CaptureSessionManagerImpl.java
src/com/android/camera/session/PlaceholderManager.java
src/com/android/camera/session/SessionNotifier.java

index 5ff2313..0adc16a 100644 (file)
@@ -144,7 +144,6 @@ import com.android.camera.util.IntentHelper;
 import com.android.camera.util.PhotoSphereHelper.PanoramaViewHelper;
 import com.android.camera.util.QuickActivity;
 import com.android.camera.util.ReleaseHelper;
-import com.android.camera.util.Size;
 import com.android.camera.widget.FilmstripView;
 import com.android.camera.widget.Preloader;
 import com.android.camera2.R;
@@ -157,7 +156,6 @@ import com.bumptech.glide.GlideBuilder;
 import com.bumptech.glide.MemoryCategory;
 import com.bumptech.glide.load.DecodeFormat;
 import com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor;
-import com.bumptech.glide.load.engine.prefill.PreFillType;
 import com.google.common.base.Optional;
 import com.google.common.logging.eventprotos;
 import com.google.common.logging.eventprotos.ForegroundEvent.ForegroundSource;
@@ -881,8 +879,10 @@ public class CameraActivity extends QuickActivity
                     if (!Storage.isSessionUri(uri)) {
                         return;
                     }
-                    SessionItem newData = new SessionItem(getApplicationContext(), uri);
-                    mDataAdapter.addOrUpdate(newData);
+                    Optional<SessionItem> newData = SessionItem.create(getApplicationContext(), uri);
+                    if (newData.isPresent()) {
+                        mDataAdapter.addOrUpdate(newData.get());
+                    }
                 }
 
                 @Override
@@ -989,6 +989,13 @@ public class CameraActivity extends QuickActivity
                 }
 
                 @Override
+                public void onSessionCanceled(Uri uri) {
+                    Log.v(TAG, "onSessionCanceled:" + uri);
+                    int failedIndex = mDataAdapter.findByContentUri(uri);
+                    mDataAdapter.removeAt(failedIndex);
+                }
+
+                @Override
                 public void onSessionThumbnailUpdate(Bitmap bitmap) {
                 }
 
index f33993e..842f9a4 100644 (file)
@@ -28,6 +28,7 @@ import android.provider.MediaStore.Images;
 import android.provider.MediaStore.Images.ImageColumns;
 import android.provider.MediaStore.MediaColumns;
 import android.util.LruCache;
+
 import com.android.camera.data.FilmstripItemData;
 import com.android.camera.debug.Log;
 import com.android.camera.exif.ExifInterface;
@@ -35,7 +36,6 @@ import com.android.camera.util.ApiHelper;
 import com.android.camera.util.Size;
 import com.google.common.base.Optional;
 
-import javax.annotation.Nonnull;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -43,6 +43,8 @@ import java.util.HashMap;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
+import javax.annotation.Nonnull;
+
 public class Storage {
     public static final String DCIM =
             Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
@@ -50,9 +52,6 @@ public class Storage {
     public static final File DIRECTORY_FILE = new File(DIRECTORY);
     public static final String JPEG_POSTFIX = ".jpg";
     public static final String GIF_POSTFIX = ".gif";
-    // Match the code in MediaProvider.computeBucketValues().
-    public static final String BUCKET_ID =
-            String.valueOf(DIRECTORY.toLowerCase().hashCode());
     public static final long UNAVAILABLE = -1L;
     public static final long PREPARING = -2L;
     public static final long UNKNOWN_SIZE = -3L;
@@ -443,14 +442,11 @@ public class Storage {
     }
 
     /**
-     * Returns the current version of a placeholder for a session. The version will increment
-     * with each call to replacePlaceholder.
-     *
-     * @param uri the session uri to look up.
-     * @return the current version int.
+     * @return Whether a placeholder size for the session with the given URI
+     *         exists.
      */
-    public static int getPlaceholderVersionForSession(Uri uri) {
-        return sSessionsToPlaceholderVersions.get(uri);
+    public static boolean containsPlaceholderSize(Uri uri) {
+        return sSessionsToSizes.containsKey(uri);
     }
 
     /**
index aa701df..283f32a 100644 (file)
@@ -610,6 +610,10 @@ public final class StateReadyForCapture extends StateImpl {
                 }
 
                 @Override
+                public void onSessionCanceled(Uri mediaUri) {
+                }
+
+                @Override
                 public void onSessionProgress(Uri sessionUri, int progress) {
                 }
 
index 6cbe2e1..ab42624 100644 (file)
 
 package com.android.camera.captureintent.state;
 
-import com.google.common.base.Optional;
+import android.graphics.Bitmap;
+import android.net.Uri;
 
 import com.android.camera.async.RefCountBase;
 import com.android.camera.captureintent.CaptureIntentConfig;
 import com.android.camera.captureintent.PictureDecoder;
-import com.android.camera.captureintent.resource.ResourceCaptureTools;
-import com.android.camera.captureintent.resource.ResourceConstructed;
-import com.android.camera.captureintent.stateful.EventHandler;
 import com.android.camera.captureintent.event.EventOnTextureViewLayoutChanged;
 import com.android.camera.captureintent.event.EventPause;
 import com.android.camera.captureintent.event.EventPictureCompressed;
@@ -31,13 +29,14 @@ import com.android.camera.captureintent.event.EventPictureDecoded;
 import com.android.camera.captureintent.event.EventTapOnCancelIntentButton;
 import com.android.camera.captureintent.event.EventTapOnConfirmPhotoButton;
 import com.android.camera.captureintent.event.EventTapOnRetakePhotoButton;
+import com.android.camera.captureintent.resource.ResourceCaptureTools;
+import com.android.camera.captureintent.resource.ResourceConstructed;
+import com.android.camera.captureintent.stateful.EventHandler;
 import com.android.camera.captureintent.stateful.State;
 import com.android.camera.captureintent.stateful.StateImpl;
 import com.android.camera.debug.Log;
 import com.android.camera.session.CaptureSessionManager;
-
-import android.graphics.Bitmap;
-import android.net.Uri;
+import com.google.common.base.Optional;
 
 /**
  * A state that shows the taken picture for review. The Cancel, Done or
@@ -263,6 +262,10 @@ public class StateReviewingPicture extends StateImpl {
                 }
 
                 @Override
+                public void onSessionCanceled(Uri mediaUri) {
+                }
+
+                @Override
                 public void onSessionProgress(Uri sessionUri, int progress) {
                 }
 
index ef9ce4a..e36931b 100644 (file)
@@ -24,6 +24,7 @@ import android.view.View;
 import android.widget.ImageView;
 
 import com.android.camera.Storage;
+import com.android.camera.debug.Log;
 import com.android.camera.util.Size;
 import com.android.camera2.R;
 import com.bumptech.glide.Glide;
@@ -44,7 +45,24 @@ public class SessionItem implements FilmstripItem {
     private final Context mContext;
     private final Uri mUri;
 
-    public SessionItem(Context context, Uri uri) {
+    /**
+     * Creates a new session from the given URI.
+     * @param context valid android application context.
+     * @param uri the URI of the session.
+     * @return If the session was found, a new SessionItem is returned.
+     */
+    public static Optional<SessionItem> create(Context context, Uri uri) {
+        if (!Storage.containsPlaceholderSize(uri)) {
+            return Optional.absent();
+        }
+        Size dimension = getSessionSize(uri);
+        if (dimension == null) {
+            return Optional.absent();
+        }
+        return Optional.of(new SessionItem(context, uri, dimension));
+    }
+
+    protected SessionItem(Context context, Uri uri, Size dimension) {
         mContext = context;
         mUri = uri;
 
@@ -52,8 +70,6 @@ public class SessionItem implements FilmstripItem {
         mMetaData.setLoaded(true);
 
         Date creationDate = new Date();
-        Size dimension = getSessionSize(uri);
-
         mData = new FilmstripItemData.Builder(uri)
               .withCreationDate(creationDate)
               .withLastModifiedDate(creationDate)
@@ -63,12 +79,14 @@ public class SessionItem implements FilmstripItem {
         mAttributes = new FilmstripItemAttributes.Builder()
                 .with(FilmstripItemAttributes.Attributes.IS_RENDERING)
                 .build();
-
     }
 
-    private Size getSessionSize(Uri uri) {
+    private static Size getSessionSize(Uri uri) {
         Point size = Storage.getSizeForSession(uri);
-        return new Size(size.x, size.y);
+        if (size == null) {
+            return null;
+        }
+        return new Size(size);
     }
 
     @Override
@@ -124,6 +142,10 @@ public class SessionItem implements FilmstripItem {
     @Override
     public FilmstripItem refresh() {
         Size dimension = getSessionSize(mData.getUri());
+        if (dimension == null) {
+            Log.w(TAG, "Cannot refresh item, session does not exist.");
+            return this;
+        }
 
         mData = FilmstripItemData.Builder.from(mData)
               .withDimensions(dimension)
index 8602d73..0cb5257 100644 (file)
@@ -50,6 +50,8 @@ public class CaptureSessionImpl implements CaptureSession {
     private final SessionNotifier mSessionNotifier;
     /** Used for adding/removing/updating placeholders for in-progress sessions. */
     private final PlaceholderManager mPlaceholderManager;
+    /** A place holder for this capture session. */
+    private PlaceholderManager.Placeholder mPlaceHolder;
     /** Used to store images on disk and to add them to the media store. */
     private final MediaSaver mMediaSaver;
     /** The title of the item being processed. */
@@ -72,8 +74,6 @@ public class CaptureSessionImpl implements CaptureSession {
     private int mProgressPercent = 0;
     /** A message ID for the current progress state. */
     private int mProgressMessageId;
-    /** A place holder for this capture session. */
-    private PlaceholderManager.Session mPlaceHolderSession;
     private Uri mContentUri;
     /** Whether this image was finished. */
     private volatile boolean mIsFinished;
@@ -163,7 +163,7 @@ public class CaptureSessionImpl implements CaptureSession {
 
     @Override
     public void updateThumbnail(Bitmap bitmap) {
-        mPlaceholderManager.replacePlaceholder(mPlaceHolderSession, bitmap);
+        mPlaceholderManager.replacePlaceholder(mPlaceHolder, bitmap);
         mSessionNotifier.notifySessionUpdated(mUri);
     }
 
@@ -179,9 +179,9 @@ public class CaptureSessionImpl implements CaptureSession {
         }
 
         mProgressMessageId = -1;
-        mPlaceHolderSession = mPlaceholderManager.insertEmptyPlaceholder(mTitle, pictureSize,
+        mPlaceHolder = mPlaceholderManager.insertEmptyPlaceholder(mTitle, pictureSize,
                 mSessionStartMillis);
-        mUri = mPlaceHolderSession.outputUri;
+        mUri = mPlaceHolder.outputUri;
         mSessionManager.putSession(mUri, this);
         mSessionNotifier.notifyTaskQueued(mUri);
     }
@@ -193,9 +193,9 @@ public class CaptureSessionImpl implements CaptureSession {
         }
 
         mProgressMessageId = progressMessageId;
-        mPlaceHolderSession = mPlaceholderManager.insertPlaceholder(mTitle, placeholder,
+        mPlaceHolder = mPlaceholderManager.insertPlaceholder(mTitle, placeholder,
                 mSessionStartMillis);
-        mUri = mPlaceHolderSession.outputUri;
+        mUri = mPlaceHolder.outputUri;
         mSessionManager.putSession(mUri, this);
         mSessionNotifier.notifyTaskQueued(mUri);
         onCaptureIndicatorUpdate(placeholder, 0);
@@ -208,13 +208,13 @@ public class CaptureSessionImpl implements CaptureSession {
         }
 
         mProgressMessageId = progressMessageId;
-        mPlaceHolderSession = mPlaceholderManager.insertPlaceholder(mTitle, placeholder,
+        mPlaceHolder = mPlaceholderManager.insertPlaceholder(mTitle, placeholder,
                 mSessionStartMillis);
-        mUri = mPlaceHolderSession.outputUri;
+        mUri = mPlaceHolder.outputUri;
         mSessionManager.putSession(mUri, this);
         mSessionNotifier.notifyTaskQueued(mUri);
         Optional<Bitmap> placeholderBitmap =
-                mPlaceholderManager.getPlaceholder(mPlaceHolderSession);
+                mPlaceholderManager.getPlaceholder(mPlaceHolder);
         if (placeholderBitmap.isPresent()) {
             onCaptureIndicatorUpdate(placeholderBitmap.get(), 0);
         }
@@ -224,7 +224,7 @@ public class CaptureSessionImpl implements CaptureSession {
     public synchronized void startSession(Uri uri, int progressMessageId) {
         mUri = uri;
         mProgressMessageId = progressMessageId;
-        mPlaceHolderSession = mPlaceholderManager.convertToPlaceholder(uri);
+        mPlaceHolder = mPlaceholderManager.convertToPlaceholder(uri);
 
         mSessionManager.putSession(mUri, this);
         mSessionNotifier.notifyTaskQueued(mUri);
@@ -234,6 +234,12 @@ public class CaptureSessionImpl implements CaptureSession {
     public synchronized void cancel() {
         if (isStarted()) {
             mSessionManager.removeSession(mUri);
+            mSessionNotifier.notifyTaskCanceled(mUri);
+        }
+
+        if (mPlaceHolder != null) {
+            mPlaceholderManager.removePlaceholder(mPlaceHolder);
+            mPlaceHolder = null;
         }
     }
 
@@ -243,7 +249,7 @@ public class CaptureSessionImpl implements CaptureSession {
         final SettableFuture<Optional<Uri>> futureResult = SettableFuture.create();
 
         mIsFinished = true;
-        if (mPlaceHolderSession == null) {
+        if (mPlaceHolder == null) {
             mMediaSaver.addImage(
                     data, mTitle, mSessionStartMillis, mLocation, width, height,
                     orientation, exif, new MediaSaver.OnMediaSavedListener() {
@@ -254,7 +260,7 @@ public class CaptureSessionImpl implements CaptureSession {
                     });
         } else {
             try {
-                mContentUri = mPlaceholderManager.finishPlaceholder(mPlaceHolderSession, mLocation,
+                mContentUri = mPlaceholderManager.finishPlaceholder(mPlaceHolder, mLocation,
                         orientation, exif, data, width, height, FilmstripItemData.MIME_TYPE_JPEG);
                 mSessionNotifier.notifyTaskDone(mUri);
                 futureResult.set(Optional.fromNullable(mUri));
@@ -274,7 +280,7 @@ public class CaptureSessionImpl implements CaptureSession {
 
     @Override
     public void finish() {
-        if (mPlaceHolderSession == null) {
+        if (mPlaceHolder == null) {
             throw new IllegalStateException(
                     "Cannot call finish without calling startSession first.");
         }
@@ -348,7 +354,7 @@ public class CaptureSessionImpl implements CaptureSession {
                 BitmapFactory.Options options = new BitmapFactory.Options();
                 Bitmap placeholder = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length,
                         options);
-                mPlaceholderManager.replacePlaceholder(mPlaceHolderSession, placeholder);
+                mPlaceholderManager.replacePlaceholder(mPlaceHolder, placeholder);
                 mSessionNotifier.notifySessionUpdated(mUri);
             }
         });
@@ -356,7 +362,7 @@ public class CaptureSessionImpl implements CaptureSession {
 
     @Override
     public void finishWithFailure(int failureMessageId, boolean removeFromFilmstrip) {
-        if (mPlaceHolderSession == null) {
+        if (mPlaceHolder == null) {
             throw new IllegalStateException(
                     "Cannot call finish without calling startSession first.");
         }
@@ -381,7 +387,7 @@ public class CaptureSessionImpl implements CaptureSession {
 
     @Override
     public void finalizeSession() {
-        mPlaceholderManager.removePlaceholder(mPlaceHolderSession);
+        mPlaceholderManager.removePlaceholder(mPlaceHolder);
     }
 
     private void onCaptureIndicatorUpdate(Bitmap indicator, int rotationDegrees) {
index 4aca936..aaf1163 100644 (file)
@@ -58,6 +58,9 @@ public interface CaptureSessionManager {
         /** Called when the session with the given Uri failed processing. */
         public void onSessionFailed(Uri mediaUri, int failureMessageId, boolean removeFromFilmstrip);
 
+        /** Called when the session with the given Uri was canceled. */
+        public void onSessionCanceled(Uri mediaUri);
+
         /** Called when the session with the given Uri has progressed. */
         public void onSessionProgress(Uri mediaUri, int progress);
 
index 7d7fd65..6412873 100644 (file)
@@ -118,6 +118,21 @@ public class CaptureSessionManagerImpl implements CaptureSessionManager {
             });
         }
 
+        @Override
+        public void notifyTaskCanceled(final Uri uri) {
+            mMainHandler.execute(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (mTaskListeners) {
+                        for (SessionListener listener : mTaskListeners) {
+                            listener.onSessionCanceled(uri);
+                        }
+                    }
+                    finalizeSession(uri);
+                }
+            });
+        }
+
         /**
          * Notifies all task listeners that the task with the given URI has
          * progressed to the given state.
index 7ed7779..b54405f 100644 (file)
@@ -43,12 +43,12 @@ public class PlaceholderManager {
 
     private final Context mContext;
 
-    public static class Session {
+    public static class Placeholder {
         final String outputTitle;
         final Uri outputUri;
         final long time;
 
-        Session(String title, Uri uri, long timestamp) {
+        Placeholder(String title, Uri uri, long timestamp) {
             outputTitle = title;
             outputUri = uri;
             time = timestamp;
@@ -68,9 +68,9 @@ public class PlaceholderManager {
      *            within the filmstrip). Millis since epoch.
      * @return A session instance representing the new placeholder.
      */
-    public Session insertEmptyPlaceholder(String title, Size size, long timestamp) {
+    public Placeholder insertEmptyPlaceholder(String title, Size size, long timestamp) {
         Uri uri =  Storage.addEmptyPlaceholder(size);
-        return new Session(title, uri, timestamp);
+        return new Placeholder(title, uri, timestamp);
     }
 
     /**
@@ -82,7 +82,7 @@ public class PlaceholderManager {
      *            within the filmstrip). Millis since epoch.
      * @return A session instance representing the new placeholder.
      */
-    public Session insertPlaceholder(String title, Bitmap placeholder, long timestamp) {
+    public Placeholder insertPlaceholder(String title, Bitmap placeholder, long timestamp) {
         if (title == null || placeholder == null) {
             throw new IllegalArgumentException("Null argument passed to insertPlaceholder");
         }
@@ -95,10 +95,10 @@ public class PlaceholderManager {
         if (uri == null) {
             return null;
         }
-        return new Session(title, uri, timestamp);
+        return new Placeholder(title, uri, timestamp);
     }
 
-    public Session insertPlaceholder(String title, byte[] placeholder, long timestamp) {
+    public Placeholder insertPlaceholder(String title, byte[] placeholder, long timestamp) {
         if (title == null || placeholder == null) {
             throw new IllegalArgumentException("Null argument passed to insertPlaceholder");
         }
@@ -115,14 +115,14 @@ public class PlaceholderManager {
      * @return A session that can be used to update the progress of the new
      *         session.
      */
-    public Session convertToPlaceholder(Uri uri) {
+    public Placeholder convertToPlaceholder(Uri uri) {
         return createSessionFromUri(uri);
     }
 
     /**
      * This converts the placeholder in to a real media item
      *
-     * @param session the session that is being finished.
+     * @param placeholder the session that is being finished.
      * @param location the location of the image
      * @param orientation the orientation of the image
      * @param exif the exif of the image
@@ -132,10 +132,10 @@ public class PlaceholderManager {
      * @param mimeType the mime type of the image
      * @return The content URI of the new media item.
      */
-    public Uri finishPlaceholder(Session session, Location location, int orientation,
+    public Uri finishPlaceholder(Placeholder placeholder, Location location, int orientation,
             ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) throws IOException {
-        Uri resultUri = Storage.updateImage(session.outputUri, mContext.getContentResolver(),
-                session.outputTitle, session.time, location, orientation, exif, jpeg, width,
+        Uri resultUri = Storage.updateImage(placeholder.outputUri, mContext.getContentResolver(),
+                placeholder.outputTitle, placeholder.time, location, orientation, exif, jpeg, width,
                 height, mimeType);
         CameraUtil.broadcastNewPicture(mContext, resultUri);
         return resultUri;
@@ -147,7 +147,7 @@ public class PlaceholderManager {
      * @param session the session to update
      * @param placeholder the placeholder bitmap
      */
-    public void replacePlaceholder(Session session, Bitmap placeholder) {
+    public void replacePlaceholder(Placeholder session, Bitmap placeholder) {
         Storage.replacePlaceholder(session.outputUri, placeholder);
         CameraUtil.broadcastNewPicture(mContext, session.outputUri);
     }
@@ -155,20 +155,20 @@ public class PlaceholderManager {
     /**
      * Retrieve the placeholder for a given session.
      *
-     * @param session the session for which to retrieve bitmap placeholder
+     * @param placeholder the session for which to retrieve bitmap placeholder
      */
-    public Optional<Bitmap> getPlaceholder(Session session) {
-        return Storage.getPlaceholderForSession(session.outputUri);
+    public Optional<Bitmap> getPlaceholder(Placeholder placeholder) {
+        return Storage.getPlaceholderForSession(placeholder.outputUri);
     }
 
 
     /**
      * Remove the placeholder for a given session.
      *
-     * @param session the session for which to remove the bitmap placeholder.
+     * @param placeholder the session for which to remove the bitmap placeholder.
      */
-    public void removePlaceholder(Session session) {
-        Storage.removePlaceholder(session.outputUri);
+    public void removePlaceholder(Placeholder placeholder) {
+        Storage.removePlaceholder(placeholder.outputUri);
     }
 
     /**
@@ -177,7 +177,7 @@ public class PlaceholderManager {
      * <p>
      * TODO: Make sure this works with types other than images when needed.
      */
-    private Session createSessionFromUri(Uri uri) {
+    private Placeholder createSessionFromUri(Uri uri) {
         ContentResolver resolver = mContext.getContentResolver();
 
         Cursor cursor = resolver.query(uri,
@@ -200,6 +200,6 @@ public class PlaceholderManager {
             name = name.substring(0, name.length() - Storage.JPEG_POSTFIX.length());
         }
 
-        return new Session(name, uri, date);
+        return new Placeholder(name, uri, date);
     }
 }
index 3107ae7..2293bfd 100644 (file)
@@ -32,7 +32,10 @@ public interface SessionNotifier {
 
     /** A task has failed to process. */
     public void notifyTaskFailed(final Uri uri, final int failureMessageId,
-            boolean removeFromFilmstrip);
+                                 boolean removeFromFilmstrip);
+
+    /** A task has been canceled. */
+    public void notifyTaskCanceled(final Uri uri);
 
     /** A task has progressed. */
     public void notifyTaskProgress(final Uri uri, final int progressPercent);