1 /*
2  * Copyright (C) 2019 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 package com.android.quickstep.util;
17 
18 import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
19 
20 import static java.lang.annotation.RetentionPolicy.SOURCE;
21 
22 import android.animation.Animator;
23 import android.content.Context;
24 import android.graphics.PointF;
25 import android.graphics.Rect;
26 import android.graphics.RectF;
27 
28 import androidx.annotation.IntDef;
29 import androidx.annotation.Nullable;
30 import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
31 import androidx.dynamicanimation.animation.FloatPropertyCompat;
32 import androidx.dynamicanimation.animation.SpringAnimation;
33 import androidx.dynamicanimation.animation.SpringForce;
34 
35 import com.android.launcher3.DeviceProfile;
36 import com.android.launcher3.R;
37 import com.android.launcher3.Utilities;
38 import com.android.launcher3.anim.FlingSpringAnim;
39 import com.android.launcher3.touch.OverScroll;
40 import com.android.launcher3.util.DynamicResource;
41 import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
42 import com.android.systemui.plugins.ResourceProvider;
43 
44 import java.lang.annotation.Retention;
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 
49 /**
50  * Applies spring forces to animate from a starting rect to a target rect,
51  * while providing update callbacks to the caller.
52  */
53 public class RectFSpringAnim extends ReleaseCheck {
54 
55     private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_X =
56             new FloatPropertyCompat<RectFSpringAnim>("rectCenterXSpring") {
57                 @Override
58                 public float getValue(RectFSpringAnim anim) {
59                     return anim.mCurrentCenterX;
60                 }
61 
62                 @Override
63                 public void setValue(RectFSpringAnim anim, float currentCenterX) {
64                     anim.mCurrentCenterX = currentCenterX;
65                     anim.onUpdate();
66                 }
67             };
68 
69     private static final FloatPropertyCompat<RectFSpringAnim> RECT_Y =
70             new FloatPropertyCompat<RectFSpringAnim>("rectYSpring") {
71                 @Override
72                 public float getValue(RectFSpringAnim anim) {
73                     return anim.mCurrentY;
74                 }
75 
76                 @Override
77                 public void setValue(RectFSpringAnim anim, float y) {
78                     anim.mCurrentY = y;
79                     anim.onUpdate();
80                 }
81             };
82 
83     private static final FloatPropertyCompat<RectFSpringAnim> RECT_SCALE_PROGRESS =
84             new FloatPropertyCompat<RectFSpringAnim>("rectScaleProgress") {
85                 @Override
86                 public float getValue(RectFSpringAnim object) {
87                     return object.mCurrentScaleProgress;
88                 }
89 
90                 @Override
91                 public void setValue(RectFSpringAnim object, float value) {
92                     object.mCurrentScaleProgress = value;
93                     object.onUpdate();
94                 }
95             };
96 
97     private final RectF mStartRect;
98     private final RectF mTargetRect;
99     private final RectF mCurrentRect = new RectF();
100     private final List<OnUpdateListener> mOnUpdateListeners = new ArrayList<>();
101     private final List<Animator.AnimatorListener> mAnimatorListeners = new ArrayList<>();
102 
103     private float mCurrentCenterX;
104     private float mCurrentY;
105     // If true, tracking the bottom of the rects, else tracking the top.
106     private float mCurrentScaleProgress;
107     private FlingSpringAnim mRectXAnim;
108     private FlingSpringAnim mRectYAnim;
109     private SpringAnimation mRectXSpring;
110     private SpringAnimation mRectYSpring;
111     private SpringAnimation mRectScaleAnim;
112     private boolean mAnimsStarted;
113     private boolean mRectXAnimEnded;
114     private boolean mRectYAnimEnded;
115     private boolean mRectScaleAnimEnded;
116 
117     private float mMinVisChange;
118     private int mMaxVelocityPxPerS;
119 
120     /**
121      * Indicates which part of the start & target rects we are interpolating between.
122      */
123     public static final int TRACKING_TOP = 0;
124     public static final int TRACKING_CENTER = 1;
125     public static final int TRACKING_BOTTOM = 2;
126 
127     @Retention(SOURCE)
128     @IntDef(value = {TRACKING_TOP,
129                     TRACKING_CENTER,
130                     TRACKING_BOTTOM})
131     public @interface Tracking{}
132 
133     @Tracking
134     public final int mTracking;
135     protected final float mStiffnessX;
136     protected final float mStiffnessY;
137     protected final float mDampingX;
138     protected final float mDampingY;
139     protected final float mRectStiffness;
140 
RectFSpringAnim(SpringConfig config)141     public RectFSpringAnim(SpringConfig config) {
142         mStartRect = config.startRect;
143         mTargetRect = config.targetRect;
144         mCurrentCenterX = mStartRect.centerX();
145 
146         mMinVisChange = config.minVisChange;
147         mMaxVelocityPxPerS = config.maxVelocityPxPerS;
148         setCanRelease(true);
149 
150         mTracking = config.tracking;
151         mStiffnessX = config.stiffnessX;
152         mStiffnessY = config.stiffnessY;
153         mDampingX = config.dampingX;
154         mDampingY = config.dampingY;
155         mRectStiffness = config.rectStiffness;
156 
157         mCurrentY = getTrackedYFromRect(mStartRect);
158     }
159 
getTargetRect()160     public RectF getTargetRect() {
161         return mTargetRect;
162     }
163 
getTrackedYFromRect(RectF rect)164     private float getTrackedYFromRect(RectF rect) {
165         switch (mTracking) {
166             case TRACKING_TOP:
167                 return rect.top;
168             case TRACKING_BOTTOM:
169                 return rect.bottom;
170             case TRACKING_CENTER:
171             default:
172                 return rect.centerY();
173         }
174     }
175 
onTargetPositionChanged()176     public void onTargetPositionChanged() {
177         if (enableScalingRevealHomeAnimation()) {
178             if (isEnded()) {
179                 return;
180             }
181 
182             if (mRectXSpring != null) {
183                 mRectXSpring.animateToFinalPosition(mTargetRect.centerX());
184                 mRectXAnimEnded = false;
185             }
186 
187             if (mRectYSpring != null) {
188                 switch (mTracking) {
189                     case TRACKING_TOP:
190                         mRectYSpring.animateToFinalPosition(mTargetRect.top);
191                         break;
192                     case TRACKING_BOTTOM:
193                         mRectYSpring.animateToFinalPosition(mTargetRect.bottom);
194                         break;
195                     case TRACKING_CENTER:
196                         mRectYSpring.animateToFinalPosition(mTargetRect.centerY());
197                         break;
198                 }
199                 mRectYAnimEnded = false;
200             }
201         } else {
202             if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
203                 mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX());
204             }
205 
206             if (mRectYAnim != null) {
207                 switch (mTracking) {
208                     case TRACKING_TOP:
209                         if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
210                             mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
211                         }
212                         break;
213                     case TRACKING_BOTTOM:
214                         if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
215                             mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
216                         }
217                         break;
218                     case TRACKING_CENTER:
219                         if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
220                             mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
221                         }
222                         break;
223                 }
224             }
225         }
226     }
227 
addOnUpdateListener(OnUpdateListener onUpdateListener)228     public void addOnUpdateListener(OnUpdateListener onUpdateListener) {
229         mOnUpdateListeners.add(onUpdateListener);
230     }
231 
addAnimatorListener(Animator.AnimatorListener animatorListener)232     public void addAnimatorListener(Animator.AnimatorListener animatorListener) {
233         mAnimatorListeners.add(animatorListener);
234     }
235 
236     /**
237      * Starts the fling/spring animation.
238      * @param context The activity context.
239      * @param velocityPxPerMs Velocity of swipe in px/ms.
240      */
start(Context context, @Nullable DeviceProfile profile, PointF velocityPxPerMs)241     public void start(Context context, @Nullable DeviceProfile profile, PointF velocityPxPerMs) {
242         // Only tell caller that we ended if both x and y animations have ended.
243         OnAnimationEndListener onXEndListener = ((animation, canceled, centerX, velocityX) -> {
244             mRectXAnimEnded = true;
245             maybeOnEnd();
246         });
247         OnAnimationEndListener onYEndListener = ((animation, canceled, centerY, velocityY) -> {
248             mRectYAnimEnded = true;
249             maybeOnEnd();
250         });
251 
252         float xVelocityPxPerS = velocityPxPerMs.x * 1000;
253         float yVelocityPxPerS = velocityPxPerMs.y * 1000;
254         float startX = mCurrentCenterX;
255         float endX = mTargetRect.centerX();
256         float startY = mCurrentY;
257         float endY = getTrackedYFromRect(mTargetRect);
258         float minVisibleChange = Math.abs(1f / mStartRect.height());
259 
260         if (enableScalingRevealHomeAnimation()) {
261             ResourceProvider rp = DynamicResource.provider(context);
262             long minVelocityXPxPerS = rp.getInt(R.dimen.swipe_up_min_velocity_x_px_per_s);
263             long maxVelocityXPxPerS = rp.getInt(R.dimen.swipe_up_max_velocity_x_px_per_s);
264             long minVelocityYPxPerS = rp.getInt(R.dimen.swipe_up_min_velocity_y_px_per_s);
265             long maxVelocityYPxPerS = rp.getInt(R.dimen.swipe_up_max_velocity_y_px_per_s);
266             float fallOffFactor = rp.getFloat(R.dimen.swipe_up_max_velocity_fall_off_factor);
267 
268             // We want the actual initial velocity to never dip below the minimum, and to taper off
269             // once it's above the soft cap so that we can prevent the window from flying off
270             // screen, while maintaining a natural feel.
271             xVelocityPxPerS = adjustVelocity(
272                     xVelocityPxPerS, minVelocityXPxPerS, maxVelocityXPxPerS, fallOffFactor);
273             yVelocityPxPerS = adjustVelocity(
274                     yVelocityPxPerS, minVelocityYPxPerS, maxVelocityYPxPerS, fallOffFactor);
275 
276             float stiffnessX = rp.getFloat(R.dimen.swipe_up_rect_x_stiffness);
277             float dampingX = rp.getFloat(R.dimen.swipe_up_rect_x_damping_ratio);
278             mRectXSpring =
279                     new SpringAnimation(this, RECT_CENTER_X)
280                             .setSpring(
281                                     new SpringForce(endX)
282                                             .setStiffness(stiffnessX)
283                                             .setDampingRatio(dampingX)
284                             ).setStartValue(startX)
285                             .setStartVelocity(xVelocityPxPerS)
286                             .addEndListener(onXEndListener);
287 
288             float stiffnessY = rp.getFloat(R.dimen.swipe_up_rect_y_stiffness);
289             float dampingY = rp.getFloat(R.dimen.swipe_up_rect_y_damping_ratio);
290             mRectYSpring =
291                     new SpringAnimation(this, RECT_Y)
292                             .setSpring(
293                                     new SpringForce(endY)
294                                             .setStiffness(stiffnessY)
295                                             .setDampingRatio(dampingY)
296                             )
297                             .setStartValue(startY)
298                             .setStartVelocity(yVelocityPxPerS)
299                             .addEndListener(onYEndListener);
300 
301             float stiffnessZ = rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness_v2);
302             float dampingZ = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio_v2);
303             mRectScaleAnim =
304                     new SpringAnimation(this, RECT_SCALE_PROGRESS)
305                             .setSpring(
306                                     new SpringForce(1f)
307                                             .setStiffness(stiffnessZ)
308                                             .setDampingRatio(dampingZ))
309                             .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
310                             .setMaxValue(1f)
311                             .setMinimumVisibleChange(minVisibleChange)
312                             .addEndListener((animation, canceled, value, velocity) -> {
313                                 mRectScaleAnimEnded = true;
314                                 maybeOnEnd();
315                             });
316 
317             setCanRelease(false);
318             mAnimsStarted = true;
319 
320             mRectXSpring.start();
321             mRectYSpring.start();
322         } else {
323             // We dampen the user velocity here to keep the natural feeling and to prevent the
324             // rect from straying too from a linear path.
325             final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
326                     Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
327             final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
328                     Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
329 
330             float minXValue = Math.min(startX, endX);
331             float maxXValue = Math.max(startX, endX);
332 
333             mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
334                     dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, mDampingX,
335                     mStiffnessX, onXEndListener);
336 
337             float minYValue = Math.min(startY, endY);
338             float maxYValue = Math.max(startY, endY);
339             mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY,
340                     dampedYVelocityPxPerS, mMinVisChange, minYValue, maxYValue, mDampingY,
341                     mStiffnessY, onYEndListener);
342 
343             ResourceProvider rp = DynamicResource.provider(context);
344             float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
345 
346             // Increase the stiffness for devices where we want the window size to transform
347             // quicker.
348             boolean shouldUseHigherStiffness = profile != null
349                     && (profile.isLandscape || profile.isTablet);
350             float stiffness = shouldUseHigherStiffness
351                     ? rp.getFloat(R.dimen.swipe_up_rect_scale_higher_stiffness)
352                     : rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
353 
354             mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
355                     .setSpring(new SpringForce(1f)
356                             .setDampingRatio(damping)
357                             .setStiffness(stiffness))
358                     .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
359                     .setMaxValue(1f)
360                     .setMinimumVisibleChange(minVisibleChange)
361                     .addEndListener((animation, canceled, value, velocity) -> {
362                         mRectScaleAnimEnded = true;
363                         maybeOnEnd();
364                     });
365 
366             setCanRelease(false);
367             mAnimsStarted = true;
368 
369             mRectXAnim.start();
370             mRectYAnim.start();
371         }
372 
373         mRectScaleAnim.start();
374         for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
375             animatorListener.onAnimationStart(null);
376         }
377     }
378 
end()379     public void end() {
380         if (mAnimsStarted) {
381             if (enableScalingRevealHomeAnimation()) {
382                 if (mRectXSpring.canSkipToEnd()) {
383                     mRectXSpring.skipToEnd();
384                 }
385                 if (mRectYSpring.canSkipToEnd()) {
386                     mRectYSpring.skipToEnd();
387                 }
388             } else {
389                 mRectXAnim.end();
390                 mRectYAnim.end();
391             }
392             if (mRectScaleAnim.canSkipToEnd()) {
393                 mRectScaleAnim.skipToEnd();
394             }
395             mCurrentScaleProgress = mRectScaleAnim.getSpring().getFinalPosition();
396 
397             // Ensures that we end the animation with the final values.
398             mRectXAnimEnded = false;
399             mRectYAnimEnded = false;
400             mRectScaleAnimEnded = false;
401             onUpdate();
402         }
403 
404         mRectXAnimEnded = true;
405         mRectYAnimEnded = true;
406         mRectScaleAnimEnded = true;
407         maybeOnEnd();
408     }
409 
isEnded()410     private boolean isEnded() {
411         return mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded;
412     }
413 
onUpdate()414     private void onUpdate() {
415         if (isEnded()) {
416             // Prevent further updates from being called. This can happen between callbacks for
417             // ending the x/y/scale animations.
418             return;
419         }
420 
421         if (!mOnUpdateListeners.isEmpty()) {
422             float currentWidth = Utilities.mapRange(mCurrentScaleProgress, mStartRect.width(),
423                     mTargetRect.width());
424             float currentHeight = Utilities.mapRange(mCurrentScaleProgress, mStartRect.height(),
425                     mTargetRect.height());
426             switch (mTracking) {
427                 case TRACKING_TOP:
428                     mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
429                             mCurrentY,
430                             mCurrentCenterX + currentWidth / 2,
431                             mCurrentY + currentHeight);
432                     break;
433                 case TRACKING_BOTTOM:
434                     mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
435                             mCurrentY - currentHeight,
436                             mCurrentCenterX + currentWidth / 2,
437                             mCurrentY);
438                     break;
439                 case TRACKING_CENTER:
440                     mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
441                             mCurrentY - currentHeight / 2,
442                             mCurrentCenterX + currentWidth / 2,
443                             mCurrentY + currentHeight / 2);
444                     break;
445             }
446             for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
447                 onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
448             }
449         }
450     }
451 
maybeOnEnd()452     private void maybeOnEnd() {
453         if (mAnimsStarted && isEnded()) {
454             mAnimsStarted = false;
455             setCanRelease(true);
456             for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
457                 animatorListener.onAnimationEnd(null);
458             }
459         }
460     }
461 
cancel()462     public void cancel() {
463         if (mAnimsStarted) {
464             for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
465                 onUpdateListener.onCancel();
466             }
467         }
468         end();
469     }
470 
471     /**
472      * Modify the given velocity so that it's never below the minimum value, and falls off by the
473      * given factor once it goes above the maximum value.
474      * In order for the max soft cap to be enforced, the fall-off factor must be >1.
475      */
adjustVelocity(float velocity, long min, long max, float factor)476     private static float adjustVelocity(float velocity, long min, long max, float factor) {
477         float sign = Math.signum(velocity);
478         float magnitude = Math.abs(velocity);
479 
480         // If the absolute velocity is less than the min, bump it up.
481         if (magnitude < min) {
482             return min * sign;
483         }
484 
485         // If the absolute velocity falls between min and max, or the fall-off factor is invalid,
486         // do nothing.
487         if (magnitude <= max || factor <= 1) {
488             return velocity;
489         }
490 
491         // Scale the excess velocity by the fall-off factor.
492         float excess = magnitude - max;
493         float scaled = (float) Math.pow(excess, 1f / factor);
494         return (max + scaled) * sign;
495     }
496 
497     public interface OnUpdateListener {
498         /**
499          * Called when an update is made to the animation.
500          * @param currentRect The rect of the window.
501          * @param progress [0, 1] The progress of the rect scale animation.
502          */
onUpdate(RectF currentRect, float progress)503         void onUpdate(RectF currentRect, float progress);
504 
onCancel()505         default void onCancel() { }
506     }
507 
508     private abstract static class SpringConfig {
509         protected RectF startRect;
510         protected RectF targetRect;
511         protected @Tracking int tracking;
512         protected float stiffnessX;
513         protected float stiffnessY;
514         protected float dampingX;
515         protected float dampingY;
516         protected float rectStiffness;
517         protected float minVisChange;
518         protected int maxVelocityPxPerS;
519 
SpringConfig(Context context, RectF start, RectF target)520         private SpringConfig(Context context, RectF start, RectF target) {
521             startRect = start;
522             targetRect = target;
523 
524             ResourceProvider rp = DynamicResource.provider(context);
525             minVisChange = rp.getDimension(R.dimen.swipe_up_fling_min_visible_change);
526             maxVelocityPxPerS = (int) rp.getDimension(R.dimen.swipe_up_max_velocity);
527         }
528     }
529 
530     /**
531      * Standard spring configuration parameters.
532      */
533     public static class DefaultSpringConfig extends SpringConfig {
534 
DefaultSpringConfig(Context context, DeviceProfile deviceProfile, RectF startRect, RectF targetRect)535         public DefaultSpringConfig(Context context, DeviceProfile deviceProfile,
536                 RectF startRect, RectF targetRect) {
537             super(context, startRect, targetRect);
538 
539             ResourceProvider rp = DynamicResource.provider(context);
540             tracking = getDefaultTracking(deviceProfile);
541             stiffnessX = rp.getFloat(R.dimen.swipe_up_rect_xy_stiffness);
542             stiffnessY = rp.getFloat(R.dimen.swipe_up_rect_xy_stiffness);
543             dampingX = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
544             dampingY = rp.getFloat(R.dimen.swipe_up_rect_xy_damping_ratio);
545 
546             this.startRect = startRect;
547             this.targetRect = targetRect;
548 
549             // Increase the stiffness for devices where we want the window size to transform
550             // quicker.
551             boolean shouldUseHigherStiffness = deviceProfile != null
552                     && (deviceProfile.isLandscape || deviceProfile.isTablet);
553             rectStiffness = shouldUseHigherStiffness
554                     ? rp.getFloat(R.dimen.swipe_up_rect_scale_higher_stiffness)
555                     : rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
556         }
557 
getDefaultTracking(@ullable DeviceProfile deviceProfile)558         private @Tracking int getDefaultTracking(@Nullable DeviceProfile deviceProfile) {
559             @Tracking int tracking;
560             if (deviceProfile == null) {
561                 tracking = startRect.bottom < targetRect.bottom
562                         ? TRACKING_BOTTOM
563                         : TRACKING_TOP;
564             } else {
565                 int heightPx = deviceProfile.heightPx;
566                 Rect padding = deviceProfile.workspacePadding;
567 
568                 final float topThreshold = heightPx / 3f;
569                 final float bottomThreshold = deviceProfile.heightPx - padding.bottom;
570 
571                 if (targetRect.bottom > bottomThreshold) {
572                     if (enableScalingRevealHomeAnimation()) {
573                         tracking = TRACKING_CENTER;
574                     } else {
575                         tracking = TRACKING_BOTTOM;
576                     }
577                 } else if (targetRect.top < topThreshold) {
578                     tracking = TRACKING_TOP;
579                 } else {
580                     tracking = TRACKING_CENTER;
581                 }
582             }
583             return tracking;
584         }
585     }
586 
587     /**
588      * Spring configuration parameters for Taskbar/Hotseat items on devices that have a taskbar.
589      */
590     public static class TaskbarHotseatSpringConfig extends SpringConfig {
591 
TaskbarHotseatSpringConfig(Context context, RectF start, RectF target)592         public TaskbarHotseatSpringConfig(Context context, RectF start, RectF target) {
593             super(context, start, target);
594 
595             ResourceProvider rp = DynamicResource.provider(context);
596             tracking = TRACKING_CENTER;
597             stiffnessX = rp.getFloat(R.dimen.taskbar_swipe_up_rect_x_stiffness);
598             stiffnessY = rp.getFloat(R.dimen.taskbar_swipe_up_rect_y_stiffness);
599             dampingX = rp.getFloat(R.dimen.taskbar_swipe_up_rect_x_damping);
600             dampingY = rp.getFloat(R.dimen.taskbar_swipe_up_rect_y_damping);
601             rectStiffness = rp.getFloat(R.dimen.taskbar_swipe_up_rect_scale_stiffness);
602         }
603     }
604 
605 }
606