OSDN Git Service

Add prominent highlights for touch feedback.
authorYuli Huang <yuli@google.com>
Tue, 24 Apr 2012 07:20:28 +0000 (15:20 +0800)
committerYuli Huang <yuli@google.com>
Tue, 24 Apr 2012 07:20:28 +0000 (15:20 +0800)
Mimic the system UI to fade out highlights on touch releases.
bug:6145331
bug:5379176

Change-Id: I44c9245a926b2c5eb46b28d494c6393ba7f0c30c

src/com/android/gallery3d/app/AlbumPage.java
src/com/android/gallery3d/app/AlbumSetPage.java
src/com/android/gallery3d/app/ManageCachePage.java
src/com/android/gallery3d/ui/AbstractSlotRenderer.java
src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java
src/com/android/gallery3d/ui/AlbumSlotRenderer.java
src/com/android/gallery3d/ui/FadeInTexture.java
src/com/android/gallery3d/ui/FadeOutTexture.java [new file with mode: 0644]
src/com/android/gallery3d/ui/FadeTexture.java [new file with mode: 0644]
src/com/android/gallery3d/ui/SlotView.java

index 158070f..c3b04d6 100644 (file)
@@ -22,6 +22,8 @@ import android.content.Intent;
 import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.os.Vibrator;
 import android.provider.MediaStore;
 import android.view.ActionMode;
@@ -44,6 +46,7 @@ import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
 import com.android.gallery3d.ui.AlbumSlotRenderer;
 import com.android.gallery3d.ui.DetailsHelper;
 import com.android.gallery3d.ui.DetailsHelper.CloseListener;
+import com.android.gallery3d.ui.FadeTexture;
 import com.android.gallery3d.ui.GLCanvas;
 import com.android.gallery3d.ui.GLRoot;
 import com.android.gallery3d.ui.GLView;
@@ -51,6 +54,7 @@ import com.android.gallery3d.ui.RelativePosition;
 import com.android.gallery3d.ui.ScreenNailHolder;
 import com.android.gallery3d.ui.SelectionManager;
 import com.android.gallery3d.ui.SlotView;
+import com.android.gallery3d.ui.SynchronizedHandler;
 import com.android.gallery3d.util.Future;
 import com.android.gallery3d.util.GalleryUtils;
 
@@ -59,6 +63,8 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
     @SuppressWarnings("unused")
     private static final String TAG = "AlbumPage";
 
+    private static final int MSG_PICK_PHOTO = 1;
+
     public static final String KEY_MEDIA_PATH = "media-path";
     public static final String KEY_PARENT_MEDIA_PATH = "parent-media-path";
     public static final String KEY_SET_CENTER = "set-center";
@@ -97,6 +103,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
     private MediaSet mMediaSet;
     private boolean mShowDetails;
     private float mUserDistance; // in pixel
+    private Handler mHandler;
 
     private Future<Integer> mSyncTask = null;
 
@@ -159,46 +166,56 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
         mAlbumView.setPressedIndex(index);
     }
 
