OSDN Git Service

Add transition animation for tapping from PhotoPage.
authorOwen Lin <owenlin@google.com>
Mon, 7 May 2012 08:35:53 +0000 (16:35 +0800)
committerOwen Lin <owenlin@google.com>
Thu, 17 May 2012 19:59:21 +0000 (12:59 -0700)
bug:6383694
Change-Id: Ib457d6b636dafd3f8ef7340bfa85725f14d90bd0

13 files changed:
src/com/android/gallery3d/app/AbstractGalleryActivity.java
src/com/android/gallery3d/app/ActivityState.java
src/com/android/gallery3d/app/AlbumPage.java
src/com/android/gallery3d/app/GalleryActivity.java
src/com/android/gallery3d/app/PhotoDataAdapter.java
src/com/android/gallery3d/app/PhotoPage.java
src/com/android/gallery3d/app/SinglePhotoDataAdapter.java
src/com/android/gallery3d/app/StateManager.java
src/com/android/gallery3d/app/TransitionStore.java [new file with mode: 0644]
src/com/android/gallery3d/ui/AlbumSlotRenderer.java
src/com/android/gallery3d/ui/PhotoFallbackEffect.java [new file with mode: 0644]
src/com/android/gallery3d/ui/PhotoView.java
src/com/android/gallery3d/ui/SlotView.java

index 4ee7403..f674c0b 100644 (file)
@@ -45,6 +45,7 @@ public class AbstractGalleryActivity extends Activity implements GalleryActivity
     private StateManager mStateManager;
     private GalleryActionBar mActionBar;
     private OrientationManager mOrientationManager;
+    private TransitionStore mTransitionStore = new TransitionStore();
     private boolean mDisableToggleStatusBar;
 
     private AlertDialog mAlertDialog = null;
@@ -260,4 +261,9 @@ public class AbstractGalleryActivity extends Activity implements GalleryActivity
             win.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
         }
     }
+
+    @Override
+    public TransitionStore getTransitionStore() {
+        return mTransitionStore;
+    }
 }
index 443e2bd..233b398 100644 (file)
@@ -59,6 +59,7 @@ abstract public class ActivityState {
 
     private boolean mDestroyed = false;
     private boolean mPlugged = false;
+    boolean mIsFinishing = false;
 
     protected ActivityState() {
     }
@@ -173,6 +174,9 @@ abstract public class ActivityState {
             activity.registerReceiver(mPowerIntentReceiver, filter);
         }
         onResume();
+
+        // the transition store should be cleared after resume;
+        mActivity.getTransitionStore().clear();
     }
 
     // a subclass of ActivityState should override the method to resume itself
@@ -196,4 +200,8 @@ abstract public class ActivityState {
     boolean isDestroyed() {
         return mDestroyed;
     }
+
+    public boolean isFinishing() {
+        return mIsFinishing;
+    }
 }
index df0124c..3033b93 100644 (file)
@@ -50,6 +50,7 @@ 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.PhotoFallbackEffect;
 import com.android.gallery3d.ui.RelativePosition;
 import com.android.gallery3d.ui.SelectionManager;
 import com.android.gallery3d.ui.SlotView;
@@ -70,6 +71,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
     public static final String KEY_SET_CENTER = "set-center";
     public static final String KEY_AUTO_SELECT_ALL = "auto-select-all";
     public static final String KEY_SHOW_CLUSTER_MENU = "cluster-menu";
+    public static final String KEY_RESUME_ANIMATION = "resume_animation";
 
     private static final int REQUEST_SLIDESHOW = 1;
     private static final int REQUEST_PHOTO = 2;
@@ -110,6 +112,30 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
     private boolean mInitialSynced = false;
     private RelativePosition mOpenCenter = new RelativePosition();
 
