• 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.launcher2;
18 
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.view.animation.Interpolator;
22 import android.widget.Scroller;
23 
24 public abstract class SmoothPagedView extends PagedView {
25     private static final float SMOOTHING_SPEED = 0.75f;
26     private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED));
27 
28     private float mBaseLineFlingVelocity;
29     private float mFlingVelocityInfluence;
30 
31     static final int DEFAULT_MODE = 0;
32     static final int X_LARGE_MODE = 1;
33 
34     int mScrollMode;
35 
36     private Interpolator mScrollInterpolator;
37 
38     public static class OvershootInterpolator implements Interpolator {
39         private static final float DEFAULT_TENSION = 1.3f;
40         private float mTension;
41 
OvershootInterpolator()42         public OvershootInterpolator() {
43             mTension = DEFAULT_TENSION;
44         }
45 
setDistance(int distance)46         public void setDistance(int distance) {
47             mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
48         }
49 
disableSettle()50         public void disableSettle() {
51             mTension = 0.f;
52         }
53 
getInterpolation(float t)54         public float getInterpolation(float t) {
55             // _o(t) = t * t * ((tension + 1) * t + tension)
56             // o(t) = _o(t - 1) + 1
57             t -= 1.0f;
58             return t * t * ((mTension + 1) * t + mTension) + 1.0f;
59         }
60     }
61 
62     /**
63      * Used to inflate the Workspace from XML.
64      *
65      * @param context The application's context.
66      * @param attrs The attributes set containing the Workspace's customization values.
67      */
SmoothPagedView(Context context, AttributeSet attrs)68     public SmoothPagedView(Context context, AttributeSet attrs) {
69         this(context, attrs, 0);
70     }
71 
72     /**
73      * Used to inflate the Workspace from XML.
74      *
75      * @param context The application's context.
76      * @param attrs The attributes set containing the Workspace's customization values.
77      * @param defStyle Unused.
78      */
SmoothPagedView(Context context, AttributeSet attrs, int defStyle)79     public SmoothPagedView(Context context, AttributeSet attrs, int defStyle) {
80         super(context, attrs, defStyle);
81 
82         mUsePagingTouchSlop = false;
83 
84         // This means that we'll take care of updating the scroll parameter ourselves (we do it
85         // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
86         mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
87     }
88 
getScrollMode()89     protected int getScrollMode() {
90         return X_LARGE_MODE;
91     }
92 
93     /**
94      * Initializes various states for this workspace.
95      */
96     @Override
init()97     protected void init() {
98         super.init();
99 
100         mScrollMode = getScrollMode();
101         if (mScrollMode == DEFAULT_MODE) {
102             mBaseLineFlingVelocity = 2500.0f;
103             mFlingVelocityInfluence = 0.4f;
104             mScrollInterpolator = new OvershootInterpolator();
105             mScroller = new Scroller(getContext(), mScrollInterpolator);
106         }
107     }
108 
109     @Override
snapToDestination()110     protected void snapToDestination() {
111         if (mScrollMode == X_LARGE_MODE) {
112             super.snapToDestination();
113         } else {
114             snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
115         }
116     }
117 
118     @Override
snapToPageWithVelocity(int whichPage, int velocity)119     protected void snapToPageWithVelocity(int whichPage, int velocity) {
120         if (mScrollMode == X_LARGE_MODE) {
121             super.snapToPageWithVelocity(whichPage, velocity);
122         } else {
123             snapToPageWithVelocity(whichPage, 0, true);
124         }
125     }
126 
snapToPageWithVelocity(int whichPage, int velocity, boolean settle)127     private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
128             // if (!mScroller.isFinished()) return;
129 
130         whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
131 
132         final int screenDelta = Math.max(1, Math.abs(whichPage - mCurrentPage));
133         final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
134         final int delta = newX - mUnboundedScrollX;
135         int duration = (screenDelta + 1) * 100;
136 
137         if (!mScroller.isFinished()) {
138             mScroller.abortAnimation();
139         }
140 
141         if (settle) {
142             ((OvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
143         } else {
144             ((OvershootInterpolator) mScrollInterpolator).disableSettle();
145         }
146 
147         velocity = Math.abs(velocity);
148         if (velocity > 0) {
149             duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
150         } else {
151             duration += 100;
152         }
153 
154         snapToPage(whichPage, delta, duration);
155     }
156 
157     @Override
snapToPage(int whichPage)158     protected void snapToPage(int whichPage) {
159        if (mScrollMode == X_LARGE_MODE) {
160            super.snapToPage(whichPage);
161        } else {
162            snapToPageWithVelocity(whichPage, 0, false);
163        }
164     }
165 
166     @Override
computeScroll()167     public void computeScroll() {
168         if (mScrollMode == X_LARGE_MODE) {
169             super.computeScroll();
170         } else {
171             boolean scrollComputed = computeScrollHelper();
172 
173             if (!scrollComputed && mTouchState == TOUCH_STATE_SCROLLING) {
174                 final float now = System.nanoTime() / NANOTIME_DIV;
175                 final float e = (float) Math.exp((now - mSmoothingTime) / SMOOTHING_CONSTANT);
176 
177                 final float dx = mTouchX - mUnboundedScrollX;
178                 scrollTo(Math.round(mUnboundedScrollX + dx * e), getScrollY());
179                 mSmoothingTime = now;
180 
181                 // Keep generating points as long as we're more than 1px away from the target
182                 if (dx > 1.f || dx < -1.f) {
183                     invalidate();
184                 }
185             }
186         }
187     }
188 }
189