-    private void onUp() {
-        mAlbumView.setPressedIndex(-1);
+    private void onUp(boolean followedByLongPress) {
+        if (followedByLongPress) {
+            // Avoid showing press-up animations for long-press.
+            mAlbumView.setPressedIndex(-1);
+        } else {
+            mAlbumView.setPressedUp();
+        }
     }
 
     private void onSingleTapUp(int slotIndex) {
         if (!mIsActive) return;
-        MediaItem item = mAlbumDataAdapter.get(slotIndex);
-        if (item == null) {
-            Log.w(TAG, "item not ready yet, ignore the click");
-            return;
-        }
-        if (mShowDetails) {
-            mAlbumView.setHighlightItemPath(item.getPath());
-            mDetailsHelper.reloadDetails(slotIndex);
-        } else if (!mSelectionManager.inSelectionMode()) {
-            if (mGetContent) {
-                onGetContent(item);
-            } else {
-                // Get into the PhotoPage.
-                Bundle data = new Bundle();
 
-                // mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
-                data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex);
-                data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT,
-                        getSlotRect(slotIndex));
-                data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
-                        mMediaSetPath.toString());
-                data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
-                        item.getPath().toString());
-                if (TEST_CAMERA_PREVIEW) {
-                    ScreenNailHolder holder = new CameraScreenNailHolder(mActivity);
-                    data.putParcelable(PhotoPage.KEY_SCREENNAIL_HOLDER, holder);
-                }
-                mActivity.getStateManager().startStateForResult(
-                        PhotoPage.class, REQUEST_PHOTO, data);
-            }
-        } else {
+        if (mSelectionManager.inSelectionMode()) {
+            MediaItem item = mAlbumDataAdapter.get(slotIndex);
+            if (item == null) return; // Item not ready yet, ignore the click
             mSelectionManager.toggle(item.getPath());
-            mDetailsSource.findIndex(slotIndex);
             mSlotView.invalidate();
+        } else {
+            // Show pressed-up animation for the single-tap.
+            mAlbumView.setPressedIndex(slotIndex);
+            mAlbumView.setPressedUp();
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0),
+                    FadeTexture.DURATION);
+        }
+    }
+
+    private void pickPhoto(int slotIndex) {
+        if (!mIsActive) return;
+
+        MediaItem item = mAlbumDataAdapter.get(slotIndex);
+        if (item == null) return; // Item not ready yet, ignore the click
+        if (mGetContent) {
+            onGetContent(item);
+        } else {
+            // Get into the PhotoPage.
+            // mAlbumView.savePositions(PositionRepository.getInstance(mActivity));
+            Bundle data = new Bundle();
+            data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex);
+            data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT,
+                    getSlotRect(slotIndex));
+            data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
+                    mMediaSetPath.toString());
+            data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
+                    item.getPath().toString());
+            if (TEST_CAMERA_PREVIEW) {
+                ScreenNailHolder holder = new CameraScreenNailHolder(mActivity);
+                data.putParcelable(PhotoPage.KEY_SCREENNAIL_HOLDER, holder);
+            }
+            mActivity.getStateManager().startStateForResult(
+                    PhotoPage.class, REQUEST_PHOTO, data);
         }
     }
 
@@ -235,16 +252,11 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
 
     public void onLongTap(int slotIndex) {
         if (mGetContent) return;
-        if (mShowDetails) {
-            onSingleTapUp(slotIndex);
-        } else {
-            MediaItem item = mAlbumDataAdapter.get(slotIndex);
-            if (item == null) return;
-            mSelectionManager.setAutoLeaveSelectionMode(true);
-            mSelectionManager.toggle(item.getPath());
-            mDetailsSource.findIndex(slotIndex);
-            mSlotView.invalidate();
-        }
+        MediaItem item = mAlbumDataAdapter.get(slotIndex);
+        if (item == null) return;
+        mSelectionManager.setAutoLeaveSelectionMode(true);
+        mSelectionManager.toggle(item.getPath());
+        mSlotView.invalidate();
     }
 
     @Override
@@ -289,6 +301,19 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
                 mSlotView.startScatteringAnimation(mOpenCenter);
             }
         }
+
+        mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
+            @Override
+            public void handleMessage(Message message) {
+                switch (message.what) {
+                    case MSG_PICK_PHOTO: {
+                        pickPhoto(message.arg1);
+                        break;
+                    }
+                    default: throw new AssertionError(message.what);
+                }
+            }
+        };
     }
 
     @Override
@@ -354,8 +379,8 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
             }
 
             @Override
