2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.recents.views;
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ObjectAnimator;
22 import android.animation.ValueAnimator;
23 import android.content.Context;
24 import android.widget.OverScroller;
25 import com.android.systemui.recents.RecentsConfiguration;
26 import com.android.systemui.recents.misc.Utilities;
28 /* The scrolling logic for a TaskStackView */
29 public class TaskStackViewScroller {
30 public interface TaskStackViewScrollerCallbacks {
31 public void onScrollChanged(float p);
34 RecentsConfiguration mConfig;
35 TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
36 TaskStackViewScrollerCallbacks mCb;
40 OverScroller mScroller;
41 ObjectAnimator mScrollAnimator;
42 float mFinalAnimatedScroll;
44 public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
46 mScroller = new OverScroller(context);
47 mLayoutAlgorithm = layoutAlgorithm;
48 setStackScroll(getStackScroll());
51 /** Resets the task scroller. */
56 /** Sets the callbacks */
57 void setCallbacks(TaskStackViewScrollerCallbacks cb) {
61 /** Gets the current stack scroll */
62 public float getStackScroll() {
66 /** Sets the current stack scroll */
67 public void setStackScroll(float s) {
70 mCb.onScrollChanged(mStackScrollP);
74 /** Sets the current stack scroll without calling the callback. */
75 void setStackScrollRaw(float s) {
80 * Sets the current stack scroll to the initial state when you first enter recents.
81 * @return whether the stack progress changed.
83 public boolean setStackScrollToInitialState() {
84 float prevStackScrollP = mStackScrollP;
85 setStackScroll(getBoundedStackScroll(mLayoutAlgorithm.mInitialScrollP));
86 return Float.compare(prevStackScrollP, mStackScrollP) != 0;
89 /** Bounds the current scroll if necessary */
90 public boolean boundScroll() {
91 float curScroll = getStackScroll();
92 float newScroll = getBoundedStackScroll(curScroll);
93 if (Float.compare(newScroll, curScroll) != 0) {
94 setStackScroll(newScroll);
99 /** Bounds the current scroll if necessary, but does not synchronize the stack view with the model. */
100 public boolean boundScrollRaw() {
101 float curScroll = getStackScroll();
102 float newScroll = getBoundedStackScroll(curScroll);
103 if (Float.compare(newScroll, curScroll) != 0) {
104 setStackScrollRaw(newScroll);
110 /** Returns the bounded stack scroll */
111 float getBoundedStackScroll(float scroll) {
112 return Math.max(mLayoutAlgorithm.mMinScrollP, Math.min(mLayoutAlgorithm.mMaxScrollP, scroll));
115 /** Returns the amount that the absolute value of how much the scroll is out of bounds. */
116 float getScrollAmountOutOfBounds(float scroll) {
117 if (scroll < mLayoutAlgorithm.mMinScrollP) {
118 return Math.abs(scroll - mLayoutAlgorithm.mMinScrollP);
119 } else if (scroll > mLayoutAlgorithm.mMaxScrollP) {
120 return Math.abs(scroll - mLayoutAlgorithm.mMaxScrollP);
125 /** Returns whether the specified scroll is out of bounds */
126 boolean isScrollOutOfBounds() {
127 return Float.compare(getScrollAmountOutOfBounds(mStackScrollP), 0f) != 0;
130 /** Animates the stack scroll into bounds */
131 ObjectAnimator animateBoundScroll() {
132 float curScroll = getStackScroll();
133 float newScroll = getBoundedStackScroll(curScroll);
134 if (Float.compare(newScroll, curScroll) != 0) {
135 // Start a new scroll animation
136 animateScroll(curScroll, newScroll, null);
138 return mScrollAnimator;
141 /** Animates the stack scroll */
142 void animateScroll(float curScroll, float newScroll, final Runnable postRunnable) {
143 // Finish any current scrolling animations
144 if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
145 setStackScroll(mFinalAnimatedScroll);
146 mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0);
149 stopBoundScrollAnimation();
151 mFinalAnimatedScroll = newScroll;
152 mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
153 mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
154 mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
155 mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
157 public void onAnimationUpdate(ValueAnimator animation) {
158 setStackScroll((Float) animation.getAnimatedValue());
161 mScrollAnimator.addListener(new AnimatorListenerAdapter() {
163 public void onAnimationEnd(Animator animation) {
164 if (postRunnable != null) {
167 mScrollAnimator.removeAllListeners();
170 mScrollAnimator.start();
173 /** Aborts any current stack scrolls */
174 void stopBoundScrollAnimation() {
175 Utilities.cancelAnimationWithoutCallbacks(mScrollAnimator);
178 /**** OverScroller ****/
180 int progressToScrollRange(float p) {
181 return (int) (p * mLayoutAlgorithm.mStackVisibleRect.height());
184 float scrollRangeToProgress(int s) {
185 return (float) s / mLayoutAlgorithm.mStackVisibleRect.height();
188 /** Called from the view draw, computes the next scroll. */
189 boolean computeScroll() {
190 if (mScroller.computeScrollOffset()) {
191 float scroll = scrollRangeToProgress(mScroller.getCurrY());
192 setStackScrollRaw(scroll);
194 mCb.onScrollChanged(scroll);
201 /** Returns whether the overscroller is scrolling. */
202 boolean isScrolling() {
203 return !mScroller.isFinished();
206 /** Stops the scroller and any current fling. */
207 void stopScroller() {
208 if (!mScroller.isFinished()) {
209 mScroller.abortAnimation();