OSDN Git Service

Big refactor, additions to state transition animations
authorBobby Georgescu <georgescu@google.com>
Wed, 17 Oct 2012 21:50:47 +0000 (14:50 -0700)
committerBobby Georgescu <georgescu@google.com>
Thu, 18 Oct 2012 00:14:22 +0000 (17:14 -0700)
Bug: 7362944
Refactored a lot of the state transitions code, adding
support for definable transition animations and defining
distinct outgoing and incoming animations.
Change-Id: I31a69057ea1b72dd3185cec656e59b11fdb528c1

src/com/android/gallery3d/anim/StateTransitionAnimation.java
src/com/android/gallery3d/app/ActivityState.java
src/com/android/gallery3d/app/StateManager.java
src/com/android/gallery3d/ui/GLView.java
src/com/android/gallery3d/ui/PositionController.java
src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java

index ffe753d..d4d59d3 100644 (file)
 package com.android.gallery3d.anim;
 
 import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
 
 import com.android.gallery3d.ui.GLCanvas;
 import com.android.gallery3d.ui.GLView;
 import com.android.gallery3d.ui.RawTexture;
+import com.android.gallery3d.ui.TiledScreenNail;
 
 public class StateTransitionAnimation extends Animation {
-    private static final float BACKGROUND_ALPHA_FROM = 1f;
-    private static final float BACKGROUND_ALPHA_TO = 0f;
-    private static final float BACKGROUND_SCALE_FROM = 1f;
-    private static final float BACKGROUND_SCALE_TO = 0f;
-    private static final float FOREGROUND_ALPHA_FROM = 0.9f;
-    private static final float FOREGROUND_ALPHA_TO = 1f;
-    private static final float FOREGROUND_SCALE_FROM = 3f;
-    private static final float FOREGROUND_SCALE_TO = 1f;
-
-    private float mCurrentForegroundScale;
+
+    public static class Spec {
+        public static final Spec OUTGOING;
+        public static final Spec INCOMING;
+
+        public int duration = 330;
+        public float backgroundAlphaFrom = 0;
+        public float backgroundAlphaTo = 0;
+        public float backgroundScaleFrom = 0;
+        public float backgroundScaleTo = 0;
+        public float contentAlphaFrom = 1;
+        public float contentAlphaTo = 1;
+        public float contentScaleFrom = 1;
+        public float contentScaleTo = 1;
+        public float overlayAlphaFrom = 0;
+        public float overlayAlphaTo = 0;
+        public float overlayScaleFrom = 0;
+        public float overlayScaleTo = 0;
+        public Interpolator interpolator;
+
+        static {
+            OUTGOING = new Spec();
+            OUTGOING.backgroundAlphaFrom = 1f;
+            OUTGOING.backgroundAlphaTo = 0f;
+            OUTGOING.backgroundScaleFrom = 1f;
+            OUTGOING.backgroundScaleTo = 0f;
+            OUTGOING.contentAlphaFrom = 0.9f;
+            OUTGOING.contentAlphaTo = 1f;
+            OUTGOING.contentScaleFrom = 3f;
+            OUTGOING.contentScaleTo = 1f;
+            OUTGOING.interpolator = new DecelerateInterpolator();
+
+            INCOMING = new Spec();
+            INCOMING.overlayAlphaFrom = 1f;
+            INCOMING.overlayAlphaTo = 0f;
+            INCOMING.overlayScaleFrom = 1f;
+            INCOMING.overlayScaleTo = 3f;
+            INCOMING.contentAlphaFrom = 0f;
+            INCOMING.contentAlphaTo = 1f;
+            INCOMING.contentScaleFrom = 0.25f;
+            INCOMING.contentScaleTo = 1f;
+            INCOMING.interpolator = new DecelerateInterpolator();
+        }
+    }
+
+    private final Spec mTransitionSpec;
+    private float mCurrentContentScale;
+    private float mCurrentContentAlpha;
     private float mCurrentBackgroundScale;
     private float mCurrentBackgroundAlpha;
-    private float mCurrentForegroundAlpha;
+    private float mCurrentOverlayScale;
+    private float mCurrentOverlayAlpha;
+    private RawTexture mOldScreenTexture;
 
-    public StateTransitionAnimation(int duration) {
-        setDuration(duration);
-        setInterpolator(new DecelerateInterpolator());
+    public StateTransitionAnimation(Spec spec, RawTexture oldScreen) {
+        mTransitionSpec = spec != null ? spec : Spec.OUTGOING;
+        setDuration(mTransitionSpec.duration);
+        setInterpolator(mTransitionSpec.interpolator);
+        mOldScreenTexture = oldScreen;
+        if (mOldScreenTexture != null) {
+            TiledScreenNail.disableDrawPlaceholder();
+        }
+    }
+
+    @Override
+    public boolean calculate(long currentTimeMillis) {
+        boolean retval = super.calculate(currentTimeMillis);
+        if (mOldScreenTexture != null && !isActive()) {
+            mOldScreenTexture.recycle();
+            mOldScreenTexture = null;
+            TiledScreenNail.enableDrawPlaceholder();
+        }
+        return retval;
     }
 
     @Override
     protected void onCalculate(float progress) {
-        mCurrentForegroundScale = FOREGROUND_SCALE_FROM
-                + (FOREGROUND_SCALE_TO - FOREGROUND_SCALE_FROM) * progress;
-        mCurrentForegroundAlpha = FOREGROUND_ALPHA_FROM
-                + (FOREGROUND_ALPHA_TO - FOREGROUND_ALPHA_FROM) * progress;
-        mCurrentBackgroundAlpha = BACKGROUND_ALPHA_FROM
-                + (BACKGROUND_ALPHA_TO - BACKGROUND_ALPHA_FROM) * progress;
-        mCurrentBackgroundScale = BACKGROUND_SCALE_FROM
-                + (BACKGROUND_SCALE_TO - BACKGROUND_SCALE_FROM) * progress;
+        mCurrentContentScale = mTransitionSpec.contentScaleFrom
+                + (mTransitionSpec.contentScaleTo - mTransitionSpec.contentScaleFrom) * progress;
+        mCurrentContentAlpha = mTransitionSpec.contentAlphaFrom
+                + (mTransitionSpec.contentAlphaTo - mTransitionSpec.contentAlphaFrom) * progress;
+        mCurrentBackgroundAlpha = mTransitionSpec.backgroundAlphaFrom
+                + (mTransitionSpec.backgroundAlphaTo - mTransitionSpec.backgroundAlphaFrom)
+                * progress;
+        mCurrentBackgroundScale = mTransitionSpec.backgroundScaleFrom
+                + (mTransitionSpec.backgroundScaleTo - mTransitionSpec.backgroundScaleFrom)
+                * progress;
+        mCurrentOverlayScale = mTransitionSpec.overlayScaleFrom
+                + (mTransitionSpec.overlayScaleTo - mTransitionSpec.overlayScaleFrom) * progress;
+        mCurrentOverlayAlpha = mTransitionSpec.overlayAlphaFrom
+                + (mTransitionSpec.overlayAlphaTo - mTransitionSpec.overlayAlphaFrom) * progress;
     }
 
-    public void applyBackground(GLView view, GLCanvas canvas, RawTexture fadeTexture) {
-        canvas.clearBuffer(view.getBackgroundColor());
+    private void applyOldTexture(GLView view, GLCanvas canvas, float alpha, float scale, boolean clear) {
+        if (mOldScreenTexture == null)
+            return;
+        if (clear) canvas.clearBuffer(view.getBackgroundColor());
         canvas.save();
-        canvas.setAlpha(mCurrentBackgroundAlpha);
+        canvas.setAlpha(alpha);
         int xOffset = view.getWidth() / 2;
         int yOffset = view.getHeight() / 2;
         canvas.translate(xOffset, yOffset);
-        canvas.scale(mCurrentBackgroundScale, mCurrentBackgroundScale, 1);
-        fadeTexture.draw(canvas, -xOffset, -yOffset);
+        canvas.scale(scale, scale, 1);
+        mOldScreenTexture.draw(canvas, -xOffset, -yOffset);
         canvas.restore();
     }
 
-    public void applyForegroundTransformation(GLView view, GLCanvas canvas) {
+    public void applyBackground(GLView view, GLCanvas canvas) {
+        if (mCurrentBackgroundAlpha > 0f) {
+            applyOldTexture(view, canvas, mCurrentBackgroundAlpha, mCurrentBackgroundScale, true);
+        }
+    }
+
+    public void applyContentTransform(GLView view, GLCanvas canvas) {
         int xOffset = view.getWidth() / 2;
         int yOffset = view.getHeight() / 2;
         canvas.translate(xOffset, yOffset);
-        canvas.scale(mCurrentForegroundScale, mCurrentForegroundScale, 1);
+        canvas.scale(mCurrentContentScale, mCurrentContentScale, 1);
         canvas.translate(-xOffset, -yOffset);
-        canvas.setAlpha(mCurrentForegroundAlpha);
+        canvas.setAlpha(mCurrentContentAlpha);
+    }
+
+    public void applyOverlay(GLView view, GLCanvas canvas) {
+        if (mCurrentOverlayAlpha > 0f) {
+            applyOldTexture(view, canvas, mCurrentOverlayAlpha, mCurrentOverlayScale, false);
+        }
     }
 }
index fe2e89e..ff0b32c 100644 (file)
@@ -35,6 +35,7 @@ import android.view.Window;
 import android.view.WindowManager;
 
 import com.android.gallery3d.R;
+import com.android.gallery3d.anim.StateTransitionAnimation;
 import com.android.gallery3d.ui.GLView;
 import com.android.gallery3d.ui.PreparePageFadeoutTexture;
 import com.android.gallery3d.ui.RawTexture;
@@ -70,19 +71,19 @@ abstract public class ActivityState {
 
     private static final String KEY_TRANSITION_IN = "transition-in";
 
-    private RawTexture mFadeOutTexture;
+    public static enum StateTransition { None, Outgoing, Incoming };
+    private StateTransition mNextTransition = StateTransition.None;
+    private StateTransitionAnimation mIntroAnimation;
     private GLView mContentPane;
-    private boolean mWantFadeOut = false;
-    private boolean mTransitionIn;
 
     protected ActivityState() {
     }
 
     protected void setContentPane(GLView content) {
         mContentPane = content;
-        if (mTransitionIn) {
-            mContentPane.setFadeOutTexture(mFadeOutTexture);
-            mFadeOutTexture = null;
+        if (mNextTransition != StateTransition.None) {
+            mContentPane.setIntroAnimation(mIntroAnimation);
+            mIntroAnimation = null;
         }
         mContentPane.setBackgroundColor(getBackgroundColor());
         mActivity.getGLRoot().setContentPane(mContentPane);
@@ -99,9 +100,6 @@ abstract public class ActivityState {
     }
 
     protected void onBackPressed() {
-        if (mActivity.getStateManager().getStateCount() > 1) {
-            fadeOutOnNextPause();
-        }
         mActivity.getStateManager().finishState(this);
     }
 
@@ -175,19 +173,25 @@ abstract public class ActivityState {
         win.setAttributes(params);
     }
 
-    protected void fadeOutOnNextPause() {
-        mWantFadeOut = true;
+    protected void transitionOnNextPause(Class<? extends ActivityState> outgoing,
+            Class<? extends ActivityState> incoming, StateTransition hint) {
+        if (outgoing == PhotoPage.class && incoming == AlbumPage.class) {
+            mNextTransition = StateTransition.Outgoing;
+        } else if (outgoing == AlbumPage.class && incoming == PhotoPage.class) {
+            mNextTransition = StateTransition.Incoming;
+        } else {
+            mNextTransition = hint;
+        }
     }
 
     protected void onPause() {
         if (0 != (mFlags & FLAG_SCREEN_ON_WHEN_PLUGGED)) {
             ((Activity) mActivity).unregisterReceiver(mPowerIntentReceiver);
         }
-        if (mWantFadeOut) {
-            mWantFadeOut = false;
-            if (PreparePageFadeoutTexture.prepareFadeOutTexture(mActivity, mContentPane)) {
-                mActivity.getTransitionStore().put(KEY_TRANSITION_IN, true);
-            }
+        if (mNextTransition != StateTransition.None) {
+            mActivity.getTransitionStore().put(KEY_TRANSITION_IN, mNextTransition);
+            PreparePageFadeoutTexture.prepareFadeOutTexture(mActivity, mContentPane);
+            mNextTransition = StateTransition.None;
         }
     }
 
@@ -242,9 +246,16 @@ abstract public class ActivityState {
 
     // a subclass of ActivityState should override the method to resume itself
     protected void onResume() {
-        mFadeOutTexture = mActivity.getTransitionStore().get(
+        RawTexture fade = mActivity.getTransitionStore().get(
                 PreparePageFadeoutTexture.KEY_FADE_TEXTURE);
-        mTransitionIn = mActivity.getTransitionStore().get(KEY_TRANSITION_IN, false);
+        mNextTransition = mActivity.getTransitionStore().get(
+                KEY_TRANSITION_IN, StateTransition.None);
+        if (mNextTransition != StateTransition.None) {
+            mIntroAnimation = new StateTransitionAnimation(
+                    (mNextTransition == StateTransition.Incoming) ?
+                            StateTransitionAnimation.Spec.INCOMING :
+                            StateTransitionAnimation.Spec.OUTGOING, fade);
+        }
     }
 
     protected boolean onCreateActionBar(Menu menu) {
index 10de5d2..fefb2c8 100644 (file)
@@ -57,7 +57,8 @@ public class StateManager {
         }
         if (!mStack.isEmpty()) {
             ActivityState top = getTopState();
-            top.fadeOutOnNextPause();
+            top.transitionOnNextPause(top.getClass(), klass,
+                    ActivityState.StateTransition.Incoming);
             if (mIsResumed) top.onPause();
         }
         state.initialize(mActivity, data);
@@ -82,7 +83,8 @@ public class StateManager {
 
         if (!mStack.isEmpty()) {
             ActivityState as = getTopState();
-            as.fadeOutOnNextPause();
+            as.transitionOnNextPause(as.getClass(), klass,
+                    ActivityState.StateTransition.Incoming);
             as.mReceivedResults = state.mResult;
             if (mIsResumed) as.onPause();
         } else {
@@ -188,15 +190,18 @@ public class StateManager {
         // Remove the top state.
         mStack.pop();
         state.mIsFinishing = true;
-        if (mIsResumed && fireOnPause) state.onPause();
+        ActivityState top = !mStack.isEmpty() ? mStack.peek().activityState : null;
+        if (mIsResumed && fireOnPause) {
+            if (top != null) {
+                state.transitionOnNextPause(state.getClass(), top.getClass(),
+                        ActivityState.StateTransition.Outgoing);
+            }
+            state.onPause();
+        }
         mActivity.getGLRoot().setContentPane(null);
         state.onDestroy();
 
-        if (!mStack.isEmpty()) {
-            // Restore the immediately previous state
-            ActivityState top = mStack.peek().activityState;
-            if (mIsResumed) top.resume();
-        }
+        if (top != null && mIsResumed) top.resume();
     }
 
     public void switchState(ActivityState oldState,
@@ -211,7 +216,7 @@ public class StateManager {
         mStack.pop();
         if (!data.containsKey(PhotoPage.KEY_APP_BRIDGE)) {
             // Do not do the fade out stuff when we are switching camera modes
-            oldState.fadeOutOnNextPause();
+            oldState.transitionOnNextPause(oldState.getClass(), klass, ActivityState.StateTransition.Incoming);
         }
         if (mIsResumed) oldState.onPause();
         oldState.onDestroy();
index b91b712..664012c 100644 (file)
@@ -78,10 +78,8 @@ public class GLView {
     protected int mScrollHeight = 0;
     protected int mScrollWidth = 0;
 
-    public static final int ANIM_TIME_OPENING = 400;
-    private RawTexture mFadeOutTexture;
     private float [] mBackgroundColor;
-    private StateTransitionAnimation mTransition = new StateTransitionAnimation(ANIM_TIME_OPENING);
+    private StateTransitionAnimation mTransition;
 
     public void startAnimation(CanvasAnimation animation) {
         GLRoot root = getGLRoot();
@@ -223,22 +221,28 @@ public class GLView {
     }
 
     protected void render(GLCanvas canvas) {
-        if (mTransition.calculate(AnimationTime.get())) invalidate();
-        canvas.save();
+        boolean transitionActive = false;
+        if (mTransition != null && mTransition.calculate(AnimationTime.get())) {
+            invalidate();
+            transitionActive = mTransition.isActive();
+        }
         renderBackground(canvas);
-        if (mTransition.isActive()) mTransition.applyForegroundTransformation(this, canvas);
+        canvas.save();
+        if (transitionActive) {
+            mTransition.applyContentTransform(this, canvas);
+        }
         for (int i = 0, n = getComponentCount(); i < n; ++i) {
             renderChild(canvas, getComponent(i));
         }
         canvas.restore();
+        if (transitionActive) {
+            mTransition.applyOverlay(this, canvas);
+        }
     }
 
-    public void setFadeOutTexture(RawTexture texture) {
-        mFadeOutTexture = texture;
-        if (mFadeOutTexture != null) {
-            TiledScreenNail.disableDrawPlaceholder();
-        }
-        mTransition.start();
+    public void setIntroAnimation(StateTransitionAnimation intro) {
+        mTransition = intro;
+        if (mTransition != null) mTransition.start();
     }
 
     public float [] getBackgroundColor() {
@@ -253,15 +257,9 @@ public class GLView {
         if (mBackgroundColor != null) {
             view.clearBuffer(mBackgroundColor);
         }
-        if (mFadeOutTexture != null) {
-            if (!mTransition.isActive()) {
-                mFadeOutTexture.recycle();
-                mFadeOutTexture = null;
-                TiledScreenNail.enableDrawPlaceholder();
-            } else {
-                mTransition.applyBackground(this, view, mFadeOutTexture);
-                return;
-            }
+        if (mTransition != null && mTransition.isActive()) {
+            mTransition.applyBackground(this, view);
+            return;
         }
     }
 
index 0111847..6a4bcea 100644 (file)
@@ -67,7 +67,7 @@ class PositionController {
         SNAPBACK_ANIMATION_TIME,  // ANIM_KIND_SNAPBACK
         400,  // ANIM_KIND_SLIDE
         300,  // ANIM_KIND_ZOOM
-        GLView.ANIM_TIME_OPENING,  // ANIM_KIND_OPENING
+        300,  // ANIM_KIND_OPENING
         0,    // ANIM_KIND_FLING (the duration is calculated dynamically)
         0,    // ANIM_KIND_FLING_X (see the comment above)
         0,    // ANIM_KIND_DELETE (the duration is calculated dynamically)
index 5152fc9..36e7f4b 100644 (file)
@@ -6,7 +6,7 @@ import com.android.gallery3d.app.AbstractGalleryActivity;
 import com.android.gallery3d.ui.GLRoot.OnGLIdleListener;
 
 public class PreparePageFadeoutTexture implements OnGLIdleListener {
-    private static final long TIMEOUT = 500;
+    private static final long TIMEOUT = 200;
     public static final String KEY_FADE_TEXTURE = "fade_texture";
 
     private RawTexture mTexture;
@@ -15,10 +15,20 @@ public class PreparePageFadeoutTexture implements OnGLIdleListener {
     private GLView mRootPane;
 
     public PreparePageFadeoutTexture(GLView rootPane) {
-        mTexture = new RawTexture(rootPane.getWidth(), rootPane.getHeight(), true);
+        int w = rootPane.getWidth();
+        int h = rootPane.getHeight();
+        if (w == 0 || h == 0) {
+            mCancelled = true;
+            return;
+        }
+        mTexture = new RawTexture(w, h, true);
         mRootPane =  rootPane;
     }
 
+    public boolean isCancelled() {
+        return mCancelled;
+    }
+
     public synchronized RawTexture get() {
         if (mCancelled) {
             return null;
@@ -32,25 +42,26 @@ public class PreparePageFadeoutTexture implements OnGLIdleListener {
 
     @Override
     public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) {
-            if(!mCancelled) {
+        if (!mCancelled) {
+            try {
                 canvas.beginRenderTarget(mTexture);
                 mRootPane.render(canvas);
                 canvas.endRenderTarget();
-            } else {
+            } catch (RuntimeException e) {
                 mTexture = null;
             }
-            mResultReady.open();
-            return false;
+        } else {
+            mTexture = null;
+        }
+        mResultReady.open();
+        return false;
     }
 
-    public static boolean prepareFadeOutTexture(AbstractGalleryActivity activity,
+    public static void prepareFadeOutTexture(AbstractGalleryActivity activity,
             GLView rootPane) {
-        if (rootPane.getWidth() == 0 || rootPane.getHeight() == 0) {
-            // The view hasn't been measured yet, just abort the animation
-            return false;
-        }
-        GLRoot root = activity.getGLRoot();
         PreparePageFadeoutTexture task = new PreparePageFadeoutTexture(rootPane);
+        if (task.isCancelled()) return;
+        GLRoot root = activity.getGLRoot();
         RawTexture texture = null;
         root.unlockRenderThread();
         try {
@@ -61,9 +72,8 @@ public class PreparePageFadeoutTexture implements OnGLIdleListener {
         }
 
         if (texture == null) {
-            return false;
+            return;
         }
         activity.getTransitionStore().put(KEY_FADE_TEXTURE, texture);
-        return true;
     }
 }