blob: 026dd0e74a0a0b52c7439562df480cc0baf6cbd2 [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;
41 private float mLastT;
42
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 }
59 if (mListener != null) {
60 if (mLastT == 0 || mLastT == 1) {
Jason Monk66eaf312016-02-25 12:29:29 -050061 if (t != mLastT) {
Jason Monk794457a2016-02-18 13:22:14 -050062 mListener.onAnimationStarted();
63 }
64 } else if (t == 1) {
65 mListener.onAnimationAtEnd();
66 } else if (t == 0) {
67 mListener.onAnimationAtStart();
68 }
69 mLastT = t;
70 }
71 for (int i = 0; i < mTargets.length; i++) {
Jason Monke80654b2016-02-24 14:53:57 -050072 mKeyframeSets[i].setValue(t, mTargets[i]);
Jason Monk794457a2016-02-18 13:22:14 -050073 }
74 }
75
76 public static class ListenerAdapter implements Listener {
77 @Override
78 public void onAnimationAtStart() { }
79
80 @Override
81 public void onAnimationAtEnd() { }
82
83 @Override
84 public void onAnimationStarted() { }
85 }
86
87 public interface Listener {
88 /**
89 * Called when the animator moves into a position of "0". Start and end delays are
90 * taken into account, so this position may cover a range of fractional inputs.
91 */
92 void onAnimationAtStart();
93
94 /**
95 * Called when the animator moves into a position of "0". Start and end delays are
96 * taken into account, so this position may cover a range of fractional inputs.
97 */
98 void onAnimationAtEnd();
99
100 /**
101 * Called when the animator moves out of the start or end position and is in a transient
102 * state.
103 */
104 void onAnimationStarted();
105 }
106
107 public static class Builder {
108 private List<Object> mTargets = new ArrayList<>();
Jason Monk794457a2016-02-18 13:22:14 -0500109 private List<KeyframeSet> mValues = new ArrayList<>();
110
111 private float mStartDelay;
112 private float mEndDelay;
113 private Interpolator mInterpolator;
114 private Listener mListener;
115
116 public Builder addFloat(Object target, String property, float... values) {
Jason Monke80654b2016-02-24 14:53:57 -0500117 add(target, KeyframeSet.ofFloat(getProperty(target, property), values));
Jason Monk794457a2016-02-18 13:22:14 -0500118 return this;
119 }
120
121 public Builder addInt(Object target, String property, int... values) {
Jason Monke80654b2016-02-24 14:53:57 -0500122 add(target, KeyframeSet.ofInt(getProperty(target, property), values));
Jason Monk794457a2016-02-18 13:22:14 -0500123 return this;
124 }
125
Jason Monke80654b2016-02-24 14:53:57 -0500126 private void add(Object target, KeyframeSet keyframeSet) {
Jason Monk794457a2016-02-18 13:22:14 -0500127 mTargets.add(target);
Jason Monk794457a2016-02-18 13:22:14 -0500128 mValues.add(keyframeSet);
129 }
130
Jason Monk8d1253e2016-02-20 08:43:27 -0500131 private static Property getProperty(Object target, String property) {
132 if (target instanceof View) {
133 switch (property) {
134 case "translationX":
135 return View.TRANSLATION_X;
136 case "translationY":
137 return View.TRANSLATION_Y;
138 case "translationZ":
139 return View.TRANSLATION_Z;
140 case "alpha":
141 return View.ALPHA;
142 case "rotation":
143 return View.ROTATION;
144 case "x":
145 return View.X;
146 case "y":
147 return View.Y;
148 case "scaleX":
149 return View.SCALE_X;
150 case "scaleY":
151 return View.SCALE_Y;
152 }
153 }
154 return Property.of(target.getClass(), float.class, property);
155 }
156
Jason Monk794457a2016-02-18 13:22:14 -0500157 public Builder setStartDelay(float startDelay) {
158 mStartDelay = startDelay;
159 return this;
160 }
161
162 public Builder setEndDelay(float endDelay) {
163 mEndDelay = endDelay;
164 return this;
165 }
166
167 public Builder setInterpolator(Interpolator intepolator) {
168 mInterpolator = intepolator;
169 return this;
170 }
171
172 public Builder setListener(Listener listener) {
173 mListener = listener;
174 return this;
175 }
176
177 public TouchAnimator build() {
178 return new TouchAnimator(mTargets.toArray(new Object[mTargets.size()]),
Jason Monk794457a2016-02-18 13:22:14 -0500179 mValues.toArray(new KeyframeSet[mValues.size()]),
180 mStartDelay, mEndDelay, mInterpolator, mListener);
181 }
182 }
183
184 private static abstract class KeyframeSet {
185
Jason Monk8d1253e2016-02-20 08:43:27 -0500186 private final float mFrameWidth;
187 private final int mSize;
Jason Monk794457a2016-02-18 13:22:14 -0500188
Jason Monk8d1253e2016-02-20 08:43:27 -0500189 public KeyframeSet(int size) {
190 mSize = size;
191 mFrameWidth = 1 / (float) (size - 1);
Jason Monk794457a2016-02-18 13:22:14 -0500192 }
193
Jason Monke80654b2016-02-24 14:53:57 -0500194 void setValue(float fraction, Object target) {
Jason Monk794457a2016-02-18 13:22:14 -0500195 int i;
Jason Monk8d1253e2016-02-20 08:43:27 -0500196 for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++);
197 float amount = fraction / mFrameWidth;
Jason Monke80654b2016-02-24 14:53:57 -0500198 interpolate(i, amount, target);
Jason Monk794457a2016-02-18 13:22:14 -0500199 }
200
Jason Monke80654b2016-02-24 14:53:57 -0500201 protected abstract void interpolate(int index, float amount, Object target);
Jason Monk794457a2016-02-18 13:22:14 -0500202
Jason Monke80654b2016-02-24 14:53:57 -0500203 public static KeyframeSet ofInt(Property property, int... values) {
204 return new IntKeyframeSet((Property<?, Integer>) property, values);
Jason Monk794457a2016-02-18 13:22:14 -0500205 }
206
Jason Monke80654b2016-02-24 14:53:57 -0500207 public static KeyframeSet ofFloat(Property property, float... values) {
208 return new FloatKeyframeSet((Property<?, Float>) property, values);
Jason Monk794457a2016-02-18 13:22:14 -0500209 }
210 }
211
Jason Monke80654b2016-02-24 14:53:57 -0500212 private static class FloatKeyframeSet<T> extends KeyframeSet {
Jason Monk8d1253e2016-02-20 08:43:27 -0500213 private final float[] mValues;
Jason Monke80654b2016-02-24 14:53:57 -0500214 private final Property<T, Float> mProperty;
Jason Monk8d1253e2016-02-20 08:43:27 -0500215
Jason Monke80654b2016-02-24 14:53:57 -0500216 public FloatKeyframeSet(Property<T, Float> property, float[] values) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500217 super(values.length);
Jason Monke80654b2016-02-24 14:53:57 -0500218 mProperty = property;
Jason Monk8d1253e2016-02-20 08:43:27 -0500219 mValues = values;
Jason Monk794457a2016-02-18 13:22:14 -0500220 }
221
222 @Override
Jason Monke80654b2016-02-24 14:53:57 -0500223 protected void interpolate(int index, float amount, Object target) {
Jason Monk8d1253e2016-02-20 08:43:27 -0500224 float firstFloat = mValues[index - 1];
225 float secondFloat = mValues[index];
Jason Monke80654b2016-02-24 14:53:57 -0500226 mProperty.set((T) target, firstFloat + (secondFloat - firstFloat) * amount);
Jason Monk794457a2016-02-18 13:22:14 -0500227 }
228 }
229
Jason Monke80654b2016-02-24 14:53:57 -0500230 private static class IntKeyframeSet<T> extends KeyframeSet {
Jason Monk8d1253e2016-02-20 08:43:27 -0500231 private final int[] mValues;
Jason Monke80654b2016-02-24 14:53:57 -0500232 private final Property<T, Integer> mProperty;
Jason Monk8d1253e2016-02-20 08:43:27 -0500233
Jason Monke80654b2016-02-24 14:53:57 -0500234 public IntKeyframeSet(Property<T, Integer> property, int[] 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 int firstFloat = mValues[index - 1];
243 int secondFloat = mValues[index];
Jason Monke80654b2016-02-24 14:53:57 -0500244 mProperty.set((T) target, (int) (firstFloat + (secondFloat - firstFloat) * amount));
Jason Monk794457a2016-02-18 13:22:14 -0500245 }
246 }
247}