Introduce ActionCallback for LocalData items.

  Bug: 18105354

Fixes the bug where we try to cast a context to an activity.

Change-Id: I3e82a2cda5fe004768276a4d48c07d75738b2a5e
diff --git a/src/com/android/camera/data/CameraDataAdapter.java b/src/com/android/camera/data/CameraDataAdapter.java
index 721b213..07100ef 100644
--- a/src/com/android/camera/data/CameraDataAdapter.java
+++ b/src/com/android/camera/data/CameraDataAdapter.java
@@ -23,6 +23,7 @@
 import android.view.View;
 
 import com.android.camera.Storage;
+import com.android.camera.data.LocalData.ActionCallback;
 import com.android.camera.debug.Log;
 import com.android.camera.filmstrip.ImageData;
 import com.android.camera.util.Callback;
@@ -125,14 +126,15 @@
     }
 
     @Override
-    public View getView(Context context, View recycled, int dataID) {
+    public View getView(Context context, View recycled, int dataID,
+            ActionCallback actionCallback) {
         if (dataID >= mImages.size() || dataID < 0) {
             return null;
         }
 
         return mImages.get(dataID).getView(
                 context, recycled, mSuggestedWidth, mSuggestedHeight,
-                mPlaceHolderResourceId, this, /* inProgress */ false);
+                mPlaceHolderResourceId, this, /* inProgress */ false, actionCallback);
     }
 
     @Override
diff --git a/src/com/android/camera/data/FixedFirstDataAdapter.java b/src/com/android/camera/data/FixedFirstDataAdapter.java
index 471fd19..f14a1c8 100644
--- a/src/com/android/camera/data/FixedFirstDataAdapter.java
+++ b/src/com/android/camera/data/FixedFirstDataAdapter.java
@@ -21,6 +21,7 @@
 import android.os.AsyncTask;
 import android.view.View;
 
+import com.android.camera.data.LocalData.ActionCallback;
 import com.android.camera.debug.Log;
 import com.android.camera.filmstrip.DataAdapter;
 import com.android.camera.filmstrip.ImageData;
@@ -110,12 +111,12 @@
     }
 
     @Override
