• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.launcher3;
18 
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.view.animation.Interpolator;
22 
23 public abstract class SmoothPagedView extends PagedView {
24     private static final float SMOOTHING_SPEED = 0.75f;
25     private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
26 
27     private float mBaseLineFlingVelocity;
28     private float mFlingVelocityInfluence;
29 
30     static final int DEFAULT_MODE = 0;
31     static final int X_LARGE_MODE = 1;
32 
33     int mScrollMode;
34 
35     private Interpolator mScrollInterpolator;
36 
37     public static class OvershootInterpolator implements Interpolator {
38         private static final float DEFAULT_TENSION = 1.3f;
39         private float mTension;
40 
OvershootInterpolator()41         public OvershootInterpolator() {
42             mTension = DEFAULT_TENSION;
43         }
44 
setDistance(int distance)45         public void setDistance(int distance) {
46             mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
47         }
48 
disableSettle()49         public void disableSettle() {
50             mTension = 0.f;
51         }
52 
getInterpolation(float t)53         public float getInterpolation(float t) {
54             t -= 1.0f;
55             return t * t * ((mTension + 1) * t + mTension) + 1.0f;
56         }
57     }
58 
59     /**
60      * Used to inflate the Workspace from XML.
61      *
62      * @param context The application's context.
63      * @param attrs The attributes set containing the Workspace's customization values.
64      */
SmoothPagedView(Context context, AttributeSet attrs)65     public SmoothPagedView(Context context, AttributeSet attrs) {
66         this(context, attrs, 0);
67     }
68 
69     /**
70      * Used to inflate the Workspace from XML.
71      *
72      * @param context The application's context.
73      * @param attrs The attributes set containing the Workspace's customization values.
74      * @param defStyle Unused.
75      */
SmoothPagedView(Context context, AttributeSet attrs, int defStyle)76     public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) {
77         super(context, attrs, defStyle);
78 
79         mUsePagingTouchSlop = false;
80 
81         // This means that we'll take care of updating the scroll parameter ourselves (we do it
82         // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
83         mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
84     }
85 
getScrollMode()86     protected int getScrollMode() {
87         return X_LARGE_MODE;
88     }
89 
90     /**
91      * Initializes various states for this workspace.
92      */
93     @Override
init()94     protected void init() {
95         super.init();
96 
97         mScrollMode = getScrollMode();
98         if (mScrollMode == DEFAULT_MODE) {
99             mBaseLineFlingVelocity = 2500.0f;
100             mFlingVelocityInfluence = 0.4f;
101             mScrollInterpolator = new OvershootInterpolator();
102             setDefaultInterpolator(mScrollInterpolator);
103         }
104     }
105 
106     @Override
snapToDestination()107     protected void snapToDestination() {
108         if (mScrollMode == X_LARGE_MODE) {
109             super.snapToDestination();
110         } else {
111             snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
112         }
113     }
114 
115     @Override
snapToPageWithVelocity(int whichPage, int velocity)116     protected void snapToPageWithVelocity(int whichPage, int velocity) {
117         if (mScrollMode == X_LARGE_MODE) {
118             super.snapToPageWithVelocity(whichPage, velocity);
119         } else {
120             snapToPageWithVelocity(whichPage, 0, true);
121         }
122     }
123 
snapToPageWithVelocity(int whichPage, int velocity, boolean settle)124     private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
125             // if (!mScroller.isFinished()) return;
126 
127         whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
128 
129         final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
130         final int newX = getScrollForPage(whichPage);
131         final int delta = newX - mUnboundedScrollX;
132         int duration = (screenDelta + 1) * 100;
133 
134         if (!mScroller.isFinished()) {
135             mScroller.abortAnimation();
136         }
137 
138         if (settle) {
139             ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
140         } else {
141             ((OvershootInterpolator) mScrollInterpolator).disableSettle();
142         }
143 
144         velocity = Math.abs(velocity);
145         if (velocity > 0) {
146             duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
147         } else {
148             duration += 100;
149         }
150 
151         snapToPage(whichPage, delta, duration);
152     }
153 
154     @Override
snapToPage(int whichPage)155     protected void snapToPage(int whichPage) {
156        if (mScrollMode == X_LARGE_MODE) {
157            super.snapToPage(whichPage);
158        } else {
159            snapToPageWithVelocity(whichPage, 0, false);
160        }
161     }
162 
163     @Override
computeScroll()164     public void computeScroll() {
165         if (mScrollMode == X_LARGE_MODE) {
166             super.computeScroll();
167         } else {
168             boolean scrollComputed = computeScrollHelper();
169 
170             if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
171                 final float now = System.nanoTime() / NANOTIME_DIV;
172                 final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
173 
174                 final float dx = mTouchX - mUnboundedScrollX;
175                 scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY());
176                 mSmoothingTime = now;
177 
178                 // Keep generating points as long as we're more than 1px away from the target
179                 if (dx > 1.f || dx < -1.f) {
180                     invalidate();
181                 }
182             }
183         }
184     }
185 }
186