From 384ca1056819542000ddc5726f0e62f56cc17b6e Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Fri, 8 Nov 2013 06:45:03 -0800 Subject: Syncing up state transition with paging transition Change-Id: Id91e4c046cfe7d9aa6e7de10dbf57ee727ba160e --- src/com/android/launcher3/LauncherScroller.java | 559 ++++++++++++++++++++++++ src/com/android/launcher3/PagedView.java | 60 ++- src/com/android/launcher3/RampUpScroller.java | 120 ----- src/com/android/launcher3/SmoothPagedView.java | 3 +- src/com/android/launcher3/Workspace.java | 15 +- 5 files changed, 611 insertions(+), 146 deletions(-) create mode 100644 src/com/android/launcher3/LauncherScroller.java delete mode 100644 src/com/android/launcher3/RampUpScroller.java (limited to 'src') diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java new file mode 100644 index 000000000..3bd0a78c4 --- /dev/null +++ b/src/com/android/launcher3/LauncherScroller.java @@ -0,0 +1,559 @@ +/* + * Copyright (C) 2006 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.launcher3; + +import android.animation.TimeInterpolator; +import android.content.Context; +import android.hardware.SensorManager; +import android.os.Build; +import android.util.FloatMath; +import android.view.ViewConfiguration; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; + +/** + * This class differs from the framework {@link android.widget.Scroller} in that + * you can modify the Interpolator post-construction. + */ +public class LauncherScroller { + private int mMode; + + private int mStartX; + private int mStartY; + private int mFinalX; + private int mFinalY; + + private int mMinX; + private int mMaxX; + private int mMinY; + private int mMaxY; + + private int mCurrX; + private int mCurrY; + private long mStartTime; + private int mDuration; + private float mDurationReciprocal; + private float mDeltaX; + private float mDeltaY; + private boolean mFinished; + private TimeInterpolator mInterpolator; + private boolean mFlywheel; + + private float mVelocity; + private float mCurrVelocity; + private int mDistance; + + private float mFlingFriction = ViewConfiguration.getScrollFriction(); + + private static final int DEFAULT_DURATION = 250; + private static final int SCROLL_MODE = 0; + private static final int FLING_MODE = 1; + + private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); + private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1) + private static final float START_TENSION = 0.5f; + private static final float END_TENSION = 1.0f; + private static final float P1 = START_TENSION * INFLEXION; + private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION); + + private static final int NB_SAMPLES = 100; + private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1]; + private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1]; + + private float mDeceleration; + private final float mPpi; + + // A context-specific coefficient adjusted to physical values. + private float mPhysicalCoeff; + + static { + float x_min = 0.0f; + float y_min = 0.0f; + for (int i = 0; i < NB_SAMPLES; i++) { + final float alpha = (float) i / NB_SAMPLES; + + float x_max = 1.0f; + float x, tx, coef; + while (true) { + x = x_min + (x_max - x_min) / 2.0f; + coef = 3.0f * x * (1.0f - x); + tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x; + if (Math.abs(tx - alpha) < 1E-5) break; + if (tx > alpha) x_max = x; + else x_min = x; + } + SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x; + + float y_max = 1.0f; + float y, dy; + while (true) { + y = y_min + (y_max - y_min) / 2.0f; + coef = 3.0f * y * (1.0f - y); + dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y; + if (Math.abs(dy - alpha) < 1E-5) break; + if (dy > alpha) y_max = y; + else y_min = y; + } + SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y; + } + SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f; + + // This controls the viscous fluid effect (how much of it) + sViscousFluidScale = 8.0f; + // must be set to 1.0 (used in viscousFluid()) + sViscousFluidNormalize = 1.0f; + sViscousFluidNormalize = 1.0f / viscousFluid(1.0f); + + } + + private static float sViscousFluidScale; + private static float sViscousFluidNormalize; + + public void setInterpolator(TimeInterpolator interpolator) { + mInterpolator = interpolator; + } + + /** + * Create a Scroller with the default duration and interpolator. + */ + public LauncherScroller(Context context) { + this(context, null); + } + + /** + * Create a Scroller with the specified interpolator. If the interpolator is + * null, the default (viscous) interpolator will be used. "Flywheel" behavior will + * be in effect for apps targeting Honeycomb or newer. + */ + public LauncherScroller(Context context, Interpolator interpolator) { + this(context, interpolator, + context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB); + } + + /** + * Create a Scroller with the specified interpolator. If the interpolator is + * null, the default (viscous) interpolator will be used. Specify whether or + * not to support progressive "flywheel" behavior in flinging. + */ + public LauncherScroller(Context context, Interpolator interpolator, boolean flywheel) { + mFinished = true; + mInterpolator = interpolator; + mPpi = context.getResources().getDisplayMetrics().density * 160.0f; + mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); + mFlywheel = flywheel; + + mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning + } + + /** + * The amount of friction applied to flings. The default value + * is {@link ViewConfiguration#getScrollFriction}. + * + * @param friction A scalar dimension-less value representing the coefficient of + * friction. + */ + public final void setFriction(float friction) { + mDeceleration = computeDeceleration(friction); + mFlingFriction = friction; + } + + private float computeDeceleration(float friction) { + return SensorManager.GRAVITY_EARTH // g (m/s^2) + * 39.37f // inch/meter + * mPpi // pixels per inch + * friction; + } + + /** + * + * Returns whether the scroller has finished scrolling. + * + * @return True if the scroller has finished scrolling, false otherwise. + */ + public final boolean isFinished() { + return mFinished; + } + + /** + * Force the finished field to a particular value. + * + * @param finished The new finished value. + */ + public final void forceFinished(boolean finished) { + mFinished = finished; + } + + /** + * Returns how long the scroll event will take, in milliseconds. + * + * @return The duration of the scroll in milliseconds. + */ + public final int getDuration() { + return mDuration; + } + + /** + * Returns the current X offset in the scroll. + * + * @return The new X offset as an absolute distance from the origin. + */ + public final int getCurrX() { + return mCurrX; + } + + /** + * Returns the current Y offset in the scroll. + * + * @return The new Y offset as an absolute distance from the origin. + */ + public final int getCurrY() { + return mCurrY; + } + + /** + * Returns the current velocity. + * + * @return The original velocity less the deceleration. Result may be + * negative. + */ + public float getCurrVelocity() { + return mMode == FLING_MODE ? + mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f; + } + + /** + * Returns the start X offset in the scroll. + * + * @return The start X offset as an absolute distance from the origin. + */ + public final int getStartX() { + return mStartX; + } + + /** + * Returns the start Y offset in the scroll. + * + * @return The start Y offset as an absolute distance from the origin. + */ + public final int getStartY() { + return mStartY; + } + + /** + * Returns where the scroll will end. Valid only for "fling" scrolls. + * + * @return The final X offset as an absolute distance from the origin. + */ + public final int getFinalX() { + return mFinalX; + } + + /** + * Returns where the scroll will end. Valid only for "fling" scrolls. + * + * @return The final Y offset as an absolute distance from the origin. + */ + public final int getFinalY() { + return mFinalY; + } + + /** + * Call this when you want to know the new location. If it returns true, + * the animation is not yet finished. + */ + public boolean computeScrollOffset() { + if (mFinished) { + return false; + } + + int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); + + if (timePassed < mDuration) { + switch (mMode) { + case SCROLL_MODE: + float x = timePassed * mDurationReciprocal; + + if (mInterpolator == null) + x = viscousFluid(x); + else + x = mInterpolator.getInterpolation(x); + + mCurrX = mStartX + Math.round(x * mDeltaX); + mCurrY = mStartY + Math.round(x * mDeltaY); + break; + case FLING_MODE: + final float t = (float) timePassed / mDuration; + final int index = (int) (NB_SAMPLES * t); + float distanceCoef = 1.f; + float velocityCoef = 0.f; + if (index < NB_SAMPLES) { + final float t_inf = (float) index / NB_SAMPLES; + final float t_sup = (float) (index + 1) / NB_SAMPLES; + final float d_inf = SPLINE_POSITION[index]; + final float d_sup = SPLINE_POSITION[index + 1]; + velocityCoef = (d_sup - d_inf) / (t_sup - t_inf); + distanceCoef = d_inf + (t - t_inf) * velocityCoef; + } + + mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f; + + mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX)); + // Pin to mMinX <= mCurrX <= mMaxX + mCurrX = Math.min(mCurrX, mMaxX); + mCurrX = Math.max(mCurrX, mMinX); + + mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY)); + // Pin to mMinY <= mCurrY <= mMaxY + mCurrY = Math.min(mCurrY, mMaxY); + mCurrY = Math.max(mCurrY, mMinY); + + if (mCurrX == mFinalX && mCurrY == mFinalY) { + mFinished = true; + } + + break; + } + } + else { + mCurrX = mFinalX; + mCurrY = mFinalY; + mFinished = true; + } + return true; + } + + /** + * Start scrolling by providing a starting point and the distance to travel. + * The scroll will use the default value of 250 milliseconds for the + * duration. + * + * @param startX Starting horizontal scroll offset in pixels. Positive + * numbers will scroll the content to the left. + * @param startY Starting vertical scroll offset in pixels. Positive numbers + * will scroll the content up. + * @param dx Horizontal distance to travel. Positive numbers will scroll the + * content to the left. + * @param dy Vertical distance to travel. Positive numbers will scroll the + * content up. + */ + public void startScroll(int startX, int startY, int dx, int dy) { + startScroll(startX, startY, dx, dy, DEFAULT_DURATION); + } + + /** + * Start scrolling by providing a starting point, the distance to travel, + * and the duration of the scroll. + * + * @param startX Starting horizontal scroll offset in pixels. Positive + * numbers will scroll the content to the left. + * @param startY Starting vertical scroll offset in pixels. Positive numbers + * will scroll the content up. + * @param dx Horizontal distance to travel. Positive numbers will scroll the + * content to the left. + * @param dy Vertical distance to travel. Positive numbers will scroll the + * content up. + * @param duration Duration of the scroll in milliseconds. + */ + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + mMode = SCROLL_MODE; + mFinished = false; + mDuration = duration; + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mStartX = startX; + mStartY = startY; + mFinalX = startX + dx; + mFinalY = startY + dy; + mDeltaX = dx; + mDeltaY = dy; + mDurationReciprocal = 1.0f / (float) mDuration; + } + + /** + * Start scrolling based on a fling gesture. The distance travelled will + * depend on the initial velocity of the fling. + * + * @param startX Starting point of the scroll (X) + * @param startY Starting point of the scroll (Y) + * @param velocityX Initial velocity of the fling (X) measured in pixels per + * second. + * @param velocityY Initial velocity of the fling (Y) measured in pixels per + * second + * @param minX Minimum X value. The scroller will not scroll past this + * point. + * @param maxX Maximum X value. The scroller will not scroll past this + * point. + * @param minY Minimum Y value. The scroller will not scroll past this + * point. + * @param maxY Maximum Y value. The scroller will not scroll past this + * point. + */ + public void fling(int startX, int startY, int velocityX, int velocityY, + int minX, int maxX, int minY, int maxY) { + // Continue a scroll or fling in progress + if (mFlywheel && !mFinished) { + float oldVel = getCurrVelocity(); + + float dx = (float) (mFinalX - mStartX); + float dy = (float) (mFinalY - mStartY); + float hyp = FloatMath.sqrt(dx * dx + dy * dy); + + float ndx = dx / hyp; + float ndy = dy / hyp; + + float oldVelocityX = ndx * oldVel; + float oldVelocityY = ndy * oldVel; + if (Math.signum(velocityX) == Math.signum(oldVelocityX) && + Math.signum(velocityY) == Math.signum(oldVelocityY)) { + velocityX += oldVelocityX; + velocityY += oldVelocityY; + } + } + + mMode = FLING_MODE; + mFinished = false; + + float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY); + + mVelocity = velocity; + mDuration = getSplineFlingDuration(velocity); + mStartTime = AnimationUtils.currentAnimationTimeMillis(); + mStartX = startX; + mStartY = startY; + + float coeffX = velocity == 0 ? 1.0f : velocityX / velocity; + float coeffY = velocity == 0 ? 1.0f : velocityY / velocity; + + double totalDistance = getSplineFlingDistance(velocity); + mDistance = (int) (totalDistance * Math.signum(velocity)); + + mMinX = minX; + mMaxX = maxX; + mMinY = minY; + mMaxY = maxY; + + mFinalX = startX + (int) Math.round(totalDistance * coeffX); + // Pin to mMinX <= mFinalX <= mMaxX + mFinalX = Math.min(mFinalX, mMaxX); + mFinalX = Math.max(mFinalX, mMinX); + + mFinalY = startY + (int) Math.round(totalDistance * coeffY); + // Pin to mMinY <= mFinalY <= mMaxY + mFinalY = Math.min(mFinalY, mMaxY); + mFinalY = Math.max(mFinalY, mMinY); + } + + private double getSplineDeceleration(float velocity) { + return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff)); + } + + private int getSplineFlingDuration(float velocity) { + final double l = getSplineDeceleration(velocity); + final double decelMinusOne = DECELERATION_RATE - 1.0; + return (int) (1000.0 * Math.exp(l / decelMinusOne)); + } + + private double getSplineFlingDistance(float velocity) { + final double l = getSplineDeceleration(velocity); + final double decelMinusOne = DECELERATION_RATE - 1.0; + return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l); + } + + static float viscousFluid(float x) + { + x *= sViscousFluidScale; + if (x < 1.0f) { + x -= (1.0f - (float)Math.exp(-x)); + } else { + float start = 0.36787944117f; // 1/e == exp(-1) + x = 1.0f - (float)Math.exp(1.0f - x); + x = start + x * (1.0f - start); + } + x *= sViscousFluidNormalize; + return x; + } + + /** + * Stops the animation. Contrary to {@link #forceFinished(boolean)}, + * aborting the animating cause the scroller to move to the final x and y + * position + * + * @see #forceFinished(boolean) + */ + public void abortAnimation() { + mCurrX = mFinalX; + mCurrY = mFinalY; + mFinished = true; + } + + /** + * Extend the scroll animation. This allows a running animation to scroll + * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}. + * + * @param extend Additional time to scroll in milliseconds. + * @see #setFinalX(int) + * @see #setFinalY(int) + */ + public void extendDuration(int extend) { + int passed = timePassed(); + mDuration = passed + extend; + mDurationReciprocal = 1.0f / mDuration; + mFinished = false; + } + + /** + * Returns the time elapsed since the beginning of the scrolling. + * + * @return The elapsed time in milliseconds. + */ + public int timePassed() { + return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); + } + + /** + * Sets the final position (X) for this scroller. + * + * @param newX The new X offset as an absolute distance from the origin. + * @see #extendDuration(int) + * @see #setFinalY(int) + */ + public void setFinalX(int newX) { + mFinalX = newX; + mDeltaX = mFinalX - mStartX; + mFinished = false; + } + + /** + * Sets the final position (Y) for this scroller. + * + * @param newY The new Y offset as an absolute distance from the origin. + * @see #extendDuration(int) + * @see #setFinalX(int) + */ + public void setFinalY(int newY) { + mFinalY = newY; + mDeltaY = mFinalY - mStartY; + mFinished = false; + } + + /** + * @hide + */ + public boolean isScrollingInDirection(float xvel, float yvel) { + return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) && + Math.signum(yvel) == Math.signum(mFinalY - mStartY); + } +} diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 76d54fc08..b11302c9a 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -120,7 +120,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected int mNextPage = INVALID_PAGE; protected int mMaxScrollX; - protected Scroller mScroller; + protected LauncherScroller mScroller; + private Interpolator mDefaultInterpolator; private VelocityTracker mVelocityTracker; private int mPageSpacing = 0; @@ -319,7 +320,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc protected void init() { mDirtyPageContent = new ArrayList(); mDirtyPageContent.ensureCapacity(32); - mScroller = new Scroller(getContext(), new ScrollInterpolator()); + mScroller = new LauncherScroller(getContext()); + setDefaultInterpolator(new ScrollInterpolator()); mCurrentPage = 0; mCenterPagesVertically = true; @@ -339,6 +341,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc setOnHierarchyChangeListener(this); } + protected void setDefaultInterpolator(Interpolator interpolator) { + mDefaultInterpolator = interpolator; + mScroller.setInterpolator(mDefaultInterpolator); + } + protected void onAttachedToWindow() { super.onAttachedToWindow(); @@ -1728,8 +1735,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc return OVERSCROLL_DAMP_FACTOR * f; } - protected void disableFreeScroll(int snapPage) { - setEnableFreeScroll(false, snapPage); + protected void enableFreeScroll() { + setEnableFreeScroll(true); + } + + protected void disableFreeScroll() { + setEnableFreeScroll(false); } void updateFreescrollBounds() { @@ -1743,16 +1754,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } } - private void setEnableFreeScroll(boolean freeScroll, int snapPage) { + private void setEnableFreeScroll(boolean freeScroll) { mFreeScroll = freeScroll; - if (snapPage == -1) { - snapPage = getPageNearestToCenterOfScreen(); - } - - if (!mFreeScroll) { - snapToPage(snapPage); - } else { + if (mFreeScroll) { updateFreescrollBounds(); getOverviewModePages(mTempVisiblePagesRange); if (getCurrentPage() < mTempVisiblePagesRange[0]) { @@ -2010,6 +2015,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc int vX = (int) (-velocityX * scaleX); int initialScrollX = (int) (getScrollX() * scaleX); + mScroller.setInterpolator(mDefaultInterpolator); mScroller.fling(initialScrollX, getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0); invalidate(); @@ -2284,27 +2290,33 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } protected void snapToPageImmediately(int whichPage) { - snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true); + snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true, null); } protected void snapToPage(int whichPage, int duration) { - snapToPage(whichPage, duration, false); + snapToPage(whichPage, duration, false, null); + } + + protected void snapToPage(int whichPage, int duration, TimeInterpolator interpolator) { + snapToPage(whichPage, duration, false, interpolator); } - protected void snapToPage(int whichPage, int duration, boolean immediate) { + protected void snapToPage(int whichPage, int duration, boolean immediate, + TimeInterpolator interpolator) { whichPage = Math.max(0, Math.min(whichPage, getPageCount() - 1)); int newX = getScrollForPage(whichPage); final int sX = mUnboundedScrollX; final int delta = newX - sX; - snapToPage(whichPage, delta, duration, immediate); + snapToPage(whichPage, delta, duration, immediate, interpolator); } protected void snapToPage(int whichPage, int delta, int duration) { - snapToPage(whichPage, delta, duration, false); + snapToPage(whichPage, delta, duration, false, null); } - protected void snapToPage(int whichPage, int delta, int duration, boolean immediate) { + protected void snapToPage(int whichPage, int delta, int duration, boolean immediate, + TimeInterpolator interpolator) { mNextPage = whichPage; View focusedChild = getFocusedChild(); if (focusedChild != null && whichPage != mCurrentPage && @@ -2323,8 +2335,15 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc } if (!mScroller.isFinished()) { - mScroller.abortAnimation(); + abortScrollerAnimation(false); } + + if (interpolator != null) { + mScroller.setInterpolator(interpolator); + } else { + mScroller.setInterpolator(mDefaultInterpolator); + } + mScroller.startScroll(mUnboundedScrollX, 0, delta, 0, duration); notifyPageSwitchListener(); @@ -2581,7 +2600,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc mDragView = getChildAt(dragViewIndex); mDragView.animate().scaleX(1.15f).scaleY(1.15f).setDuration(100).start(); mDragViewBaselineLeft = mDragView.getLeft(); - disableFreeScroll(-1); + snapToPage(getPageNearestToCenterOfScreen()); + disableFreeScroll(); onStartReordering(); return true; } diff --git a/src/com/android/launcher3/RampUpScroller.java b/src/com/android/launcher3/RampUpScroller.java deleted file mode 100644 index 89eb5798e..000000000 --- a/src/com/android/launcher3/RampUpScroller.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2013 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.launcher3; - -import android.view.animation.AccelerateInterpolator; -import android.view.animation.AnimationUtils; -import android.view.animation.Interpolator; - -/** - * Scroller that gradually reaches a target velocity. - */ -class RampUpScroller { - private final Interpolator mInterpolator; - private final long mRampUpTime; - - private long mStartTime; - private long mDeltaTime; - private float mTargetVelocityX; - private float mTargetVelocityY; - private int mDeltaX; - private int mDeltaY; - - /** - * Creates a new ramp-up scroller that reaches full velocity after a - * specified duration. - * - * @param rampUpTime Duration before the scroller reaches target velocity. - */ - public RampUpScroller(long rampUpTime) { - mInterpolator = new AccelerateInterpolator(); - mRampUpTime = rampUpTime; - } - - /** - * Starts the scroller at the current animation time. - */ - public void start() { - mStartTime = AnimationUtils.currentAnimationTimeMillis(); - mDeltaTime = mStartTime; - } - - /** - * Computes the current scroll deltas. This usually only be called after - * starting the scroller with {@link #start()}. - * - * @see #getDeltaX() - * @see #getDeltaY() - */ - public void computeScrollDelta() { - final long currentTime = AnimationUtils.currentAnimationTimeMillis(); - final long elapsedSinceStart = currentTime - mStartTime; - final float scale; - if (elapsedSinceStart < mRampUpTime) { - scale = mInterpolator.getInterpolation((float) elapsedSinceStart / mRampUpTime); - } else { - scale = 1f; - } - - final long elapsedSinceDelta = currentTime - mDeltaTime; - mDeltaTime = currentTime; - - mDeltaX = (int) (elapsedSinceDelta * scale * mTargetVelocityX); - mDeltaY = (int) (elapsedSinceDelta * scale * mTargetVelocityY); - } - - /** - * Sets the target velocity for this scroller. - * - * @param x The target X velocity in pixels per millisecond. - * @param y The target Y velocity in pixels per millisecond. - */ - public void setTargetVelocity(float x, float y) { - mTargetVelocityX = x; - mTargetVelocityY = y; - } - - /** - * @return The target X velocity for this scroller. - */ - public float getTargetVelocityX() { - return mTargetVelocityX; - } - - /** - * @return The target Y velocity for this scroller. - */ - public float getTargetVelocityY() { - return mTargetVelocityY; - } - - /** - * The distance traveled in the X-coordinate computed by the last call to - * {@link #computeScrollDelta()}. - */ - public int getDeltaX() { - return mDeltaX; - } - - /** - * The distance traveled in the Y-coordinate computed by the last call to - * {@link #computeScrollDelta()}. - */ - public int getDeltaY() { - return mDeltaY; - } -} diff --git a/src/com/android/launcher3/SmoothPagedView.java b/src/com/android/launcher3/SmoothPagedView.java index 64dcb34ca..4e331aa2c 100644 --- a/src/com/android/launcher3/SmoothPagedView.java +++ b/src/com/android/launcher3/SmoothPagedView.java @@ -19,7 +19,6 @@ package com.android.launcher3; import android.content.Context; import android.util.AttributeSet; import android.view.animation.Interpolator; -import android.widget.Scroller; public abstract class SmoothPagedView extends PagedView { private static final float SMOOTHING_SPEED = 0.75f; @@ -100,7 +99,7 @@ public abstract class SmoothPagedView extends PagedView { mBaseLineFlingVelocity = 2500.0f; mFlingVelocityInfluence = 0.4f; mScrollInterpolator = new OvershootInterpolator(); - mScroller = new Scroller(getContext(), mScrollInterpolator); + setDefaultInterpolator(mScrollInterpolator); } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index eeb49f8e0..7ba6adf2a 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2234,9 +2234,12 @@ public class Workspace extends SmoothPagedView mNewScale = 1.0f; if (oldStateIsOverview) { - disableFreeScroll(snapPage); + disableFreeScroll(); + } else if (stateIsOverview) { + enableFreeScroll(); } + if (state != State.NORMAL) { if (stateIsSpringLoaded) { mNewScale = mSpringLoadedShrinkFactor; @@ -2259,16 +2262,20 @@ public class Workspace extends SmoothPagedView duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime); } + if (snapPage == -1) { + snapPage = getPageNearestToCenterOfScreen(); + } + snapToPage(snapPage, duration, mZoomInInterpolator); + for (int i = 0; i < getChildCount(); i++) { final CellLayout cl = (CellLayout) getChildAt(i); - boolean isCurrentPage = (i == getNextPage()); + boolean isCurrentPage = (i == snapPage); float initialAlpha = cl.getShortcutsAndWidgets().getAlpha(); float finalAlpha; if (stateIsSmall) { finalAlpha = 0f; } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) { - - finalAlpha = (i == getNextPage() || i < numCustomPages()) ? 1f : 0f; + finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f; } else { finalAlpha = 1f; } -- cgit v1.2.3