+    private PhotoFallbackEffect mResumeEffect;
+    private PhotoFallbackEffect.PositionProvider mPositionProvider =
+            new PhotoFallbackEffect.PositionProvider() {
+        @Override
+        public Rect getPosition(int index) {
+            Rect rect = mSlotView.getSlotRect(index);
+            Rect bounds = mSlotView.bounds();
+            rect.offset(bounds.left - mSlotView.getScrollX(),
+                    bounds.top - mSlotView.getScrollY());
+            return rect;
+        }
+
+        @Override
+        public int getItemIndex(Path path) {
+            int start = mSlotView.getVisibleStart();
+            int end = mSlotView.getVisibleEnd();
+            for (int i = start; i < end; ++i) {
+                MediaItem item = mAlbumDataAdapter.get(i);
+                if (item != null && item.getPath() == path) return i;
+            }
+            return -1;
+        }
+    };
+
     private final GLView mRootPane = new GLView() {
         private final float mMatrix[] = new float[16];
 
@@ -144,6 +170,16 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
             canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
             canvas.multiplyMatrix(mMatrix, 0);
             super.render(canvas);
+
+            if (mResumeEffect != null) {
+                boolean more = mResumeEffect.draw(canvas);
+                if (!more) {
+                    mResumeEffect = null;
+                    mAlbumView.setSlotFilter(null);
+                } else {
+                    invalidate();
+                }
+            }
             canvas.restore();
         }
     };
