blob: 8b0a835024d31fc58b9720eb43c19b50c993f778 [file] [log] [blame]
Michael Jurka0142d492010-08-25 17:46:15 -07001/*
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
17package com.android.launcher2;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.animation.Interpolator;
22import android.widget.Scroller;
23
Michael Jurka0142d492010-08-25 17:46:15 -070024public 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
Adam Cohenf34bab52010-09-30 14:11:56 -070028 private float mBaseLineFlingVelocity;
29 private float mFlingVelocityInfluence;
Michael Jurka0142d492010-08-25 17:46:15 -070030
Adam Cohene0f66b52010-11-23 15:06:07 -080031 static final int DEFAULT_MODE = 0;
32 static final int X_LARGE_MODE = 1;
Michael Jurka0142d492010-08-25 17:46:15 -070033
Adam Cohenf34bab52010-09-30 14:11:56 -070034 int mScrollMode;
35
36 private Interpolator mScrollInterpolator;
Michael Jurka0142d492010-08-25 17:46:15 -070037
38 private static class WorkspaceOvershootInterpolator implements Interpolator {
39 private static final float DEFAULT_TENSION = 1.3f;
40 private float mTension;
41
42 public WorkspaceOvershootInterpolator() {
43 mTension = DEFAULT_TENSION;
44 }
45
46 public void setDistance(int distance) {
47 mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION;
48 }
49
50 public void disableSettle() {
51 mTension = 0.f;
52 }
53
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 */
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 */
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
Adam Cohene0f66b52010-11-23 15:06:07 -080085 // in computeScroll), we only do this in the OVERSHOOT_MODE, ie. on phones
86 mDeferScrollUpdate = mScrollMode != X_LARGE_MODE;
Michael Jurka0142d492010-08-25 17:46:15 -070087 }
88
Adam Cohenf34bab52010-09-30 14:11:56 -070089 protected int getScrollMode() {
Adam Cohene0f66b52010-11-23 15:06:07 -080090 return DEFAULT_MODE;
Adam Cohenf34bab52010-09-30 14:11:56 -070091 }
92
Michael Jurka0142d492010-08-25 17:46:15 -070093 /**
94 * Initializes various states for this workspace.
95 */
96 @Override
97 protected void init() {
98 super.init();
Adam Cohenf34bab52010-09-30 14:11:56 -070099
100 mScrollMode = getScrollMode();
Adam Cohene0f66b52010-11-23 15:06:07 -0800101 if (mScrollMode == DEFAULT_MODE) {
Adam Cohenf34bab52010-09-30 14:11:56 -0700102 mBaseLineFlingVelocity = 2500.0f;
103 mFlingVelocityInfluence = 0.4f;
104 mScrollInterpolator = new WorkspaceOvershootInterpolator();
Adam Cohene0f66b52010-11-23 15:06:07 -0800105 mScroller = new Scroller(getContext(), mScrollInterpolator);
Adam Cohenf34bab52010-09-30 14:11:56 -0700106 }
Michael Jurka0142d492010-08-25 17:46:15 -0700107 }
108
109 @Override
110 protected void snapToDestination() {
Adam Cohene0f66b52010-11-23 15:06:07 -0800111 if (mScrollMode == X_LARGE_MODE) {
112 super.snapToDestination();
113 } else {
114 snapToPageWithVelocity(getPageNearestToCenterOfScreen(), 0);
115 }
Michael Jurka0142d492010-08-25 17:46:15 -0700116 }
117
118 @Override
119 protected void snapToPageWithVelocity(int whichPage, int velocity) {
Adam Cohene0f66b52010-11-23 15:06:07 -0800120 if (mScrollMode == X_LARGE_MODE) {
121 super.snapToPageWithVelocity(whichPage, velocity);
122 } else {
123 snapToPageWithVelocity(whichPage, 0, true);
124 }
Michael Jurka0142d492010-08-25 17:46:15 -0700125 }
126
Patrick Dubroy54fa3b92010-11-17 12:18:45 -0800127 private void snapToPageWithVelocity(int whichPage, int velocity, boolean settle) {
Michael Jurka0142d492010-08-25 17:46:15 -0700128 // 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));
Michael Jurka5f1c5092010-09-03 14:15:02 -0700133 final int newX = getChildOffset(whichPage) - getRelativeChildOffset(whichPage);
Adam Cohen68d73932010-11-15 10:50:58 -0800134 final int delta = newX - mUnboundedScrollX;
Adam Cohene0f66b52010-11-23 15:06:07 -0800135 int duration = (screenDelta + 1) * 100;
Michael Jurka0142d492010-08-25 17:46:15 -0700136
137 if (!mScroller.isFinished()) {
138 mScroller.abortAnimation();
139 }
140
Adam Cohene0f66b52010-11-23 15:06:07 -0800141 if (settle) {
142 ((WorkspaceOvershootInterpolator) mScrollInterpolator).setDistance(screenDelta);
143 } else {
144 ((WorkspaceOvershootInterpolator) mScrollInterpolator).disableSettle();
Michael Jurka0142d492010-08-25 17:46:15 -0700145 }
146
147 velocity = Math.abs(velocity);
148 if (velocity > 0) {
Adam Cohenf34bab52010-09-30 14:11:56 -0700149 duration += (duration / (velocity / mBaseLineFlingVelocity)) * mFlingVelocityInfluence;
Michael Jurka0142d492010-08-25 17:46:15 -0700150 } else {
151 duration += 100;
152 }
Adam Cohenf34bab52010-09-30 14:11:56 -0700153
Michael Jurka0142d492010-08-25 17:46:15 -0700154 snapToPage(whichPage, delta, duration);
155 }
156
157 @Override
158 protected void snapToPage(int whichPage) {
Adam Cohene0f66b52010-11-23 15:06:07 -0800159 if (mScrollMode == X_LARGE_MODE) {
160 super.snapToPage(whichPage);
161 } else {
162 snapToPageWithVelocity(whichPage, 0, false);
163 }
Michael Jurka0142d492010-08-25 17:46:15 -0700164 }
165
166 @Override
167 public void computeScroll() {
Adam Cohene0f66b52010-11-23 15:06:07 -0800168 if (mScrollMode == X_LARGE_MODE) {
169 super.computeScroll();
170 } else {
171 boolean scrollComputed = computeScrollHelper();
Michael Jurka0142d492010-08-25 17:46:15 -0700172
Adam Cohene0f66b52010-11-23 15:06:07 -0800173 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);
Adam Cohen68d73932010-11-15 10:50:58 -0800176
Adam Cohene0f66b52010-11-23 15:06:07 -0800177 final float dx = mTouchX - mUnboundedScrollX;
178 scrollTo(Math.round(mUnboundedScrollX + dx * e), mScrollY);
179 mSmoothingTime = now;
Michael Jurka0142d492010-08-25 17:46:15 -0700180
Adam Cohene0f66b52010-11-23 15:06:07 -0800181 // 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 }
Michael Jurka0142d492010-08-25 17:46:15 -0700185 }
186 }
Michael Jurka0142d492010-08-25 17:46:15 -0700187 }
188}