-    public View getView(Context context, View recycled, int dataID) {
+    public View getView(Context context, View recycled, int dataID, ActionCallback actionCallback) {
         if (dataID == 0) {
-            return mFirstData.getView(
-                    context, recycled, mSuggestedWidth, mSuggestedHeight, 0, null, false);
+            return mFirstData.getView(context, recycled, mSuggestedWidth, mSuggestedHeight, 0,
+                    null, false, actionCallback);
         }
-        return mAdapter.getView(context, recycled, dataID - 1);
+        return mAdapter.getView(context, recycled, dataID - 1, actionCallback);
     }
 
     @Override
diff --git a/src/com/android/camera/data/FixedLastDataAdapter.java b/src/com/android/camera/data/FixedLastDataAdapter.java
index 35978d8..a87a2de 100644
--- a/src/com/android/camera/data/FixedLastDataAdapter.java
+++ b/src/com/android/camera/data/FixedLastDataAdapter.java
@@ -21,6 +21,7 @@
 import android.os.AsyncTask;
 import android.view.View;
 
+import com.android.camera.data.LocalData.ActionCallback;
 import com.android.camera.filmstrip.ImageData;
 
 /**
@@ -66,7 +67,6 @@
         } else if (dataID == totalNumber) {
             return mLastData;
         }
-
         return null;
     }
 
@@ -112,16 +112,15 @@
     }
 
     @Override
-    public View getView(Context context, View recycled, int dataID) {
+    public View getView(Context context, View recycled, int dataID, ActionCallback actionCallback) {
         int totalNumber = mAdapter.getTotalNumber();
 
         if (dataID < totalNumber) {
-            return mAdapter.getView(context, recycled, dataID);
+            return mAdapter.getView(context, recycled, dataID, actionCallback);
         } else if (dataID == totalNumber) {
-            return mLastData.getView(context, recycled,
-                    mSuggestedWidth, mSuggestedHeight, 0, null, false);
+            return mLastData.getView(context, recycled, mSuggestedWidth, mSuggestedHeight, 0, null,
+                    false, actionCallback);
         }
-
         return null;
     }
 
@@ -134,7 +133,6 @@
         } else if (dataId == totalNumber) {
             return mLastData.getItemViewType().ordinal();
         }
-
         return -1;
    }
 
diff --git a/src/com/android/camera/data/LocalData.java b/src/com/android/camera/data/LocalData.java
index df2d9c2..d42bf97 100644
--- a/src/com/android/camera/data/LocalData.java
+++ b/src/com/android/camera/data/LocalData.java
@@ -17,8 +17,10 @@
 package com.android.camera.data;
 
 import android.content.Context;
+import android.net.Uri;
 import android.os.Bundle;
 import android.view.View;
+
 import com.android.camera.debug.Log;
 import com.android.camera.filmstrip.ImageData;
 
@@ -32,6 +34,14 @@
  * can guarantee thread safety for LocalData.
  */
 public interface LocalData extends ImageData {
+    /**
+     * An action callback to be used for actions on the local media data items.
+     */
+    public static interface ActionCallback {
+        /** Plays the video with the given URI and title. */
+        public void playVideo(Uri uri, String title);
+    }
+
     static final Log.Tag TAG = new Log.Tag("LocalData");
 
     public static final String MIME_TYPE_JPEG = "image/jpeg";
@@ -79,7 +89,8 @@
      * @param adapter Data adapter for this data item.
      */
     View getView(Context context, View recycled, int thumbWidth, int thumbHeight,
-        int placeHolderResourceId, LocalDataAdapter adapter, boolean isInProgress);
+            int placeHolderResourceId, LocalDataAdapter adapter, boolean isInProgress,
+            ActionCallback actionCallback);
 
     /** Returns a unique identifier for the view created by this data so that the view
      * can be reused.
diff --git a/src/com/android/camera/data/LocalMediaData.java b/src/com/android/camera/data/LocalMediaData.java
index 3f7e413..ab57058 100644
--- a/src/com/android/camera/data/LocalMediaData.java
+++ b/src/com/android/camera/data/LocalMediaData.java
@@ -16,7 +16,6 @@
 
 package com.android.camera.data;
 
-import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
@@ -32,7 +31,6 @@
 
 import com.android.camera.Storage;
 import com.android.camera.debug.Log;
-import com.android.camera.util.CameraUtil;
 import com.android.camera2.R;
 import com.bumptech.glide.BitmapRequestBuilder;
 import com.bumptech.glide.Glide;
@@ -219,7 +217,8 @@
 
     @Override
     public View getView(Context context, View recycled, int thumbWidth, int thumbHeight,
-            int placeHolderResourceId, LocalDataAdapter adapter, boolean isInProgress) {
+            int placeHolderResourceId, LocalDataAdapter adapter, boolean isInProgress,
+            ActionCallback actionCallback) {
         final ImageView imageView;
         if (recycled != null) {
             imageView = (ImageView) recycled;
@@ -842,7 +841,8 @@
         @Override
         public View getView(final Context context, View recycled,
                 int thumbWidth, int thumbHeight, int placeHolderResourceId,
-                LocalDataAdapter adapter, boolean isInProgress) {
+                LocalDataAdapter adapter, boolean isInProgress,
+                final ActionCallback actionCallback) {
 
             final VideoViewHolder viewHolder;
             final View result;
@@ -865,9 +865,7 @@
             viewHolder.mPlayButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    // TODO: refactor this into activities to avoid this class
-                    // conversion.
-                    CameraUtil.playVideo((Activity) context, getUri(), mTitle);
+                    actionCallback.playVideo(getUri(), mTitle);
                 }
             });
 
diff --git a/src/com/android/camera/data/LocalSessionData.java b/src/com/android/camera/data/LocalSessionData.java
index 8254baa..8a5d6c6 100644
--- a/src/com/android/camera/data/LocalSessionData.java
+++ b/src/com/android/camera/data/LocalSessionData.java
@@ -26,7 +26,6 @@
 import com.android.camera.Storage;
 import com.android.camera2.R;
 import com.bumptech.glide.Glide;
-import com.bumptech.glide.load.DecodeFormat;
 
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
@@ -37,9 +36,9 @@
  */
 public class LocalSessionData implements LocalData {
 
-    private Uri mUri;
+    private final Uri mUri;
     // Units are GMT epoch milliseconds.
-    private long mDateTaken;
+    private final long mDateTaken;
     protected final Bundle mMetaData;
     private int mWidth;
     private int mHeight;
@@ -59,7 +58,8 @@
 
     @Override
     public View getView(Context context, View recycled, int thumbWidth, int thumbHeight,
-            int placeholderResourcedId, LocalDataAdapter adapter, boolean isInProgress) {
+            int placeholderResourcedId, LocalDataAdapter adapter, boolean isInProgress,
+            ActionCallback actionCallback) {
         final ImageView imageView;
         if (recycled != null) {
             imageView = (ImageView) recycled;
diff --git a/src/com/android/camera/data/SimpleViewData.java b/src/com/android/camera/data/SimpleViewData.java
index 74f1073..3b60958 100644
--- a/src/com/android/camera/data/SimpleViewData.java
+++ b/src/com/android/camera/data/SimpleViewData.java
@@ -17,7 +17,6 @@
 package com.android.camera.data;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.view.View;
@@ -135,8 +134,9 @@
     }
 
     @Override
-    public View getView(Context context, View recycled, int width, int height, int placeHolderResourceId,
-            LocalDataAdapter adapter, boolean isInProgressSession) {
+    public View getView(Context context, View recycled, int width, int height,
+            int placeHolderResourceId, LocalDataAdapter adapter, boolean isInProgressSession,
+            ActionCallback actionCallback) {
         return mView;
     }
 
diff --git a/src/com/android/camera/filmstrip/DataAdapter.java b/src/com/android/camera/filmstrip/DataAdapter.java
index e1ca61d..65ae48a 100644
--- a/src/com/android/camera/filmstrip/DataAdapter.java
+++ b/src/com/android/camera/filmstrip/DataAdapter.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.view.View;
 
+import com.android.camera.data.LocalData.ActionCallback;
+
 /**
  * An interface which defines the interactions between the
  * {@link ImageData} and the
@@ -85,7 +87,7 @@
      * @return The view representing the image data. Null if unavailable or
      *         the {@code dataID} is out of range.
      */
-    public View getView(Context context, View recycled, int dataID);
+    public View getView(Context context, View recycled, int dataID, ActionCallback actionCallback);
 
     /** Returns a unique identifier for the view created by this data so that the view
      * can be reused.
diff --git a/src/com/android/camera/widget/FilmstripView.java b/src/com/android/camera/widget/FilmstripView.java
index 70c2b86..8743c43 100644
--- a/src/com/android/camera/widget/FilmstripView.java
+++ b/src/com/android/camera/widget/FilmstripView.java
@@ -21,6 +21,7 @@
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
+import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -42,6 +43,7 @@
 import android.widget.Scroller;
 
 import com.android.camera.CameraActivity;
+import com.android.camera.data.LocalData.ActionCallback;
 import com.android.camera.debug.Log;
 import com.android.camera.filmstrip.DataAdapter;
 import com.android.camera.filmstrip.FilmstripController;
@@ -52,11 +54,39 @@
 import com.android.camera.util.CameraUtil;
 import com.android.camera2.R;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Queue;
 
 public class FilmstripView extends ViewGroup {
+    /**
+     * An action callback to be used for actions on the local media data items.
+     */
+    public static class ActionCallbackImpl implements ActionCallback {
+        private final WeakReference<Activity> mActivity;
+
+        /**
+         * The given activity is used to start intents. It is wrapped in a weak
+         * reference to prevent leaks.
+         */
+        public ActionCallbackImpl(Activity activity) {
+            mActivity = new WeakReference<Activity>(activity);
+        }
+
+        /**
+         * Fires an intent to play the video with the given URI and title.
+         */
+        @Override
+        public void playVideo(Uri uri, String title) {
+            Activity activity = mActivity.get();
+            if (activity != null) {
+              CameraUtil.playVideo(activity, uri, title);
+            }
+        }
+    }
+
+
     private static final Log.Tag TAG = new Log.Tag("FilmstripView");
 
     private static final int BUFFER_SIZE = 5;
@@ -87,6 +117,7 @@
     private static final int DECELERATION_FACTOR = 4;
 
     private CameraActivity mActivity;
+    private ActionCallback mActionCallback;
     private FilmstripGestureRecognizer mGestureRecognizer;
     private FilmstripGestureRecognizer.Listener mGestureListener;
     private DataAdapter mDataAdapter;
@@ -585,6 +616,7 @@
     private void init(CameraActivity cameraActivity) {
         setWillNotDraw(false);
         mActivity = cameraActivity;
+        mActionCallback = new ActionCallbackImpl(mActivity);
         mScale = 1.0f;
         mDataIdOnUserScrolling = 0;
         mController = new MyController(cameraActivity);
@@ -813,7 +845,8 @@
 
         data.prepare();
         View recycled = getRecycledView(dataID);
-        View v = mDataAdapter.getView(mActivity.getAndroidContext(), recycled, dataID);
+        View v = mDataAdapter.getView(mActivity.getAndroidContext(), recycled, dataID,
+                mActionCallback);
         if (v == null) {
             return null;
         }