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);
+ }
}
}
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;
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);
}
protected void onBackPressed() {
- if (mActivity.getStateManager().getStateCount() > 1) {
- fadeOutOnNextPause();
- }
mActivity.getStateManager().finishState(this);
}
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;
}
}
// 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) {
}
if (!mStack.isEmpty()) {
ActivityState top = getTopState();
- top.fadeOutOnNextPause();
+ top.transitionOnNextPause(top.getClass(), klass,
+ ActivityState.StateTransition.Incoming);
if (mIsResumed) top.onPause();
}
state.initialize(mActivity, data);
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 {
// 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,
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();
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();
}
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() {
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;
}
}
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)
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;
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;
@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 {
}
if (texture == null) {
- return false;
+ return;
}
activity.getTransitionStore().put(KEY_FADE_TEXTURE, texture);
- return true;
}
}