blob: aacb22ddaa905eb1189c8b508f5583e9271a956c [file] [log] [blame]
Selim Cinekf082fe22016-12-20 14:32:19 +01001/*
2 * Copyright (C) 2016 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.systemui.statusbar.notification;
18
19import android.animation.Animator;
20import android.animation.AnimatorListenerAdapter;
21import android.animation.PropertyValuesHolder;
22import android.animation.ValueAnimator;
23import android.util.Property;
24import android.view.View;
25import android.view.animation.Interpolator;
26
27import com.android.systemui.Interpolators;
Rohan Shah20790b82018-07-02 17:21:04 -070028import com.android.systemui.statusbar.notification.stack.AnimationFilter;
29import com.android.systemui.statusbar.notification.stack.AnimationProperties;
30import com.android.systemui.statusbar.notification.stack.ViewState;
Selim Cinekf082fe22016-12-20 14:32:19 +010031
32/**
33 * An animator to animate properties
34 */
35public class PropertyAnimator {
36
Selim Cinek0228a252017-11-10 17:47:27 -080037 public static <T extends View> void setProperty(final T view,
38 AnimatableProperty animatableProperty, float newEndValue,
39 AnimationProperties properties, boolean animated) {
40 int animatorTag = animatableProperty.getAnimatorTag();
41 ValueAnimator previousAnimator = ViewState.getChildTag(view, animatorTag);
42 if (previousAnimator != null || animated) {
43 startAnimation(view, animatableProperty, newEndValue, properties);
44 } else {
45 // no new animation needed, let's just apply the value
46 animatableProperty.getProperty().set(view, newEndValue);
47 }
48 }
49
Selim Cinekf082fe22016-12-20 14:32:19 +010050 public static <T extends View> void startAnimation(final T view,
51 AnimatableProperty animatableProperty, float newEndValue,
52 AnimationProperties properties) {
53 Property<T, Float> property = animatableProperty.getProperty();
54 int animationStartTag = animatableProperty.getAnimationStartTag();
55 int animationEndTag = animatableProperty.getAnimationEndTag();
56 Float previousStartValue = ViewState.getChildTag(view, animationStartTag);
57 Float previousEndValue = ViewState.getChildTag(view, animationEndTag);
58 if (previousEndValue != null && previousEndValue == newEndValue) {
59 return;
60 }
61 int animatorTag = animatableProperty.getAnimatorTag();
62 ValueAnimator previousAnimator = ViewState.getChildTag(view, animatorTag);
63 AnimationFilter filter = properties.getAnimationFilter();
64 if (!filter.shouldAnimateProperty(property)) {
65 // just a local update was performed
66 if (previousAnimator != null) {
67 // we need to increase all animation keyframes of the previous animator by the
68 // relative change to the end value
69 PropertyValuesHolder[] values = previousAnimator.getValues();
70 float relativeDiff = newEndValue - previousEndValue;
71 float newStartValue = previousStartValue + relativeDiff;
72 values[0].setFloatValues(newStartValue, newEndValue);
73 view.setTag(animationStartTag, newStartValue);
74 view.setTag(animationEndTag, newEndValue);
75 previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
76 return;
77 } else {
78 // no new animation needed, let's just apply the value
79 property.set(view, newEndValue);
80 return;
81 }
82 }
83
84 Float currentValue = property.get(view);
85 ValueAnimator animator = ValueAnimator.ofFloat(currentValue, newEndValue);
86 animator.addUpdateListener(
87 animation -> property.set(view, (Float) animation.getAnimatedValue()));
88 Interpolator customInterpolator = properties.getCustomInterpolator(view, property);
89 Interpolator interpolator = customInterpolator != null ? customInterpolator
90 : Interpolators.FAST_OUT_SLOW_IN;
91 animator.setInterpolator(interpolator);
92 long newDuration = ViewState.cancelAnimatorAndGetNewDuration(properties.duration,
93 previousAnimator);
94 animator.setDuration(newDuration);
95 if (properties.delay > 0 && (previousAnimator == null
96 || previousAnimator.getAnimatedFraction() == 0)) {
97 animator.setStartDelay(properties.delay);
98 }
99 AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
100 if (listener != null) {
101 animator.addListener(listener);
102 }
103 // remove the tag when the animation is finished
104 animator.addListener(new AnimatorListenerAdapter() {
105 @Override
106 public void onAnimationEnd(Animator animation) {
107 view.setTag(animatorTag, null);
108 view.setTag(animationStartTag, null);
109 view.setTag(animationEndTag, null);
110 }
111 });
112 ViewState.startAnimator(animator, listener);
113 view.setTag(animatorTag, animator);
114 view.setTag(animationStartTag, currentValue);
115 view.setTag(animationEndTag, newEndValue);
116 }
117
Lucas Dupin60661a62018-04-12 10:50:13 -0700118 public static <T extends View> boolean isAnimating(T view, AnimatableProperty property) {
119 return view.getTag(property.getAnimatorTag()) != null;
120 }
Selim Cinekf082fe22016-12-20 14:32:19 +0100121}