1 /*
2  * Copyright (C) 2021 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 androidx.constraintlayout.core.motion.key;
17 
18 import androidx.constraintlayout.core.motion.CustomVariable;
19 import androidx.constraintlayout.core.motion.utils.Oscillator;
20 import androidx.constraintlayout.core.motion.utils.SplineSet;
21 import androidx.constraintlayout.core.motion.utils.TimeCycleSplineSet;
22 import androidx.constraintlayout.core.motion.utils.TypedValues;
23 import androidx.constraintlayout.core.motion.utils.Utils;
24 
25 import java.util.HashMap;
26 import java.util.HashSet;
27 
28 public class MotionKeyTimeCycle extends MotionKey {
29     static final String NAME = "KeyTimeCycle";
30     private static final String TAG = NAME;
31 
32     private String mTransitionEasing;
33     private int mCurveFit = -1;
34     private float mAlpha = Float.NaN;
35     private float mElevation = Float.NaN;
36     private float mRotation = Float.NaN;
37     private float mRotationX = Float.NaN;
38     private float mRotationY = Float.NaN;
39     private float mTransitionPathRotate = Float.NaN;
40     private float mScaleX = Float.NaN;
41     private float mScaleY = Float.NaN;
42     private float mTranslationX = Float.NaN;
43     private float mTranslationY = Float.NaN;
44     private float mTranslationZ = Float.NaN;
45     private float mProgress = Float.NaN;
46     private int mWaveShape = 0;
47 
48     // TODO add support of custom wave shapes in KeyTimeCycle
49     @SuppressWarnings("unused") private String mCustomWaveShape = null;
50     private float mWavePeriod = Float.NaN;
51     private float mWaveOffset = 0;
52     public static final int KEY_TYPE = 3;
53 
54     {
55         mType = KEY_TYPE;
56         mCustom = new HashMap<>();
57     }
58 
59     // @TODO: add description
addTimeValues(HashMap<String, TimeCycleSplineSet> splines)60     public void addTimeValues(HashMap<String, TimeCycleSplineSet> splines) {
61         for (String s : splines.keySet()) {
62             TimeCycleSplineSet splineSet = splines.get(s);
63             if (splineSet == null) {
64                 continue;
65             }
66             if (s.startsWith(CUSTOM)) {
67                 String cKey = s.substring(CUSTOM.length() + 1);
68                 CustomVariable cValue = mCustom.get(cKey);
69                 if (cValue != null) {
70                     ((TimeCycleSplineSet.CustomVarSet) splineSet)
71                             .setPoint(mFramePosition, cValue, mWavePeriod, mWaveShape, mWaveOffset);
72                 }
73                 continue;
74             }
75             switch (s) {
76                 case AttributesType.S_ALPHA:
77                     if (!Float.isNaN(mAlpha)) {
78                         splineSet.setPoint(mFramePosition,
79                                 mAlpha, mWavePeriod, mWaveShape, mWaveOffset);
80                     }
81                     break;
82 
83                 case AttributesType.S_ROTATION_X:
84                     if (!Float.isNaN(mRotationX)) {
85                         splineSet.setPoint(mFramePosition,
86                                 mRotationX, mWavePeriod, mWaveShape, mWaveOffset);
87                     }
88                     break;
89                 case AttributesType.S_ROTATION_Y:
90                     if (!Float.isNaN(mRotationY)) {
91                         splineSet.setPoint(mFramePosition,
92                                 mRotationY, mWavePeriod, mWaveShape, mWaveOffset);
93                     }
94                     break;
95                 case AttributesType.S_ROTATION_Z:
96                     if (!Float.isNaN(mRotation)) {
97                         splineSet.setPoint(mFramePosition,
98                                 mRotation, mWavePeriod, mWaveShape, mWaveOffset);
99                     }
100                     break;
101                 case AttributesType.S_PATH_ROTATE:
102                     if (!Float.isNaN(mTransitionPathRotate)) {
103                         splineSet.setPoint(mFramePosition,
104                                 mTransitionPathRotate, mWavePeriod, mWaveShape, mWaveOffset);
105                     }
106                     break;
107 
108                 case AttributesType.S_SCALE_X:
109                     if (!Float.isNaN(mScaleX)) {
110                         splineSet.setPoint(mFramePosition,
111                                 mScaleX, mWavePeriod, mWaveShape, mWaveOffset);
112                     }
113                     break;
114                 case AttributesType.S_SCALE_Y:
115                     if (!Float.isNaN(mScaleY)) {
116                         splineSet.setPoint(mFramePosition,
117                                 mScaleY, mWavePeriod, mWaveShape, mWaveOffset);
118                     }
119                     break;
120                 case AttributesType.S_TRANSLATION_X:
121                     if (!Float.isNaN(mTranslationX)) {
122                         splineSet.setPoint(mFramePosition,
123                                 mTranslationX, mWavePeriod, mWaveShape, mWaveOffset);
124                     }
125                     break;
126                 case AttributesType.S_TRANSLATION_Y:
127                     if (!Float.isNaN(mTranslationY)) {
128                         splineSet.setPoint(mFramePosition,
129                                 mTranslationY, mWavePeriod, mWaveShape, mWaveOffset);
130                     }
131                     break;
132                 case AttributesType.S_TRANSLATION_Z:
133                     if (!Float.isNaN(mTranslationZ)) {
134                         splineSet.setPoint(mFramePosition,
135                                 mTranslationZ, mWavePeriod, mWaveShape, mWaveOffset);
136                     }
137                     break;
138                 case AttributesType.S_ELEVATION:
139                     if (!Float.isNaN(mTranslationZ)) {
140                         splineSet.setPoint(mFramePosition,
141                                 mTranslationZ, mWavePeriod, mWaveShape, mWaveOffset);
142                     }
143                     break;
144                 case AttributesType.S_PROGRESS:
145                     if (!Float.isNaN(mProgress)) {
146                         splineSet.setPoint(mFramePosition,
147                                 mProgress, mWavePeriod, mWaveShape, mWaveOffset);
148                     }
149                     break;
150                 default:
151                     Utils.loge("KeyTimeCycles", "UNKNOWN addValues \"" + s + "\"");
152             }
153         }
154     }
155 
156     @Override
addValues(HashMap<String, SplineSet> splines)157     public void addValues(HashMap<String, SplineSet> splines) {
158     }
159 
160     // @TODO: add description
161     @Override
setValue(int type, int value)162     public boolean setValue(int type, int value) {
163 
164         switch (type) {
165             case TypedValues.TYPE_FRAME_POSITION:
166                 mFramePosition = value;
167                 break;
168             case CycleType.TYPE_WAVE_SHAPE:
169                 mWaveShape = value;
170                 break;
171             default:
172                 return super.setValue(type, value);
173         }
174         return true;
175     }
176 
177     // @TODO: add description
178     @Override
setValue(int type, float value)179     public boolean setValue(int type, float value) {
180         switch (type) {
181             case CycleType.TYPE_ALPHA:
182                 mAlpha = value;
183                 break;
184             case CycleType.TYPE_CURVE_FIT:
185                 mCurveFit = toInt(value);
186                 break;
187             case CycleType.TYPE_ELEVATION:
188                 mElevation = toFloat(value);
189                 break;
190             case CycleType.TYPE_PROGRESS:
191                 mProgress = toFloat(value);
192                 break;
193             case CycleType.TYPE_ROTATION_Z:
194                 mRotation = toFloat(value);
195                 break;
196             case CycleType.TYPE_ROTATION_X:
197                 mRotationX = toFloat(value);
198                 break;
199             case CycleType.TYPE_ROTATION_Y:
200                 mRotationY = toFloat(value);
201                 break;
202             case CycleType.TYPE_SCALE_X:
203                 mScaleX = toFloat(value);
204                 break;
205             case CycleType.TYPE_SCALE_Y:
206                 mScaleY = toFloat(value);
207                 break;
208             case CycleType.TYPE_PATH_ROTATE:
209                 mTransitionPathRotate = toFloat(value);
210                 break;
211             case CycleType.TYPE_TRANSLATION_X:
212                 mTranslationX = toFloat(value);
213                 break;
214             case CycleType.TYPE_TRANSLATION_Y:
215                 mTranslationY = toFloat(value);
216                 break;
217             case CycleType.TYPE_TRANSLATION_Z:
218                 mTranslationZ = toFloat(value);
219                 break;
220             case CycleType.TYPE_WAVE_PERIOD:
221                 mWavePeriod = toFloat(value);
222                 break;
223             case CycleType.TYPE_WAVE_OFFSET:
224                 mWaveOffset = toFloat(value);
225                 break;
226             default:
227                 return super.setValue(type, value);
228         }
229         return true;
230     }
231 
232     // @TODO: add description
233     @Override
setValue(int type, String value)234     public boolean setValue(int type, String value) {
235         switch (type) {
236             case CycleType.TYPE_WAVE_SHAPE:
237                 mWaveShape = Oscillator.CUSTOM;
238                 mCustomWaveShape = value;
239                 break;
240             case CycleType.TYPE_EASING:
241                 mTransitionEasing = value;
242                 break;
243             default:
244                 return super.setValue(type, value);
245         }
246         return true;
247     }
248 
249     // @TODO: add description
250     @Override
setValue(int type, boolean value)251     public boolean setValue(int type, boolean value) {
252         return super.setValue(type, value);
253     }
254 
255     // @TODO: add description
256     @Override
copy(MotionKey src)257     public MotionKeyTimeCycle copy(MotionKey src) {
258         super.copy(src);
259         MotionKeyTimeCycle k = (MotionKeyTimeCycle) src;
260         mTransitionEasing = k.mTransitionEasing;
261         mCurveFit = k.mCurveFit;
262         mWaveShape = k.mWaveShape;
263         mWavePeriod = k.mWavePeriod;
264         mWaveOffset = k.mWaveOffset;
265         mProgress = k.mProgress;
266         mAlpha = k.mAlpha;
267         mElevation = k.mElevation;
268         mRotation = k.mRotation;
269         mTransitionPathRotate = k.mTransitionPathRotate;
270         mRotationX = k.mRotationX;
271         mRotationY = k.mRotationY;
272         mScaleX = k.mScaleX;
273         mScaleY = k.mScaleY;
274         mTranslationX = k.mTranslationX;
275         mTranslationY = k.mTranslationY;
276         mTranslationZ = k.mTranslationZ;
277         return this;
278     }
279 
280     @Override
getAttributeNames(HashSet<String> attributes)281     public void getAttributeNames(HashSet<String> attributes) {
282         if (!Float.isNaN(mAlpha)) {
283             attributes.add(CycleType.S_ALPHA);
284         }
285         if (!Float.isNaN(mElevation)) {
286             attributes.add(CycleType.S_ELEVATION);
287         }
288         if (!Float.isNaN(mRotation)) {
289             attributes.add(CycleType.S_ROTATION_Z);
290         }
291         if (!Float.isNaN(mRotationX)) {
292             attributes.add(CycleType.S_ROTATION_X);
293         }
294         if (!Float.isNaN(mRotationY)) {
295             attributes.add(CycleType.S_ROTATION_Y);
296         }
297         if (!Float.isNaN(mScaleX)) {
298             attributes.add(CycleType.S_SCALE_X);
299         }
300         if (!Float.isNaN(mScaleY)) {
301             attributes.add(CycleType.S_SCALE_Y);
302         }
303         if (!Float.isNaN(mTransitionPathRotate)) {
304             attributes.add(CycleType.S_PATH_ROTATE);
305         }
306         if (!Float.isNaN(mTranslationX)) {
307             attributes.add(CycleType.S_TRANSLATION_X);
308         }
309         if (!Float.isNaN(mTranslationY)) {
310             attributes.add(CycleType.S_TRANSLATION_Y);
311         }
312         if (!Float.isNaN(mTranslationZ)) {
313             attributes.add(CycleType.S_TRANSLATION_Z);
314         }
315         if (mCustom.size() > 0) {
316             for (String s : mCustom.keySet()) {
317                 attributes.add(TypedValues.S_CUSTOM + "," + s);
318             }
319         }
320     }
321 
322     // @TODO: add description
323     @Override
clone()324     public MotionKey clone() {
325         return new MotionKeyTimeCycle().copy(this);
326     }
327 
328     @Override
getId(String name)329     public int getId(String name) {
330         return CycleType.getId(name);
331     }
332 }
333