-            public void onUp() {
-                AlbumPage.this.onUp();
+            public void onUp(boolean followedByLongPress) {
+                AlbumPage.this.onUp(followedByLongPress);
             }
 
             @Override
index 4c5a49b..f8274ca 100644 (file)
@@ -21,6 +21,8 @@ import android.content.Context;
 import android.content.Intent;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.os.Vibrator;
 import android.provider.MediaStore;
 import android.view.ActionMode;
@@ -43,11 +45,13 @@ import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
 import com.android.gallery3d.ui.AlbumSetSlotRenderer;
 import com.android.gallery3d.ui.DetailsHelper;
 import com.android.gallery3d.ui.DetailsHelper.CloseListener;
+import com.android.gallery3d.ui.FadeTexture;
 import com.android.gallery3d.ui.GLCanvas;
 import com.android.gallery3d.ui.GLRoot;
 import com.android.gallery3d.ui.GLView;
 import com.android.gallery3d.ui.SelectionManager;
 import com.android.gallery3d.ui.SlotView;
+import com.android.gallery3d.ui.SynchronizedHandler;
 import com.android.gallery3d.util.Future;
 import com.android.gallery3d.util.GalleryUtils;
 
@@ -57,6 +61,8 @@ public class AlbumSetPage extends ActivityState implements
     @SuppressWarnings("unused")
     private static final String TAG = "AlbumSetPage";
 
+    private static final int MSG_PICK_ALBUM = 1;
+
     public static final String KEY_MEDIA_PATH = "media-path";
     public static final String KEY_SET_TITLE = "set-title";
     public static final String KEY_SET_SUBTITLE = "set-subtitle";
@@ -91,6 +97,7 @@ public class AlbumSetPage extends ActivityState implements
     private MyDetailsSource mDetailsSource;
     private boolean mShowDetails;
     private EyePosition mEyePosition;
+    private Handler mHandler;
 
     // The eyes' position of the user, the origin is at the center of the
     // device and the unit is in pixels.
@@ -173,43 +180,53 @@ public class AlbumSetPage extends ActivityState implements
 
     public void onSingleTapUp(int slotIndex) {
         if (!mIsActive) return;
+
+        if (mSelectionManager.inSelectionMode()) {
+            MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
+            if (targetSet == null) return; // Content is dirty, we shall reload soon
+            mSelectionManager.toggle(targetSet.getPath());
+            mSlotView.invalidate();
+        } else {
+            // Show pressed-up animation for the single-tap.
+            mAlbumSetView.setPressedIndex(slotIndex);
+            mAlbumSetView.setPressedUp();
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_ALBUM, slotIndex, 0),
+                    FadeTexture.DURATION);
+        }
+    }
+
+    private void pickAlbum(int slotIndex) {
+        if (!mIsActive) return;
+
         MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex);
         if (targetSet == null) return; // Content is dirty, we shall reload soon
+        String mediaPath = targetSet.getPath().toString();
 