@@ -336,6 +372,14 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
     protected void onResume() {
         super.onResume();
         mIsActive = true;
+
+        mResumeEffect = mActivity.getTransitionStore().get(KEY_RESUME_ANIMATION);
+        if (mResumeEffect != null) {
+            mAlbumView.setSlotFilter(mResumeEffect);
+            mResumeEffect.setPositionProvider(mPositionProvider);
+            mResumeEffect.start();
+        }
+
         setContentPane(mRootPane);
 
         Path path = mMediaSet.getPath();
@@ -359,6 +403,9 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
     protected void onPause() {
         super.onPause();
         mIsActive = false;
+
+        mAlbumView.setSlotFilter(null);
+
         mAlbumDataAdapter.pause();
         mAlbumView.pause();
         DetailsHelper.pause();
@@ -549,7 +596,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster
                 if (data == null) return;
                 mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0);
                 mSlotView.makeSlotVisible(mFocusIndex);
-                mSlotView.startRestoringAnimation(mFocusIndex);
                 break;
             }
             case REQUEST_DO_ANIMATION: {
index 0c6375f..33c77fb 100644 (file)
@@ -23,4 +23,5 @@ public interface GalleryActivity extends GalleryContext {
     public GLRoot getGLRoot();
     public GalleryActionBar getGalleryActionBar();
     public OrientationManager getOrientationManager();
+    public TransitionStore getTransitionStore();
 }
index d88b72c..a0c4cdf 100644 (file)
@@ -469,8 +469,12 @@ public class PhotoDataAdapter implements PhotoPage.Model {
         return mCurrentIndex;
     }
 
-    public MediaItem getCurrentMediaItem() {
-        return mData[mCurrentIndex % DATA_CACHE_SIZE];
+    public MediaItem getMediaItem(int offset) {
+        int index = mCurrentIndex + offset;
+        if (index >= mContentStart && index < mContentEnd) {
+            return mData[index % DATA_CACHE_SIZE];
+        }
+        return null;
     }
 
     public void setCurrentPhoto(Path path, int indexHint) {
@@ -482,7 +486,7 @@ public class PhotoDataAdapter implements PhotoPage.Model {
         fireDataChange();
 
         // We need to reload content if the path doesn't match.
-        MediaItem item = getCurrentMediaItem();
+        MediaItem item = getMediaItem(0);
         if (item != null && item.getPath() != path) {
             if (mReloadTask != null) mReloadTask.notifyDirty();
         }
index 493e4aa..d344558 100644 (file)
@@ -37,6 +37,7 @@ import android.widget.ShareActionProvider;
 import android.widget.Toast;
 
 import com.android.gallery3d.R;
+import com.android.gallery3d.common.Utils;
 import com.android.gallery3d.data.DataManager;
 import com.android.gallery3d.data.MediaDetails;
 import com.android.gallery3d.data.MediaItem;
@@ -52,9 +53,12 @@ import com.android.gallery3d.ui.DetailsHelper;
 import com.android.gallery3d.ui.DetailsHelper.CloseListener;
 import com.android.gallery3d.ui.DetailsHelper.DetailsSource;
 import com.android.gallery3d.ui.GLCanvas;
+import com.android.gallery3d.ui.GLRoot;
+import com.android.gallery3d.ui.GLRoot.OnGLIdleListener;
 import com.android.gallery3d.ui.GLView;
 import com.android.gallery3d.ui.ImportCompleteListener;
 import com.android.gallery3d.ui.MenuExecutor;
+import com.android.gallery3d.ui.PhotoFallbackEffect;
 import com.android.gallery3d.ui.PhotoView;
 import com.android.gallery3d.ui.SelectionManager;
 import com.android.gallery3d.ui.SynchronizedHandler;
@@ -129,7 +133,6 @@ public class PhotoPage extends ActivityState implements
         public void resume();
         public void pause();
         public boolean isEmpty();
-        public MediaItem getCurrentMediaItem();
         public void setCurrentPhoto(Path path, int indexHint);
     }
 
@@ -223,7 +226,7 @@ public class PhotoPage extends ActivityState implements
                 public void onPhotoChanged(int index, Path item) {
                     mCurrentIndex = index;
                     if (item != null) {
-                        MediaItem photo = mModel.getCurrentMediaItem();
+                        MediaItem photo = mModel.getMediaItem(0);
                         if (photo != null) updateCurrentPhoto(photo);
                     }
                     updateBars();
@@ -232,7 +235,7 @@ public class PhotoPage extends ActivityState implements
                 @Override
                 public void onLoadingFinished() {
                     if (!mModel.isEmpty()) {
-                        MediaItem photo = mModel.getCurrentMediaItem();
+                        MediaItem photo = mModel.getMediaItem(0);
                         if (photo != null) updateCurrentPhoto(photo);
                     } else if (mIsActive) {
                         mActivity.getStateManager().finishState(PhotoPage.this);
@@ -519,7 +522,7 @@ public class PhotoPage extends ActivityState implements
 
     @Override
     protected boolean onItemSelected(MenuItem item) {
-        MediaItem current = mModel.getCurrentMediaItem();
+        MediaItem current = mModel.getMediaItem(0);
 
         if (current == null) {
             // item is not ready, ignore
@@ -624,7 +627,7 @@ public class PhotoPage extends ActivityState implements
             if (mAppBridge.onSingleTapUp(x, y)) return;
         }
 
-        MediaItem item = mModel.getCurrentMediaItem();
+        MediaItem item = mModel.getMediaItem(0);
         if (item == null || item == mScreenNailItem) {
             // item is not ready or it is camera preview, ignore
             return;
@@ -724,11 +727,49 @@ public class PhotoPage extends ActivityState implements
         }
     }
 
+    private class PreparePhotoFallback implements OnGLIdleListener {
+        private PhotoFallbackEffect mPhotoFallback = new PhotoFallbackEffect();
+        private boolean mResultReady = false;
+
+        public synchronized PhotoFallbackEffect get() {
+            while (!mResultReady) {
+                Utils.waitWithoutInterrupt(this);
+            }
+            return mPhotoFallback;
+        }
+
+        @Override
+        public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) {
+            mPhotoFallback = mPhotoView.buildFallbackEffect(mRootPane, canvas);
+            synchronized (this) {
+                mResultReady = true;
+                notifyAll();
+            }
+            return false;
+        }
+    }
+
+    private void preparePhotoFallbackView() {
+        GLRoot root = mActivity.getGLRoot();
+        PreparePhotoFallback task = new PreparePhotoFallback();
+        root.unlockRenderThread();
+        PhotoFallbackEffect anim;
+        try {
+            root.addOnGLIdleListener(task);
+            anim = task.get();
+        } finally {
+            root.lockRenderThread();
+        }
+        mActivity.getTransitionStore().put(
+                AlbumPage.KEY_RESUME_ANIMATION, anim);
+    }
+
     @Override
     public void onPause() {
         mActivity.getGLRoot().unfreeze();
         mHandler.removeMessages(MSG_UNFREEZE_GLROOT);
         super.onPause();
+        if (isFinishing()) preparePhotoFallbackView();
         mIsActive = false;
 
         DetailsHelper.pause();
@@ -789,7 +830,7 @@ public class PhotoPage extends ActivityState implements
 
         @Override
         public MediaDetails getDetails() {
-            return mModel.getCurrentMediaItem().getDetails();
+            return mModel.getMediaItem(0).getDetails();
         }
 
         @Override
index 4ee6a01..179c930 100644 (file)
@@ -194,8 +194,8 @@ public class SinglePhotoDataAdapter extends TileImageViewAdapter
         return mItem.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO;
     }
 
-    public MediaItem getCurrentMediaItem() {
-        return mItem;
+    public MediaItem getMediaItem(int offset) {
+        return offset == 0 ? mItem : null;
     }
 
     public int getCurrentIndex() {
index 096602a..02e9976 100644 (file)
@@ -175,6 +175,7 @@ public class StateManager {
 
         // Remove the top state.
         mStack.pop();
+        state.mIsFinishing = true;
         if (mIsResumed) state.onPause();
         mContext.getGLRoot().setContentPane(null);
         state.onDestroy();
diff --git a/src/com/android/gallery3d/app/TransitionStore.java b/src/com/android/gallery3d/app/TransitionStore.java
new file mode 100644 (file)
index 0000000..9c09e7b
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 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.app;
+
+import java.util.HashMap;
+
+public class TransitionStore {
+    private HashMap<Object, Object> mStorage = new HashMap<Object, Object>();
+
+    public void put(Object key, Object value) {
+        mStorage.put(key, value);
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T> T get(Object key) {
+        return (T) mStorage.get(key);
+    }
+
+    public void clear() {
+        mStorage.clear();
+    }
+}
index 922e2c3..5f1e3a1 100644 (file)
@@ -24,10 +24,14 @@ import com.android.gallery3d.data.MediaObject;
 import com.android.gallery3d.data.Path;
 
 public class AlbumSlotRenderer extends AbstractSlotRenderer {
-    private static final int PLACEHOLDER_COLOR = 0xFF222222;
-
     @SuppressWarnings("unused")
     private static final String TAG = "AlbumView";
+
+    public interface SlotFilter {
+        public boolean acceptSlot(int index);
+    }
+
+    private static final int PLACEHOLDER_COLOR = 0xFF222222;
     private static final int CACHE_SIZE = 96;
 
     private AlbumSlidingWindow mDataWindow;
@@ -41,6 +45,8 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer {
     private Path mHighlightItemPath = null;
     private boolean mInSelectionMode;
 
+    private SlotFilter mSlotFilter;
+
     public AlbumSlotRenderer(GalleryActivity activity, SlotView slotView,
             SelectionManager selectionManager) {
         super((Context) activity);
@@ -92,6 +98,8 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer {
 
     @Override
     public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height) {
+        if (mSlotFilter != null && !mSlotFilter.acceptSlot(index)) return 0;
+
         AlbumSlidingWindow.AlbumEntry entry = mDataWindow.get(index);
 
         int renderRequestFlags = 0;
@@ -183,4 +191,8 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer {
     public void onSlotSizeChanged(int width, int height) {
         // Do nothing
     }
+
+    public void setSlotFilter(SlotFilter slotFilter) {
+        mSlotFilter = slotFilter;
+    }
 }
diff --git a/src/com/android/gallery3d/ui/PhotoFallbackEffect.java b/src/com/android/gallery3d/ui/PhotoFallbackEffect.java
new file mode 100644 (file)
index 0000000..cd930bd
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2010 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 android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.android.gallery3d.anim.Animation;
+import com.android.gallery3d.data.Path;
+import com.android.gallery3d.ui.AlbumSlotRenderer.SlotFilter;
+
+import java.util.ArrayList;
+
+public class PhotoFallbackEffect extends Animation implements SlotFilter {
+
+    private static final int ANIM_DURATION = 300;
+    private static final Interpolator ANIM_INTERPOLATE = new DecelerateInterpolator(1.5f);
+
+    public static class Entry {
+        public int index;
+        public Path path;
+        public Rect source;
+        public Rect dest;
+        public RawTexture texture;
+
+        public Entry(Path path, Rect source, RawTexture texture) {
+            this.path = path;
+            this.source = source;
+            this.texture = texture;
+        }
+    }
+
+    public interface PositionProvider {
+        public Rect getPosition(int index);
+        public int getItemIndex(Path path);
+    }
+
+    private RectF mSource = new RectF();
+    private RectF mTarget = new RectF();
+    private float mProgress;
+    private PositionProvider mPositionProvider;
+
+    private ArrayList<Entry> mList = new ArrayList<Entry>();
+
+    public PhotoFallbackEffect() {
+        setDuration(ANIM_DURATION);
+        setInterpolator(ANIM_INTERPOLATE);
+    }
+
+    public void addEntry(Path path, Rect rect, RawTexture texture) {
+        mList.add(new Entry(path, rect, texture));
+    }
+
+    public Entry getEntry(Path path) {
+        for (int i = 0, n = mList.size(); i < n; ++i) {
+            Entry entry = mList.get(i);
+            if (entry.path == path) return entry;
+        }
+        return null;
+    }
+
+    public boolean draw(GLCanvas canvas) {
+        boolean more = calculate(AnimationTime.get());
+        for (int i = 0, n = mList.size(); i < n; ++i) {
+            Entry entry = mList.get(i);
+            if (entry.index < 0) continue;
+            entry.dest = mPositionProvider.getPosition(entry.index);
+            drawEntry(canvas, entry);
+        }
+        return more;
+    }
+
+    private void drawEntry(GLCanvas canvas, Entry entry) {
+        if (!entry.texture.isLoaded(canvas)) return;
+
+        int w = entry.texture.getWidth();
+        int h = entry.texture.getHeight();
+
+        Rect s = entry.source;
+        Rect d = entry.dest;
+
+        // the following calculation is based on d.width() == d.height()
+
+        float p = mProgress;
+
+        float fullScale = (float) d.height() / Math.min(s.width(), s.height());
+        float scale = fullScale * p + 1 * (1 - p);
+
+        float cx = d.centerX() * p + s.centerX() * (1 - p);
+        float cy = d.centerY() * p + s.centerY() * (1 - p);
+
+        float ch = s.height() * scale;
+        float cw = s.width() * scale;
+
+        if (w > h) {
+            // draw the center part
+            mTarget.set(cx - ch / 2, cy - ch / 2, cx + ch / 2, cy + ch / 2);
+            mSource.set((w - h) / 2, 0, (w + h) / 2, h);
+            canvas.drawTexture(entry.texture, mSource, mTarget);
+
+            canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
+            canvas.multiplyAlpha(1 - p);
+
+            // draw the left part
+            mTarget.set(cx - cw / 2, cy - ch / 2, cx - ch / 2, cy + ch / 2);
+            mSource.set(0, 0, (w - h) / 2, h);
+            canvas.drawTexture(entry.texture, mSource, mTarget);
+
+            // draw the right part
+            mTarget.set(cx + ch / 2, cy - ch / 2, cx + cw / 2, cy + ch / 2);
+            mSource.set((w + h) / 2, 0, w, h);
+            canvas.drawTexture(entry.texture, mSource, mTarget);
+
+            canvas.restore();
+        } else {
+            // draw the center part
+            mTarget.set(cx - cw / 2, cy - cw / 2, cx + cw / 2, cy + cw / 2);
+            mSource.set(0, (h - w) / 2, w, (h + w) / 2);
+            canvas.drawTexture(entry.texture, mSource, mTarget);
+
+            canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
+            canvas.multiplyAlpha(1 - p);
+
+            // draw the upper part
+            mTarget.set(cx - cw / 2, cy - ch / 2, cx + cw / 2, cy - cw / 2);
+            mSource.set(0, 0, w, (h - w) / 2);
+            canvas.drawTexture(entry.texture, mSource, mTarget);
+
+            // draw the bottom part
+            mTarget.set(cx - cw / 2, cy + cw / 2, cx + cw / 2, cy + ch / 2);
+            mSource.set(0, (w + h) / 2, w, h);
+            canvas.drawTexture(entry.texture, mSource, mTarget);
+
+            canvas.restore();
+        }
+    }
+
+    @Override
+    protected void onCalculate(float progress) {
+        mProgress = progress;
+    }
+
+    public void setPositionProvider(PositionProvider provider) {
+        mPositionProvider = provider;
+        if (mPositionProvider != null) {
+            for (int i = 0, n = mList.size(); i < n; ++i) {
+                Entry entry = mList.get(i);
+                entry.index = mPositionProvider.getItemIndex(entry.path);
+            }
+        }
+    }
+
+    @Override
+    public boolean acceptSlot(int index) {
+        for (int i = 0, n = mList.size(); i < n; ++i) {
+            Entry entry = mList.get(i);
+            if (entry.index == index) return false;
+        }
+        return true;
+    }
+}
index 7f3bee0..1610a12 100644 (file)
@@ -28,11 +28,10 @@ import android.view.animation.AccelerateInterpolator;
 import com.android.gallery3d.R;
 import com.android.gallery3d.app.GalleryActivity;
 import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.MediaItem;
 import com.android.gallery3d.data.MediaObject;
 import com.android.gallery3d.util.RangeArray;
 
-import java.util.Arrays;
-
 public class PhotoView extends GLView {
     @SuppressWarnings("unused")
     private static final String TAG = "PhotoView";
@@ -55,6 +54,9 @@ public class PhotoView extends GLView {
         // not avaiable, width = height = 0.
         public void getImageSize(int offset, Size size);
 
+        // Returns the media item for the specified picture.
+        public MediaItem getMediaItem(int offset);
+
         // Returns the rotation for the specified picture.
         public int getImageRotation(int offset);
 
@@ -1337,4 +1339,33 @@ public class PhotoView extends GLView {
     public void setListener(Listener listener) {
         mListener = listener;
     }
+
+    public Rect getPhotoRect(int index) {
+        return mPositionController.getPosition(index);
+    }
+
+
+    public PhotoFallbackEffect buildFallbackEffect(GLView root, GLCanvas canvas) {
+        Rect location = new Rect();
+        Utils.assertTrue(root.getBoundsOf(this, location));
+
+        Rect fullRect = bounds();
+        PhotoFallbackEffect effect = new PhotoFallbackEffect();
+        for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) {
+            MediaItem item = mModel.getMediaItem(i);
+            if (item == null) continue;
+            ScreenNail sc = mModel.getScreenNail(i);
+            if (sc == null) continue;
+            Rect rect = new Rect(getPhotoRect(i));
+            if (!Rect.intersects(fullRect, rect)) continue;
+            rect.offset(location.left, location.top);
+
+            RawTexture texture = new RawTexture(sc.getWidth(), sc.getHeight(), true);
+            canvas.beginRenderTarget(texture);
+            sc.draw(canvas, 0, 0, sc.getWidth(), sc.getHeight());
+            canvas.endRenderTarget();
+            effect.addEntry(item.getPath(), rect, texture);
+        }
+        return effect;
+    }
 }
index 0334c55..88a2e0d 100644 (file)
@@ -179,12 +179,6 @@ public class SlotView extends GLView {
         if (mLayout.mSlotCount != 0) invalidate();
     }
 
-    public void startRestoringAnimation(int targetIndex) {
-        mAnimation = new RestoringAnimation(targetIndex);
-        mAnimation.start();
-        if (mLayout.mSlotCount != 0) invalidate();
-    }
-
     private void updateScrollPosition(int position, boolean force) {
         if (!force && (WIDE ? position == mScrollX : position == mScrollY)) return;
         if (WIDE) {
@@ -378,22 +372,6 @@ public class SlotView extends GLView {
         }
     }
 
-    public static class RestoringAnimation extends SlotAnimation {
-        private static final int DISTANCE = 1000;
-        private int mTargetIndex;
-
-        public RestoringAnimation(int targetIndex) {
-            mTargetIndex = targetIndex;
-        }
-
-        @Override
-        public void apply(GLCanvas canvas, int slotIndex, Rect target) {
-            if (slotIndex == mTargetIndex) {
-                canvas.translate(0, 0, -DISTANCE * (1 - mProgress));
-            }
-        }
-    }
-
     // This Spec class is used to specify the size of each slot in the SlotView.
     // There are two ways to do it:
     //