10142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka/* 20142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Copyright (C) 2008 The Android Open Source Project 30142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * 40142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 50142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * you may not use this file except in compliance with the License. 60142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * You may obtain a copy of the License at 70142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * 80142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * http://www.apache.org/licenses/LICENSE-2.0 90142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * 100142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Unless required by applicable law or agreed to in writing, software 110142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 120142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * See the License for the specific language governing permissions and 140142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * limitations under the License. 150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 180142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 190142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkaimport android.content.Context; 200142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkaimport android.util.AttributeSet; 210142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkaimport android.view.animation.Interpolator; 220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurkapublic abstract class SmoothPagedView extends PagedView { 240142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private static final float SMOOTHING_SPEED = 0.75f; 250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED)); 260142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 27f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen private float mBaseLineFlingVelocity; 28f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen private float mFlingVelocityInfluence; 290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 30e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen static final int DEFAULT_MODE = 0; 31e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen static final int X_LARGE_MODE = 1; 320142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 33f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen int mScrollMode; 34f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 35f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen private Interpolator mScrollInterpolator; 360142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 37f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung public static class OvershootInterpolator implements Interpolator { 380142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private static final float DEFAULT_TENSION = 1.3f; 390142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka private float mTension; 400142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 41f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung public OvershootInterpolator() { 420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTension = DEFAULT_TENSION; 430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 450142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void setDistance(int distance) { 460142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION; 470142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 480142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 490142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void disableSettle() { 500142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mTension = 0.f; 510142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public float getInterpolation(float t) { 540142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka t -= 1.0f; 550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka return t * t * ((mTension + 1) * t + mTension) + 1.0f; 560142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 570142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 580142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 590142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 600142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Used to inflate the Workspace from XML. 610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * 620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * @param context The application's context. 630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * @param attrs The attributes set containing the Workspace's customization values. 640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 650142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public SmoothPagedView(Context context, AttributeSet attrs) { 660142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka this(context, attrs, 0); 670142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 680142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 690142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 700142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Used to inflate the Workspace from XML. 710142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * 720142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * @param context The application's context. 730142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * @param attrs The attributes set containing the Workspace's customization values. 740142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * @param defStyle Unused. 750142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 760142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) { 770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka super(context, attrs, defStyle); 780142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 790142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mUsePagingTouchSlop = false; 800142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 810142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // This means that we'll take care of updating the scroll parameter ourselves (we do it 82e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones 83e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen mDeferScrollUpdate = mScrollMode != X_LARGE_MODE; 840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 86f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen protected int getScrollMode() { 87b26f3d6a8c62e7c1a603b6c7979375d8dd4f20d4Winson Chung return X_LARGE_MODE; 88f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 89f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 900142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka /** 910142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka * Initializes various states for this workspace. 920142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka */ 930142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka @Override 940142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void init() { 950142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka super.init(); 96f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 97f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen mScrollMode = getScrollMode(); 98e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (mScrollMode == DEFAULT_MODE) { 99f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen mBaseLineFlingVelocity = 2500.0f; 100f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen mFlingVelocityInfluence = 0.4f; 101f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung mScrollInterpolator = new OvershootInterpolator(); 102f9618856d6910ac385ad37762f9f067ae59a8622Adam Cohen setDefaultInterpolator(mScrollInterpolator); 103f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen } 1040142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1050142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1060142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka @Override 1070142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToDestination() { 108e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (mScrollMode == X_LARGE_MODE) { 109e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen super.snapToDestination(); 110e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } else { 111e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0); 112e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } 1130142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1140142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1150142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka @Override 1160142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPageWithVelocity(int whichPage, int velocity) { 117e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (mScrollMode == X_LARGE_MODE) { 118e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen super.snapToPageWithVelocity(whichPage, velocity); 119e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } else { 120e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen snapToPageWithVelocity(whichPage, 0, true); 121e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } 1220142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1230142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 12454fa3b95557c283976e8c1aa8a157b460b0b4513Patrick Dubroy private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) { 1250142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka // if (!mScroller.isFinished()) return; 1260142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1270142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1)); 1280142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1290142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage)); 130edb4076e59861d0c343e7245f247e2bee6d48159Adam Cohen final int newX = getScrollForPage(whichPage); 13168d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen final int delta = newX - mUnboundedScrollX; 132e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen int duration = (screenDelta + 1) * 100; 1330142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1340142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (!mScroller.isFinished()) { 1350142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka mScroller.abortAnimation(); 1360142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1370142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 138e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (settle) { 139f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta); 140e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } else { 141f0c6ae0e35d3e020db55b5b826955da66b14b7f6Winson Chung ((OvershootInterpolator) mScrollInterpolator).disableSettle(); 1420142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1430142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1440142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka velocity = Math.abs(velocity); 1450142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka if (velocity > 0) { 146f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence; 1470142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } else { 1480142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka duration += 100; 1490142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 150f34bab59fc0260f926aec44d044883dce1b4191fAdam Cohen 1510142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka snapToPage(whichPage, delta, duration); 1520142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1530142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1540142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka @Override 1550142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka protected void snapToPage(int whichPage) { 156e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (mScrollMode == X_LARGE_MODE) { 157e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen super.snapToPage(whichPage); 158e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } else { 159e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen snapToPageWithVelocity(whichPage, 0, false); 160e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } 1610142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1620142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 1630142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka @Override 1640142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka public void computeScroll() { 165e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (mScrollMode == X_LARGE_MODE) { 166e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen super.computeScroll(); 167e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } else { 168e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen boolean scrollComputed = computeScrollHelper(); 1690142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 170e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) { 171e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen final float now = System.nanoTime() / NANOTIME_DIV; 172e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT); 17368d739365bf650fe7fecf99cd3bfe63a0d41bd12Adam Cohen 174e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen final float dx = mTouchX - mUnboundedScrollX; 1758b805b17158886035b38261eb611d8641701ae43Michael Jurka scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY()); 176e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen mSmoothingTime = now; 1770142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka 178e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen // Keep generating points as long as we're more than 1px away from the target 179e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen if (dx > 1.f || dx < -1.f) { 180e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen invalidate(); 181e0f66b546994a9bdee452851c17a148db02ec300Adam Cohen } 1820142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1830142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1840142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka } 1850142d49e1378a7155bcca1fb59965d9e73016dbcMichael Jurka} 186