-        if (mShowDetails) {
-            mAlbumSetView.setHighlightItemPath(targetSet.getPath());
-            mDetailsHelper.reloadDetails(slotIndex);
-        } else if (!mSelectionManager.inSelectionMode()) {
-            Bundle data = new Bundle(getData());
-            String mediaPath = targetSet.getPath().toString();
-            int[] center = new int[2];
-            getSlotCenter(slotIndex, center);
-            data.putIntArray(AlbumPage.KEY_SET_CENTER, center);
-            if (mGetAlbum && targetSet.isLeafAlbum()) {
-                Activity activity = (Activity) mActivity;
-                Intent result = new Intent()
-                        .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString());
-                activity.setResult(Activity.RESULT_OK, result);
-                activity.finish();
-            } else if (targetSet.getSubMediaSetCount() > 0) {
-                data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
-                mActivity.getStateManager().startStateForResult(
-                        AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
-            } else {
-                if (!mGetContent && (targetSet.getSupportedOperations()
-                        & MediaObject.SUPPORT_IMPORT) != 0) {
-                    data.putBoolean(AlbumPage.KEY_AUTO_SELECT_ALL, true);
-                }
-                data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);
-                boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
-                // We only show cluster menu in the first AlbumPage in stack
-                data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum);
-                mActivity.getStateManager().startStateForResult(
-                        AlbumPage.class, REQUEST_DO_ANIMATION, data);
-            }
+        Bundle data = new Bundle(getData());
+        int[] center = new int[2];
+        getSlotCenter(slotIndex, center);
+        data.putIntArray(AlbumPage.KEY_SET_CENTER, center);
+        if (mGetAlbum && targetSet.isLeafAlbum()) {
+            Activity activity = (Activity) mActivity;
+            Intent result = new Intent()
+                    .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString());
+            activity.setResult(Activity.RESULT_OK, result);
+            activity.finish();
+        } else if (targetSet.getSubMediaSetCount() > 0) {
+            data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath);
+            mActivity.getStateManager().startStateForResult(
+                    AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
         } else {
-            mSelectionManager.toggle(targetSet.getPath());
-            mSlotView.invalidate();
+            if (!mGetContent && (targetSet.getSupportedOperations()
+                    & MediaObject.SUPPORT_IMPORT) != 0) {
+                data.putBoolean(AlbumPage.KEY_AUTO_SELECT_ALL, true);
+            }
+            data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath);
+            boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class);
+            // We only show cluster menu in the first AlbumPage in stack
+            data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum);
+            mActivity.getStateManager().startStateForResult(
+                    AlbumPage.class, REQUEST_DO_ANIMATION, data);
         }
     }
 
@@ -217,22 +234,22 @@ public class AlbumSetPage extends ActivityState implements
         mAlbumSetView.setPressedIndex(index);
     }
 
-    private void onUp() {
-        mAlbumSetView.setPressedIndex(-1);
+    private void onUp(boolean followedByLongPress) {
+        if (followedByLongPress) {
+            // Avoid showing press-up animations for long-press.
+            mAlbumSetView.setPressedIndex(-1);
+        } else {
+            mAlbumSetView.setPressedUp();
+        }
     }
 
     public void onLongTap(int slotIndex) {
         if (mGetContent || mGetAlbum) return;
-        if (mShowDetails) {
-            onSingleTapUp(slotIndex);
-        } else {
-            MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex);
-            if (set == null) return;
-            mSelectionManager.setAutoLeaveSelectionMode(true);
-            mSelectionManager.toggle(set.getPath());
-            mDetailsSource.findIndex(slotIndex);
-            mSlotView.invalidate();
-        }
+        MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex);
+        if (set == null) return;
+        mSelectionManager.setAutoLeaveSelectionMode(true);
+        mSelectionManager.toggle(set.getPath());
+        mSlotView.invalidate();
     }
 
     @Override
@@ -260,6 +277,19 @@ public class AlbumSetPage extends ActivityState implements
         mActionBar = mActivity.getGalleryActionBar();
         mSelectedAction = data.getInt(AlbumSetPage.KEY_SELECTED_CLUSTER_TYPE,
                 FilterUtils.CLUSTER_BY_ALBUM);
+
+        mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
+            @Override
+            public void handleMessage(Message message) {
+                switch (message.what) {
+                    case MSG_PICK_ALBUM: {
+                        pickAlbum(message.arg1);
+                        break;
+                    }
+                    default: throw new AssertionError(message.what);
+                }
+            }
+        };
     }
 
     private void clearLoadingBit(int loadingBit) {
@@ -355,8 +385,8 @@ public class AlbumSetPage extends ActivityState implements
             }
 
             @Override
