blob: 35ade580654a02ce1a02996e70bff2496b6c78da [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 Monk794457a2016-02-18 13:22:14 -050017import android.util.MathUtils;
18import android.util.Property;
Jason Monk8d1253e2016-02-20 08:43:27 -050019import android.view.View;
Jason Monk794457a2016-02-18 13:22:14 -050020import android.view.animation.Interpolator;
21
22import java.util.ArrayList;
23import java.util.List;
24
25/**
26 * Helper class, that handles similar properties as animators (delay, interpolators)
27 * but can have a float input as to the amount they should be in effect. This allows
28 * easier animation that tracks input.
29 *
30 * All "delays" and "times" are as fractions from 0-1.
31 */
32public class TouchAnimator {
33
34 private final Object[] mTargets;
Jason Monk794457a2016-02-18 13:22:14 -050035 private final KeyframeSet[] mKeyframeSets;
36 private final float mStartDelay;
37 private final float mEndDelay;
38 private final float mSpan;
39 private final Interpolator mInterpolator;
40 private final Listener mListener;
Jason Monkdf5459d2016-02-29 10:47:35 -050041 private float mLastT = -1;
Jason Monk794457a2016-02-18 13:22:14 -050042
Jason Monke80654b2016-02-24 14:53:57 -050043 private TouchAnimator(Object[] targets, KeyframeSet[] keyframeSets,
Jason Monk794457a2016-02-18 13:22:14 -050044 float startDelay, float endDelay, Interpolator interpolator, Listener listener) {
45 mTargets = targets;
Jason Monk794457a2016-02-18 13:22:14 -050046 mKeyframeSets = keyframeSets;
47 mStartDelay = startDelay;
48 mEndDelay = endDelay;
49 mSpan = (1 - mEndDelay - mStartDelay);
50 mInterpolator = interpolator;
51 mListener = listener;
52 }
53
54 public void setPosition(float fraction) {
55 float t = MathUtils.constrain((fraction - mStartDelay) / mSpan, 0, 1);
56 if (mInterpolator != null) {
57 t = mInterpolator.getInterpolation(t);
58 }
Jason Monkdf5459d2016-02-29 10:47:35 -050059 if (t == mLastT) {
60 return;
61 }
Jason Monk794457a2016-02-18 13:22:14 -050062 if (mListener != null) {
Jason Monkdf5459d2016-02-29 10:47:35 -050063 if (t == 1) {
Jason Monk794457a2016-02-18 13:22:14 -050064 mListener.onAnimationAtEnd();
65 } else if (t == 0) {
66 mListener.onAnimationAtStart();
Jason Monkdf5459d2016-02-29 10:47:35 -050067 } else if (mLastT <= 0 || mLastT == 1) {
68 mListener.onAnimationStarted();
Jason Monk794457a2016-02-18 13:22:14 -050069 }
70 mLastT = t;
71 }
72 for (int i = 0; i < mTargets.length; i++) {
Jason Monke80654b2016-02-24 14:53:57 -050073 mKeyframeSets[i].setValue(t, mTargets[i]);
Jason Monk794457a2016-02-18 13:22:14 -050074 }
75 }
76
77 public static class ListenerAdapter implements Listener {
78 @Override
79 public void onAnimationAtStart() { }
80
81 @Override
82 public void onAnimationAtEnd() { }
83
84 @Override
85 public void onAnimationStarted() { }
86 }
87
88 public interface Listener {
89 /**
90 * Called when the animator moves into a position of "0". Start and end delays are
91 * taken into account, so this position may cover a range of fractional inputs.
92 */
93 void onAnimationAtStart();
94
95 /**
96 * Called when the animator moves into a position of "0". Start and end delays are
97 * taken into account, so this position may cover a range of fractional inputs.
98 */
99 void onAnimationAtEnd();
100
101 /**
102 * Called when the animator moves out of the start or end position and is in a transient
103 * state.
104 */
105 void onAnimationStarted();
106 }
107
108 public static class Builder {
109 private List<Object> mTargets = new ArrayList<>();
Jason Monk794457a2016-02-18 13:22:14 -0500110 private List<KeyframeSet> mValues = new ArrayList<>();
111
112 private float mStartDelay;
113 private float mEndDelay;
114 private Interpolator mInterpolator;
115 private Listener mListener;
116
117 public Builder addFloat(Object target, String property, float... values) {
Jason Monkdf5459d2016-02-29 10:47:35 -0500118 add(target, KeyframeSet.ofFloat(getProperty(target, property, float.class), values));
Jason Monk794457a2016-02-18 13:22:14 -0500119 return this;
120 }
121
122 public Builder addInt(Object target, String property, int... values) {
Jason Monkdf5459d2016-02-29 10:47:35 -0500123 add(target, KeyframeSet.ofInt(getProperty(target, property, int.class), values));
Jason Monk794457a2016-02-18 13:22:14 -0500124 return this;
125 }
126
Jason Monke80654b2016-02-24 14:53:57 -0500127 private void add(Object target, KeyframeSet keyframeSet) {
Jason Monk794457a2016-02-18 13:22:14 -0500128 mTargets.add(target);
Jason Monk794457a2016-02-18 13:22:14 -0500129 mValues.add(keyframeSet);
130 }
131
Jason Monkdf5459d2016-02-29 10:47:35 -0500132 private static Property getProperty(Object target, String property, Class<?> cls) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500133 if (target instanceof View) {
134 switch (property) {
135 case "translationX":
136 return View.TRANSLATION_X;
137 case "translationY":
138 return View.TRANSLATION_Y;
139 case "translationZ":
140 return View.TRANSLATION_Z;
141 case "alpha":
142 return View.ALPHA;
143 case "rotation":
144 return View.ROTATION;
145 case "x":
146 return View.X;
147 case "y":
148 return View.Y;
149 case "scaleX":
150 return View.SCALE_X;
151 case "scaleY":
152 return View.SCALE_Y;
153 }
154 }
Jason Monkdf5459d2016-02-29 10:47:35 -0500155 return Property.of(target.getClass(), cls, property);
Jason Monk8d1253e2016-02-20 08:43:27 -0500156 }
157
Jason Monk794457a2016-02-18 13:22:14 -0500158 public Builder setStartDelay(float startDelay) {
159 mStartDelay = startDelay;
160 return this;
161 }
162
163 public Builder setEndDelay(float endDelay) {
164 mEndDelay = endDelay;
165 return this;
166 }
167
168 public Builder setInterpolator(Interpolator intepolator) {
169 mInterpolator = intepolator;
170 return this;
171 }
172
173 public Builder setListener(Listener listener) {
174 mListener = listener;
175 return this;
176 }
177
178 public TouchAnimator build() {
179 return new TouchAnimator(mTargets.toArray(new Object[mTargets.size()]),
Jason Monk794457a2016-02-18 13:22:14 -0500180 mValues.toArray(new KeyframeSet[mValues.size()]),
181 mStartDelay, mEndDelay, mInterpolator, mListener);
182 }
183 }
184
185 private static abstract class KeyframeSet {
186
Jason Monk8d1253e2016-02-20 08:43:27 -0500187 private final float mFrameWidth;
188 private final int mSize;
Jason Monk794457a2016-02-18 13:22:14 -0500189
Jason Monk8d1253e2016-02-20 08:43:27 -0500190 public KeyframeSet(int size) {
191 mSize = size;
192 mFrameWidth = 1 / (float) (size - 1);
Jason Monk794457a2016-02-18 13:22:14 -0500193 }
194
Jason Monke80654b2016-02-24 14:53:57 -0500195 void setValue(float fraction, Object target) {
Jason Monk794457a2016-02-18 13:22:14 -0500196 int i;
Jason Monk8d1253e2016-02-20 08:43:27 -0500197 for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
198 float amount = fraction / mFrameWidth;
Jason Monke80654b2016-02-24 14:53:57 -0500199 interpolate(i, amount, target);
Jason Monk794457a2016-02-18 13:22:14 -0500200 }
201
Jason Monke80654b2016-02-24 14:53:57 -0500202 protected abstract void interpolate(int index, float amount, Object target);
Jason Monk794457a2016-02-18 13:22:14 -0500203
Jason Monke80654b2016-02-24 14:53:57 -0500204 public static KeyframeSet ofInt(Property property, int... values) {
205 return new IntKeyframeSet((Property<?, Integer>) property, values);
Jason Monk794457a2016-02-18 13:22:14 -0500206 }
207
Jason Monke80654b2016-02-24 14:53:57 -0500208 public static KeyframeSet ofFloat(Property property, float... values) {
209 return new FloatKeyframeSet((Property<?, Float>) property, values);
Jason Monk794457a2016-02-18 13:22:14 -0500210 }
211 }
212
Jason Monke80654b2016-02-24 14:53:57 -0500213 private static class FloatKeyframeSet<T> extends KeyframeSet {
Jason Monk8d1253e2016-02-20 08:43:27 -0500214 private final float[] mValues;
Jason Monke80654b2016-02-24 14:53:57 -0500215 private final Property<T, Float> mProperty;
Jason Monk8d1253e2016-02-20 08:43:27 -0500216
Jason Monke80654b2016-02-24 14:53:57 -0500217 public FloatKeyframeSet(Property<T, Float> property, float[] values) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500218 super(values.length);
Jason Monke80654b2016-02-24 14:53:57 -0500219 mProperty = property;
Jason Monk8d1253e2016-02-20 08:43:27 -0500220 mValues = values;
Jason Monk794457a2016-02-18 13:22:14 -0500221 }
222
223 @Override
Jason Monke80654b2016-02-24 14:53:57 -0500224 protected void interpolate(int index, float amount, Object target) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500225 float firstFloat = mValues[index - 1];
226 float secondFloat = mValues[index];
Jason Monke80654b2016-02-24 14:53:57 -0500227 mProperty.set((T) target, firstFloat + (secondFloat - firstFloat) * amount);
Jason Monk794457a2016-02-18 13:22:14 -0500228 }
229 }
230
Jason Monke80654b2016-02-24 14:53:57 -0500231 private static class IntKeyframeSet<T> extends KeyframeSet {
Jason Monk8d1253e2016-02-20 08:43:27 -0500232 private final int[] mValues;
Jason Monke80654b2016-02-24 14:53:57 -0500233 private final Property<T, Integer> mProperty;
Jason Monk8d1253e2016-02-20 08:43:27 -0500234
Jason Monke80654b2016-02-24 14:53:57 -0500235 public IntKeyframeSet(Property<T, Integer> property, int[] values) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500236 super(values.length);
Jason Monke80654b2016-02-24 14:53:57 -0500237 mProperty = property;
Jason Monk8d1253e2016-02-20 08:43:27 -0500238 mValues = values;
Jason Monk794457a2016-02-18 13:22:14 -0500239 }
240
241 @Override
Jason Monke80654b2016-02-24 14:53:57 -0500242 protected void interpolate(int index, float amount, Object target) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500243 int firstFloat = mValues[index - 1];
244 int secondFloat = mValues[index];
Jason Monke80654b2016-02-24 14:53:57 -0500245 mProperty.set((T) target, (int) (firstFloat + (secondFloat - firstFloat) * amount));
Jason Monk794457a2016-02-18 13:22:14 -0500246 }
247 }
248}