summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/ui/EdgeEffect.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/ui/EdgeEffect.java')
-rw-r--r--src/com/android/gallery3d/ui/EdgeEffect.java443
1 files changed, 0 insertions, 443 deletions
diff --git a/src/com/android/gallery3d/ui/EdgeEffect.java b/src/com/android/gallery3d/ui/EdgeEffect.java
deleted file mode 100644
index 87ff0c5d3..000000000
--- a/src/com/android/gallery3d/ui/EdgeEffect.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * 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 android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-
-import com.android.gallery3d.R;
-import com.android.gallery3d.glrenderer.GLCanvas;
-import com.android.gallery3d.glrenderer.ResourceTexture;
-
-// This is copied from android.widget.EdgeEffect with some small modifications:
-// (1) Copy the images (overscroll_{edge|glow}.png) to local resources.
-// (2) Use "GLCanvas" instead of "Canvas" for draw()'s parameter.
-// (3) Use a private Drawable class (which inherits from ResourceTexture)
-// instead of android.graphics.drawable.Drawable to hold the images.
-// The private Drawable class is used to translate original Canvas calls to
-// corresponding GLCanvas calls.
-
-/**
- * This class performs the graphical effect used at the edges of scrollable widgets
- * when the user scrolls beyond the content bounds in 2D space.
- *
- * <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an
- * instance for each edge that should show the effect, feed it input data using
- * the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()},
- * and draw the effect using {@link #draw(Canvas)} in the widget's overridden
- * {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns
- * false after drawing, the edge effect's animation is not yet complete and the widget
- * should schedule another drawing pass to continue the animation.</p>
- *
- * <p>When drawing, widgets should draw their main content and child views first,
- * usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code>
- * method. (This will invoke onDraw and dispatch drawing to child views as needed.)
- * The edge effect may then be drawn on top of the view's content using the
- * {@link #draw(Canvas)} method.</p>
- */
-public class EdgeEffect {
- @SuppressWarnings("unused")
- private static final String TAG = "EdgeEffect";
-
- // Time it will take the effect to fully recede in ms
- private static final int RECEDE_TIME = 1000;
-
- // Time it will take before a pulled glow begins receding in ms
- private static final int PULL_TIME = 167;
-
- // Time it will take in ms for a pulled glow to decay to partial strength before release
- private static final int PULL_DECAY_TIME = 1000;
-
- private static final float MAX_ALPHA = 0.8f;
- private static final float HELD_EDGE_ALPHA = 0.7f;
- private static final float HELD_EDGE_SCALE_Y = 0.5f;
- private static final float HELD_GLOW_ALPHA = 0.5f;
- private static final float HELD_GLOW_SCALE_Y = 0.5f;
-
- private static final float MAX_GLOW_HEIGHT = 4.f;
-
- private static final float PULL_GLOW_BEGIN = 1.f;
- private static final float PULL_EDGE_BEGIN = 0.6f;
-
- // Minimum velocity that will be absorbed
- private static final int MIN_VELOCITY = 100;
-
- private static final float EPSILON = 0.001f;
-
- private final Drawable mEdge;
- private final Drawable mGlow;
- private int mWidth;
- private int mHeight;
- private final int MIN_WIDTH = 300;
- private final int mMinWidth;
-
- private float mEdgeAlpha;
- private float mEdgeScaleY;
- private float mGlowAlpha;
- private float mGlowScaleY;
-
- private float mEdgeAlphaStart;
- private float mEdgeAlphaFinish;
- private float mEdgeScaleYStart;
- private float mEdgeScaleYFinish;
- private float mGlowAlphaStart;
- private float mGlowAlphaFinish;
- private float mGlowScaleYStart;
- private float mGlowScaleYFinish;
-
- private long mStartTime;
- private float mDuration;
-
- private final Interpolator mInterpolator;
-
- private static final int STATE_IDLE = 0;
- private static final int STATE_PULL = 1;
- private static final int STATE_ABSORB = 2;
- private static final int STATE_RECEDE = 3;
- private static final int STATE_PULL_DECAY = 4;
-
- // How much dragging should effect the height of the edge image.
- // Number determined by user testing.
- private static final int PULL_DISTANCE_EDGE_FACTOR = 7;
-
- // How much dragging should effect the height of the glow image.
- // Number determined by user testing.
- private static final int PULL_DISTANCE_GLOW_FACTOR = 7;
- private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f;
-
- private static final int VELOCITY_EDGE_FACTOR = 8;
- private static final int VELOCITY_GLOW_FACTOR = 16;
-
- private int mState = STATE_IDLE;
-
- private float mPullDistance;
-
- /**
- * Construct a new EdgeEffect with a theme appropriate for the provided context.
- * @param context Context used to provide theming and resource information for the EdgeEffect
- */
- public EdgeEffect(Context context) {
- mEdge = new Drawable(context, R.drawable.overscroll_edge);
- mGlow = new Drawable(context, R.drawable.overscroll_glow);
-
- mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f);
- mInterpolator = new DecelerateInterpolator();
- }
-
- /**
- * Set the size of this edge effect in pixels.
- *
- * @param width Effect width in pixels
- * @param height Effect height in pixels
- */
- public void setSize(int width, int height) {
- mWidth = width;
- mHeight = height;
- }
-
- /**
- * Reports if this EdgeEffect's animation is finished. If this method returns false
- * after a call to {@link #draw(Canvas)} the host widget should schedule another
- * drawing pass to continue the animation.
- *
- * @return true if animation is finished, false if drawing should continue on the next frame.
- */
- public boolean isFinished() {
- return mState == STATE_IDLE;
- }
-
- /**
- * Immediately finish the current animation.
- * After this call {@link #isFinished()} will return true.
- */
- public void finish() {
- mState = STATE_IDLE;
- }
-
- /**
- * A view should call this when content is pulled away from an edge by the user.
- * This will update the state of the current visual effect and its associated animation.
- * The host view should always {@link android.view.View#invalidate()} after this
- * and draw the results accordingly.
- *
- * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
- * 1.f (full length of the view) or negative values to express change
- * back toward the edge reached to initiate the effect.
- */
- public void onPull(float deltaDistance) {
- final long now = AnimationTime.get();
- if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) {
- return;
- }
- if (mState != STATE_PULL) {
- mGlowScaleY = PULL_GLOW_BEGIN;
- }
- mState = STATE_PULL;
-
- mStartTime = now;
- mDuration = PULL_TIME;
-
- mPullDistance += deltaDistance;
- float distance = Math.abs(mPullDistance);
-
- mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA));
- mEdgeScaleY = mEdgeScaleYStart = Math.max(
- HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f));
-
- mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
- mGlowAlpha +
- (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR));
-
- float glowChange = Math.abs(deltaDistance);
- if (deltaDistance > 0 && mPullDistance < 0) {
- glowChange = -glowChange;
- }
- if (mPullDistance == 0) {
- mGlowScaleY = 0;
- }
-
- // Do not allow glow to get larger than MAX_GLOW_HEIGHT.
- mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max(
- 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR));
-
- mEdgeAlphaFinish = mEdgeAlpha;
- mEdgeScaleYFinish = mEdgeScaleY;
- mGlowAlphaFinish = mGlowAlpha;
- mGlowScaleYFinish = mGlowScaleY;
- }
-
- /**
- * Call when the object is released after being pulled.
- * This will begin the "decay" phase of the effect. After calling this method
- * the host view should {@link android.view.View#invalidate()} and thereby
- * draw the results accordingly.
- */
- public void onRelease() {
- mPullDistance = 0;
-
- if (mState != STATE_PULL && mState != STATE_PULL_DECAY) {
- return;
- }
-
- mState = STATE_RECEDE;
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
-
- mStartTime = AnimationTime.get();
- mDuration = RECEDE_TIME;
- }
-
- /**
- * Call when the effect absorbs an impact at the given velocity.
- * Used when a fling reaches the scroll boundary.
- *
- * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller},
- * the method <code>getCurrVelocity</code> will provide a reasonable approximation
- * to use here.</p>
- *
- * @param velocity Velocity at impact in pixels per second.
- */
- public void onAbsorb(int velocity) {
- mState = STATE_ABSORB;
- velocity = Math.max(MIN_VELOCITY, Math.abs(velocity));
-
- mStartTime = AnimationTime.get();
- mDuration = 0.1f + (velocity * 0.03f);
-
- // The edge should always be at least partially visible, regardless
- // of velocity.
- mEdgeAlphaStart = 0.f;
- mEdgeScaleY = mEdgeScaleYStart = 0.f;
- // The glow depends more on the velocity, and therefore starts out
- // nearly invisible.
- mGlowAlphaStart = 0.5f;
- mGlowScaleYStart = 0.f;
-
- // Factor the velocity by 8. Testing on device shows this works best to
- // reflect the strength of the user's scrolling.
- mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1));
- // Edge should never get larger than the size of its asset.
- mEdgeScaleYFinish = Math.max(
- HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f));
-
- // Growth for the size of the glow should be quadratic to properly
- // respond
- // to a user's scrolling speed. The faster the scrolling speed, the more
- // intense the effect should be for both the size and the saturation.
- mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f);
- // Alpha should change for the glow as well as size.
- mGlowAlphaFinish = Math.max(
- mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
- }
-
-
- /**
- * Draw into the provided canvas. Assumes that the canvas has been rotated
- * accordingly and the size has been set. The effect will be drawn the full
- * width of X=0 to X=width, beginning from Y=0 and extending to some factor <
- * 1.f of height.
- *
- * @param canvas Canvas to draw into
- * @return true if drawing should continue beyond this frame to continue the
- * animation
- */
- public boolean draw(GLCanvas canvas) {
- update();
-
- final int edgeHeight = mEdge.getIntrinsicHeight();
- final int edgeWidth = mEdge.getIntrinsicWidth();
- final int glowHeight = mGlow.getIntrinsicHeight();
- final int glowWidth = mGlow.getIntrinsicWidth();
-
- mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
-
- int glowBottom = (int) Math.min(
- glowHeight * mGlowScaleY * glowHeight/ glowWidth * 0.6f,
- glowHeight * MAX_GLOW_HEIGHT);
- if (mWidth < mMinWidth) {
- // Center the glow and clip it.
- int glowLeft = (mWidth - mMinWidth)/2;
- mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom);
- } else {
- // Stretch the glow to fit.
- mGlow.setBounds(0, 0, mWidth, glowBottom);
- }
-
- mGlow.draw(canvas);
-
- mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255));
-
- int edgeBottom = (int) (edgeHeight * mEdgeScaleY);
- if (mWidth < mMinWidth) {
- // Center the edge and clip it.
- int edgeLeft = (mWidth - mMinWidth)/2;
- mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom);
- } else {
- // Stretch the edge to fit.
- mEdge.setBounds(0, 0, mWidth, edgeBottom);
- }
- mEdge.draw(canvas);
-
- return mState != STATE_IDLE;
- }
-
- private void update() {
- final long time = AnimationTime.get();
- final float t = Math.min((time - mStartTime) / mDuration, 1.f);
-
- final float interp = mInterpolator.getInterpolation(t);
-
- mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp;
- mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp;
- mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
- mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
-
- if (t >= 1.f - EPSILON) {
- switch (mState) {
- case STATE_ABSORB:
- mState = STATE_RECEDE;
- mStartTime = AnimationTime.get();
- mDuration = RECEDE_TIME;
-
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- // After absorb, the glow and edge should fade to nothing.
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
- break;
- case STATE_PULL:
- mState = STATE_PULL_DECAY;
- mStartTime = AnimationTime.get();
- mDuration = PULL_DECAY_TIME;
-
- mEdgeAlphaStart = mEdgeAlpha;
- mEdgeScaleYStart = mEdgeScaleY;
- mGlowAlphaStart = mGlowAlpha;
- mGlowScaleYStart = mGlowScaleY;
-
- // After pull, the glow and edge should fade to nothing.
- mEdgeAlphaFinish = 0.f;
- mEdgeScaleYFinish = 0.f;
- mGlowAlphaFinish = 0.f;
- mGlowScaleYFinish = 0.f;
- break;
- case STATE_PULL_DECAY:
- // When receding, we want edge to decrease more slowly
- // than the glow.
- float factor = mGlowScaleYFinish != 0 ? 1
- / (mGlowScaleYFinish * mGlowScaleYFinish)
- : Float.MAX_VALUE;
- mEdgeScaleY = mEdgeScaleYStart +
- (mEdgeScaleYFinish - mEdgeScaleYStart) *
- interp * factor;
- mState = STATE_RECEDE;
- break;
- case STATE_RECEDE:
- mState = STATE_IDLE;
- break;
- }
- }
- }
-
- private static class Drawable extends ResourceTexture {
- private Rect mBounds = new Rect();
- private int mAlpha = 255;
-
- public Drawable(Context context, int resId) {
- super(context, resId);
- }
-
- public int getIntrinsicWidth() {
- return getWidth();
- }
-
- public int getIntrinsicHeight() {
- return getHeight();
- }
-
- public void setBounds(int left, int top, int right, int bottom) {
- mBounds.set(left, top, right, bottom);
- }
-
- public void setAlpha(int alpha) {
- mAlpha = alpha;
- }
-
- public void draw(GLCanvas canvas) {
- canvas.save(GLCanvas.SAVE_FLAG_ALPHA);
- canvas.multiplyAlpha(mAlpha / 255.0f);
- Rect b = mBounds;
- draw(canvas, b.left, b.top, b.width(), b.height());
- canvas.restore();
- }
- }
-}