-            public void onUp() {
-                AlbumSetPage.this.onUp();
+            public void onUp(boolean followedByLongPress) {
+                AlbumSetPage.this.onUp(followedByLongPress);
             }
 
             @Override
index 94ebf92..f97958e 100644 (file)
@@ -58,7 +58,6 @@ public class ManageCachePage extends ActivityState implements
 
     private static final String TAG = "ManageCachePage";
 
-    private static final float USER_DISTANCE_METER = 0.3f;
     private static final int DATA_CACHE_SIZE = 256;
     private static final int MSG_REFRESH_STORAGE_INFO = 1;
     private static final int MSG_REQUEST_LAYOUT = 2;
@@ -70,7 +69,6 @@ public class ManageCachePage extends ActivityState implements
     protected SelectionManager mSelectionManager;
     protected ManageCacheDrawer mSelectionDrawer;
     private AlbumSetDataLoader mAlbumSetDataAdapter;
-    private float mUserDistance; // in pixel
 
     private EyePosition mEyePosition;
 
@@ -265,7 +263,6 @@ public class ManageCachePage extends ActivityState implements
     }
 
     private void initializeData(Bundle data) {
-        mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER);
         String mediaPath = data.getString(ManageCachePage.KEY_MEDIA_PATH);
         mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
         mSelectionManager.setSourceMediaSet(mMediaSet);
@@ -297,7 +294,7 @@ public class ManageCachePage extends ActivityState implements
             }
 
             @Override
