blob: 37f2528205f700dc93d01f3321acb0180110937d [file] [log] [blame]
Jason Monk794457a2016-02-18 13:22:14 -05001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.qs;
16
Jason Monkfa0f47a2016-03-08 09:17:56 -050017import android.util.FloatProperty;
Jason Monk794457a2016-02-18 13:22:14 -050018import android.util.MathUtils;
19import android.util.Property;
Jason Monk8d1253e2016-02-20 08:43:27 -050020import android.view.View;
Jason Monk794457a2016-02-18 13:22:14 -050021import android.view.animation.Interpolator;
22
23import java.util.ArrayList;
24import java.util.List;
25
26/**
27 * Helper class, that handles similar properties as animators (delay, interpolators)
28 * but can have a float input as to the amount they should be in effect. This allows
29 * easier animation that tracks input.
30 *
31 * All "delays" and "times" are as fractions from 0-1.
32 */
33public class TouchAnimator {
34
35 private final Object[] mTargets;
Jason Monk794457a2016-02-18 13:22:14 -050036 private final KeyframeSet[] mKeyframeSets;
37 private final float mStartDelay;
38 private final float mEndDelay;
39 private final float mSpan;
40 private final Interpolator mInterpolator;
41 private final Listener mListener;
Jason Monkdf5459d2016-02-29 10:47:35 -050042 private float mLastT = -1;
Jason Monk794457a2016-02-18 13:22:14 -050043
Jason Monke80654b2016-02-24 14:53:57 -050044 private TouchAnimator(Object[] targets, KeyframeSet[] keyframeSets,
Jason Monk794457a2016-02-18 13:22:14 -050045 float startDelay, float endDelay, Interpolator interpolator, Listener listener) {
46 mTargets = targets;
Jason Monk794457a2016-02-18 13:22:14 -050047 mKeyframeSets = keyframeSets;
48 mStartDelay = startDelay;
49 mEndDelay = endDelay;
50 mSpan = (1 - mEndDelay - mStartDelay);
51 mInterpolator = interpolator;
52 mListener = listener;
53 }
54
55 public void setPosition(float fraction) {
56 float t = MathUtils.constrain((fraction - mStartDelay) / mSpan, 0, 1);
57 if (mInterpolator != null) {
58 t = mInterpolator.getInterpolation(t);
59 }
Jason Monkdf5459d2016-02-29 10:47:35 -050060 if (t == mLastT) {
61 return;
62 }
Jason Monk794457a2016-02-18 13:22:14 -050063 if (mListener != null) {
Jason Monkdf5459d2016-02-29 10:47:35 -050064 if (t == 1) {
Jason Monk794457a2016-02-18 13:22:14 -050065 mListener.onAnimationAtEnd();
66 } else if (t == 0) {
67 mListener.onAnimationAtStart();
Jason Monkdf5459d2016-02-29 10:47:35 -050068 } else if (mLastT <= 0 || mLastT == 1) {
69 mListener.onAnimationStarted();
Jason Monk794457a2016-02-18 13:22:14 -050070 }
71 mLastT = t;
72 }
73 for (int i = 0; i < mTargets.length; i++) {
Jason Monke80654b2016-02-24 14:53:57 -050074 mKeyframeSets[i].setValue(t, mTargets[i]);
Jason Monk794457a2016-02-18 13:22:14 -050075 }
76 }
77
Jason Monkfa0f47a2016-03-08 09:17:56 -050078 private static final FloatProperty<TouchAnimator> POSITION =
79 new FloatProperty<TouchAnimator>("position") {
80 @Override
81 public void setValue(TouchAnimator touchAnimator, float value) {
82 touchAnimator.setPosition(value);
83 }
84
85 @Override
86 public Float get(TouchAnimator touchAnimator) {
87 return touchAnimator.mLastT;
88 }
89 };
90
Jason Monk794457a2016-02-18 13:22:14 -050091 public static class ListenerAdapter implements Listener {
92 @Override
93 public void onAnimationAtStart() { }
94
95 @Override
96 public void onAnimationAtEnd() { }
97
98 @Override
99 public void onAnimationStarted() { }
100 }
101
102 public interface Listener {
103 /**
104 * Called when the animator moves into a position of "0". Start and end delays are
105 * taken into account, so this position may cover a range of fractional inputs.
106 */
107 void onAnimationAtStart();
108
109 /**
Evan Laird92fbcb22018-02-16 15:25:53 +0000110 * Called when the animator moves into a position of "0". Start and end delays are
Jason Monk794457a2016-02-18 13:22:14 -0500111 * taken into account, so this position may cover a range of fractional inputs.
112 */
113 void onAnimationAtEnd();
114
115 /**
116 * Called when the animator moves out of the start or end position and is in a transient
117 * state.
118 */
119 void onAnimationStarted();
120 }
121
122 public static class Builder {
123 private List<Object> mTargets = new ArrayList<>();
Jason Monk794457a2016-02-18 13:22:14 -0500124 private List<KeyframeSet> mValues = new ArrayList<>();
125
126 private float mStartDelay;
127 private float mEndDelay;
128 private Interpolator mInterpolator;
129 private Listener mListener;
130
131 public Builder addFloat(Object target, String property, float... values) {
Jason Monkdf5459d2016-02-29 10:47:35 -0500132 add(target, KeyframeSet.ofFloat(getProperty(target, property, float.class), values));
Jason Monk794457a2016-02-18 13:22:14 -0500133 return this;
134 }
135
136 public Builder addInt(Object target, String property, int... values) {
Jason Monkdf5459d2016-02-29 10:47:35 -0500137 add(target, KeyframeSet.ofInt(getProperty(target, property, int.class), values));
Jason Monk794457a2016-02-18 13:22:14 -0500138 return this;
139 }
140
Jason Monke80654b2016-02-24 14:53:57 -0500141 private void add(Object target, KeyframeSet keyframeSet) {
Jason Monk794457a2016-02-18 13:22:14 -0500142 mTargets.add(target);
Jason Monk794457a2016-02-18 13:22:14 -0500143 mValues.add(keyframeSet);
144 }
145
Jason Monkdf5459d2016-02-29 10:47:35 -0500146 private static Property getProperty(Object target, String property, Class<?> cls) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500147 if (target instanceof View) {
148 switch (property) {
149 case "translationX":
150 return View.TRANSLATION_X;
151 case "translationY":
152 return View.TRANSLATION_Y;
153 case "translationZ":
154 return View.TRANSLATION_Z;
155 case "alpha":
156 return View.ALPHA;
157 case "rotation":
158 return View.ROTATION;
159 case "x":
160 return View.X;
161 case "y":
162 return View.Y;
163 case "scaleX":
164 return View.SCALE_X;
165 case "scaleY":
166 return View.SCALE_Y;
167 }
168 }
Jason Monkfa0f47a2016-03-08 09:17:56 -0500169 if (target instanceof TouchAnimator && "position".equals(property)) {
170 return POSITION;
171 }
Jason Monkdf5459d2016-02-29 10:47:35 -0500172 return Property.of(target.getClass(), cls, property);
Jason Monk8d1253e2016-02-20 08:43:27 -0500173 }
174
Jason Monk794457a2016-02-18 13:22:14 -0500175 public Builder setStartDelay(float startDelay) {
176 mStartDelay = startDelay;
177 return this;
178 }
179
180 public Builder setEndDelay(float endDelay) {
181 mEndDelay = endDelay;
182 return this;
183 }
184
185 public Builder setInterpolator(Interpolator intepolator) {
186 mInterpolator = intepolator;
187 return this;
188 }
189
190 public Builder setListener(Listener listener) {
191 mListener = listener;
192 return this;
193 }
194
195 public TouchAnimator build() {
196 return new TouchAnimator(mTargets.toArray(new Object[mTargets.size()]),
Jason Monk794457a2016-02-18 13:22:14 -0500197 mValues.toArray(new KeyframeSet[mValues.size()]),
198 mStartDelay, mEndDelay, mInterpolator, mListener);
199 }
200 }
201
202 private static abstract class KeyframeSet {
203
Jason Monk8d1253e2016-02-20 08:43:27 -0500204 private final float mFrameWidth;
205 private final int mSize;
Jason Monk794457a2016-02-18 13:22:14 -0500206
Jason Monk8d1253e2016-02-20 08:43:27 -0500207 public KeyframeSet(int size) {
208 mSize = size;
209 mFrameWidth = 1 / (float) (size - 1);
Jason Monk794457a2016-02-18 13:22:14 -0500210 }
211
Jason Monke80654b2016-02-24 14:53:57 -0500212 void setValue(float fraction, Object target) {
Jason Monk794457a2016-02-18 13:22:14 -0500213 int i;
Jason Monk8d1253e2016-02-20 08:43:27 -0500214 for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
215 float amount = fraction / mFrameWidth;
Jason Monke80654b2016-02-24 14:53:57 -0500216 interpolate(i, amount, target);
Jason Monk794457a2016-02-18 13:22:14 -0500217 }
218
Jason Monke80654b2016-02-24 14:53:57 -0500219 protected abstract void interpolate(int index, float amount, Object target);
Jason Monk794457a2016-02-18 13:22:14 -0500220
Jason Monke80654b2016-02-24 14:53:57 -0500221 public static KeyframeSet ofInt(Property property, int... values) {
222 return new IntKeyframeSet((Property<?, Integer>) property, values);
Jason Monk794457a2016-02-18 13:22:14 -0500223 }
224
Jason Monke80654b2016-02-24 14:53:57 -0500225 public static KeyframeSet ofFloat(Property property, float... values) {
226 return new FloatKeyframeSet((Property<?, Float>) property, values);
Jason Monk794457a2016-02-18 13:22:14 -0500227 }
228 }
229
Jason Monke80654b2016-02-24 14:53:57 -0500230 private static class FloatKeyframeSet<T> extends KeyframeSet {
Jason Monk8d1253e2016-02-20 08:43:27 -0500231 private final float[] mValues;
Jason Monke80654b2016-02-24 14:53:57 -0500232 private final Property<T, Float> mProperty;
Jason Monk8d1253e2016-02-20 08:43:27 -0500233
Jason Monke80654b2016-02-24 14:53:57 -0500234 public FloatKeyframeSet(Property<T, Float> property, float[] values) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500235 super(values.length);
Jason Monke80654b2016-02-24 14:53:57 -0500236 mProperty = property;
Jason Monk8d1253e2016-02-20 08:43:27 -0500237 mValues = values;
Jason Monk794457a2016-02-18 13:22:14 -0500238 }
239
240 @Override
Jason Monke80654b2016-02-24 14:53:57 -0500241 protected void interpolate(int index, float amount, Object target) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500242 float firstFloat = mValues[index - 1];
243 float secondFloat = mValues[index];
Jason Monke80654b2016-02-24 14:53:57 -0500244 mProperty.set((T) target, firstFloat + (secondFloat - firstFloat) * amount);
Jason Monk794457a2016-02-18 13:22:14 -0500245 }
246 }
247
Jason Monke80654b2016-02-24 14:53:57 -0500248 private static class IntKeyframeSet<T> extends KeyframeSet {
Jason Monk8d1253e2016-02-20 08:43:27 -0500249 private final int[] mValues;
Jason Monke80654b2016-02-24 14:53:57 -0500250 private final Property<T, Integer> mProperty;
Jason Monk8d1253e2016-02-20 08:43:27 -0500251
Jason Monke80654b2016-02-24 14:53:57 -0500252 public IntKeyframeSet(Property<T, Integer> property, int[] values) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500253 super(values.length);
Jason Monke80654b2016-02-24 14:53:57 -0500254 mProperty = property;
Jason Monk8d1253e2016-02-20 08:43:27 -0500255 mValues = values;
Jason Monk794457a2016-02-18 13:22:14 -0500256 }
257
258 @Override
Jason Monke80654b2016-02-24 14:53:57 -0500259 protected void interpolate(int index, float amount, Object target) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500260 int firstFloat = mValues[index - 1];
261 int secondFloat = mValues[index];
Jason Monke80654b2016-02-24 14:53:57 -0500262 mProperty.set((T) target, (int) (firstFloat + (secondFloat - firstFloat) * amount));
Jason Monk794457a2016-02-18 13:22:14 -0500263 }
264 }
Jason Monk794457a2016-02-18 13:22:14 -0500265}