-            public void onUp() {
+            public void onUp(boolean followedByLongPress) {
                 ManageCachePage.this.onUp();
             }
 
index fecb70f..98eae56 100644 (file)
@@ -28,6 +28,7 @@ public abstract class AbstractSlotRenderer implements SlotView.SlotRenderer {
     private final NinePatchTexture mPanoramaBorder;
     private final NinePatchTexture mFramePressed;
     private final NinePatchTexture mFrameSelected;
+    private FadeOutTexture mFramePressedUp;
 
     protected AbstractSlotRenderer(Context context) {
         mVideoOverlay = new ResourceTexture(context, R.drawable.ic_video_thumb);
@@ -85,18 +86,35 @@ public abstract class AbstractSlotRenderer implements SlotView.SlotRenderer {
         mPanoramaBorder.draw(canvas, 0, height - h, w, h);
     }
 
+    protected boolean isPressedUpFrameFinished() {
+        if (mFramePressedUp != null) {
+            if (mFramePressedUp.isAnimating()) {
+                return false;
+            } else {
+                mFramePressedUp = null;
+            }
+        }
+        return true;
+    }
+
+    protected void drawPressedUpFrame(GLCanvas canvas, int width, int height) {
+        if (mFramePressedUp == null) {
+            mFramePressedUp = new FadeOutTexture(mFramePressed);
+        }
+        drawFrame(canvas, mFramePressed.getPaddings(), mFramePressedUp, 0, 0, width, height);
+    }
+
     protected void drawPressedFrame(GLCanvas canvas, int width, int height) {
-        drawFrame(canvas, mFramePressed, 0, 0, width, height);
+        drawFrame(canvas, mFramePressed.getPaddings(), mFramePressed, 0, 0, width, height);
     }
 
     protected void drawSelectedFrame(GLCanvas canvas, int width, int height) {
-        drawFrame(canvas, mFrameSelected, 0, 0, width, height);
+        drawFrame(canvas, mFrameSelected.getPaddings(), mFrameSelected, 0, 0, width, height);
     }
 
-    protected static void drawFrame(GLCanvas canvas, NinePatchTexture frame,
+    protected static void drawFrame(GLCanvas canvas, Rect padding, Texture frame,
             int x, int y, int width, int height) {
-        Rect p = frame.getPaddings();
-        frame.draw(canvas, x - p.left, y - p.top, width + p.left + p.right,
-                 height + p.top + p.bottom);
+        frame.draw(canvas, x - padding.left, y - padding.top, width + padding.left + padding.right,
+                 height + padding.top + padding.bottom);
     }
 }
index d20c387..b0e6153 100644 (file)
@@ -39,6 +39,7 @@ public class AlbumSetSlotRenderer extends AbstractSlotRenderer {
     private SlotView mSlotView;
 
     private int mPressedIndex = -1;
+    private boolean mAnimatePressedUp;
     private Path mHighlightItemPath = null;
     private boolean mInSelectionMode;
 
@@ -72,6 +73,12 @@ public class AlbumSetSlotRenderer extends AbstractSlotRenderer {
         mSlotView.invalidate();
     }
 
+    public void setPressedUp() {
+        if (mPressedIndex == -1) return;
+        mAnimatePressedUp = true;
+        mSlotView.invalidate();
+    }
+
     public void setHighlightItemPath(Path path) {
         if (mHighlightItemPath == path) return;
         mHighlightItemPath = path;
@@ -111,15 +118,24 @@ public class AlbumSetSlotRenderer extends AbstractSlotRenderer {
 
     protected int renderOverlay(
             GLCanvas canvas, int index, AlbumSetEntry entry, int width, int height) {
-        Path path = entry.setPath;
+        int renderRequestFlags = 0;
         if (mPressedIndex == index) {
-            drawPressedFrame(canvas, width, height);
-        } else if ((path != null) && (mHighlightItemPath == path)) {
+            if (mAnimatePressedUp) {
+                drawPressedUpFrame(canvas, width, height);
+                renderRequestFlags |= SlotView.RENDER_MORE_FRAME;
+                if (isPressedUpFrameFinished()) {
+                    mAnimatePressedUp = false;
+                    mPressedIndex = -1;
+                }
+            } else {
+                drawPressedFrame(canvas, width, height);
+            }
+        } else if ((mHighlightItemPath != null) && (mHighlightItemPath == entry.setPath)) {
             drawSelectedFrame(canvas, width, height);
-        } else if (mInSelectionMode && mSelectionManager.isItemSelected(path)) {
+        } else if (mInSelectionMode && mSelectionManager.isItemSelected(entry.setPath)) {
             drawSelectedFrame(canvas, width, height);
         }
-        return 0;
+        return renderRequestFlags;
     }
 
     protected int renderContent(
index f996a82..922e2c3 100644 (file)
@@ -37,6 +37,7 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer {
     private final SelectionManager mSelectionManager;
 
     private int mPressedIndex = -1;
+    private boolean mAnimatePressedUp;
     private Path mHighlightItemPath = null;
     private boolean mInSelectionMode;
 
@@ -57,6 +58,12 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer {
         mSlotView.invalidate();
     }
 
+    public void setPressedUp() {
+        if (mPressedIndex == -1) return;
+        mAnimatePressedUp = true;
+        mSlotView.invalidate();
+    }
+
     public void setHighlightItemPath(Path path) {
         if (mHighlightItemPath == path) return;
         mHighlightItemPath = path;
@@ -113,14 +120,30 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer {
             drawPanoramaBorder(canvas, width, height);
         }
 
+        renderRequestFlags |= renderOverlay(canvas, index, entry, width, height);
+
+        return renderRequestFlags;
+    }
+
+    private int renderOverlay(GLCanvas canvas, int index,
+            AlbumSlidingWindow.AlbumEntry entry, int width, int height) {
+        int renderRequestFlags = 0;
         if (mPressedIndex == index) {
-            drawPressedFrame(canvas, width, height);
+            if (mAnimatePressedUp) {
+                drawPressedUpFrame(canvas, width, height);
+                renderRequestFlags |= SlotView.RENDER_MORE_FRAME;
+                if (isPressedUpFrameFinished()) {
+                    mAnimatePressedUp = false;
+                    mPressedIndex = -1;
+                }
+            } else {
+                drawPressedFrame(canvas, width, height);
+            }
         } else if ((entry.path != null) && (mHighlightItemPath == entry.path)) {
             drawSelectedFrame(canvas, width, height);
         } else if (mInSelectionMode && mSelectionManager.isItemSelected(entry.path)) {
             drawSelectedFrame(canvas, width, height);
         }
-
         return renderRequestFlags;
     }
 
index 17ab715..648bdcf 100644 (file)
 
 package com.android.gallery3d.ui;
 
-import com.android.gallery3d.common.Utils;
-
 // FadeInTexture is a texture which begins with a color, then gradually animates
 // into a given texture.
-public class FadeInTexture implements Texture {
+public class FadeInTexture extends FadeTexture implements Texture {
     @SuppressWarnings("unused")
     private static final String TAG = "FadeInTexture";
 
-    // The duration of the animation in milliseconds
-    private static final int DURATION = 180;
-
-    private final BasicTexture mTexture;
     private final int mColor;
-    private final long mStartTime;
-    private final int mWidth;
-    private final int mHeight;
-    private final boolean mIsOpaque;
-    private boolean mIsAnimating;
 
     public FadeInTexture(int color, BasicTexture texture) {
+        super(texture);
         mColor = color;
-        mTexture = texture;
-        mWidth = mTexture.getWidth();
-        mHeight = mTexture.getHeight();
-        mIsOpaque = mTexture.isOpaque();
-        mStartTime = now();
-        mIsAnimating = true;
-    }
-
-    public void draw(GLCanvas canvas, int x, int y) {
-        draw(canvas, x, y, mWidth, mHeight);
     }
 
+    @Override
     public void draw(GLCanvas canvas, int x, int y, int w, int h) {
         if (isAnimating()) {
             canvas.drawMixed(mTexture, mColor, getRatio(), x, y, w, h);
@@ -56,34 +37,4 @@ public class FadeInTexture implements Texture {
             mTexture.draw(canvas, x, y, w, h);
         }
     }
-
-    public boolean isOpaque() {
-        return mIsOpaque;
-    }
-
-    public int getWidth() {
-        return mWidth;
-    }
-
-    public int getHeight() {
-        return mHeight;
-    }
-
-    public boolean isAnimating() {
-        if (mIsAnimating) {
-            if (now() - mStartTime >= DURATION) {
-                mIsAnimating = false;
-            }
-        }
-        return mIsAnimating;
-    }
-
-    private float getRatio() {
-        float r = (float)(now() - mStartTime) / DURATION;
-        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
-    }
-
-    private long now() {
-        return AnimationTime.get();
-    }
 }
diff --git a/src/com/android/gallery3d/ui/FadeOutTexture.java b/src/com/android/gallery3d/ui/FadeOutTexture.java
new file mode 100644 (file)
index 0000000..c438977
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.ui;
+
+// FadeOutTexture is a texture which begins with a given texture, then gradually animates
+// into fading out totally.
+public class FadeOutTexture extends FadeTexture implements Texture {
+    @SuppressWarnings("unused")
+    private static final String TAG = "FadeOutTexture";
+
+    public FadeOutTexture(BasicTexture texture) {
+        super(texture);
+    }
+
+    @Override
+    public void draw(GLCanvas canvas, int x, int y, int w, int h) {
+        if (isAnimating()) {
+            canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
+            canvas.setAlpha(getRatio());
+            mTexture.draw(canvas, x, y, w, h);
+            canvas.restore();
+        }
+    }
+}
diff --git a/src/com/android/gallery3d/ui/FadeTexture.java b/src/com/android/gallery3d/ui/FadeTexture.java
new file mode 100644 (file)
index 0000000..ad0d358
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 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.gallery3d.ui;
+
+import com.android.gallery3d.common.Utils;
+
+// FadeTexture is a texture which fades the given texture along the time.
+public abstract class FadeTexture implements Texture {
+    @SuppressWarnings("unused")
+    private static final String TAG = "FadeTexture";
+
+    // The duration of the fading animation in milliseconds
+    public static final int DURATION = 180;
+
+    protected final BasicTexture mTexture;
+    private final long mStartTime;
+    private final int mWidth;
+    private final int mHeight;
+    private final boolean mIsOpaque;
+    private boolean mIsAnimating;
+
+    public FadeTexture(BasicTexture texture) {
+        mTexture = texture;
+        mWidth = mTexture.getWidth();
+        mHeight = mTexture.getHeight();
+        mIsOpaque = mTexture.isOpaque();
+        mStartTime = now();
+        mIsAnimating = true;
+    }
+
+    public void draw(GLCanvas canvas, int x, int y) {
+        draw(canvas, x, y, mWidth, mHeight);
+    }
+
+    /**
+     * Subclasses should implement how to fade the texture.
+     */
+    public abstract void draw(GLCanvas canvas, int x, int y, int w, int h);
+
+    public boolean isOpaque() {
+        return mIsOpaque;
+    }
+
+    public int getWidth() {
+        return mWidth;
+    }
+
+    public int getHeight() {
+        return mHeight;
+    }
+
+    public boolean isAnimating() {
+        if (mIsAnimating) {
+            if (now() - mStartTime >= DURATION) {
+                mIsAnimating = false;
+            }
+        }
+        return mIsAnimating;
+    }
+
+    protected float getRatio() {
+        float r = (float)(now() - mStartTime) / DURATION;
+        return Utils.clamp(1.0f - r, 0.0f, 1.0f);
+    }
+
+    private long now() {
+        return AnimationTime.get();
+    }
+}
index 26e885f..bf3a55d 100644 (file)
@@ -39,7 +39,7 @@ public class SlotView extends GLView {
 
     public interface Listener {
         public void onDown(int index);
-        public void onUp();
+        public void onUp(boolean followedByLongPress);
         public void onSingleTapUp(int index);
         public void onLongTap(int index);
         public void onScrollPositionChanged(int position, int total);
@@ -47,7 +47,7 @@ public class SlotView extends GLView {
 
     public static class SimpleListener implements Listener {
         @Override public void onDown(int index) {}
-        @Override public void onUp() {}
+        @Override public void onUp(boolean followedByLongPress) {}
         @Override public void onSingleTapUp(int index) {}
         @Override public void onLongTap(int index) {}
         @Override public void onScrollPositionChanged(int position, int total) {}
@@ -653,10 +653,10 @@ public class SlotView extends GLView {
             }
         }
 
-        private void cancelDown() {
+        private void cancelDown(boolean byLongPress) {
             if (!isDown) return;
             isDown = false;
-            mListener.onUp();
+            mListener.onUp(byLongPress);
         }
 
         @Override
@@ -667,7 +667,7 @@ public class SlotView extends GLView {
         @Override
         public boolean onFling(MotionEvent e1,
                 MotionEvent e2, float velocityX, float velocityY) {
-            cancelDown();
+            cancelDown(false);
             int scrollLimit = mLayout.getScrollLimit();
             if (scrollLimit == 0) return false;
             float velocity = WIDE ? velocityX : velocityY;
@@ -680,7 +680,7 @@ public class SlotView extends GLView {
         @Override
         public boolean onScroll(MotionEvent e1,
                 MotionEvent e2, float distanceX, float distanceY) {
-            cancelDown();
+            cancelDown(false);
             float distance = WIDE ? distanceX : distanceY;
             int overDistance = mScroller.startScroll(
                     Math.round(distance), 0, mLayout.getScrollLimit());
@@ -693,7 +693,7 @@ public class SlotView extends GLView {
 
         @Override
         public boolean onSingleTapUp(MotionEvent e) {
-            cancelDown();
+            cancelDown(false);
             if (mDownInScrolling) return true;
             int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY());
             if (index != INDEX_NONE) mListener.onSingleTapUp(index);
@@ -702,7 +702,7 @@ public class SlotView extends GLView {
 
         @Override
         public void onLongPress(MotionEvent e) {
-            cancelDown();
+            cancelDown(true);
             if (mDownInScrolling) return;
             lockRendering();
             try {