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.KeyCycleOscillator;
20 import androidx.constraintlayout.core.motion.utils.Oscillator;
21 import androidx.constraintlayout.core.motion.utils.SplineSet;
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 MotionKeyCycle extends MotionKey {
29     private static final String TAG = "KeyCycle";
30     static final String NAME = "KeyCycle";
31     public static final String WAVE_PERIOD = "wavePeriod";
32     public static final String WAVE_OFFSET = "waveOffset";
33     public static final String WAVE_PHASE = "wavePhase";
34     public static final String WAVE_SHAPE = "waveShape";
35     public static final int SHAPE_SIN_WAVE = Oscillator.SIN_WAVE;
36     public static final int SHAPE_SQUARE_WAVE = Oscillator.SQUARE_WAVE;
37     public static final int SHAPE_TRIANGLE_WAVE = Oscillator.TRIANGLE_WAVE;
38     public static final int SHAPE_SAW_WAVE = Oscillator.SAW_WAVE;
39     public static final int SHAPE_REVERSE_SAW_WAVE = Oscillator.REVERSE_SAW_WAVE;
40     public static final int SHAPE_COS_WAVE = Oscillator.COS_WAVE;
41     public static final int SHAPE_BOUNCE = Oscillator.BOUNCE;
42 
43     @SuppressWarnings("unused") private String mTransitionEasing = null;
44     @SuppressWarnings("unused") private int mCurveFit = 0;
45     private int mWaveShape = -1;
46     private String mCustomWaveShape = null;
47     private float mWavePeriod = Float.NaN;
48     private float mWaveOffset = 0;
49     private float mWavePhase = 0;
50     private float mProgress = Float.NaN;
51     private float mAlpha = Float.NaN;
52     private float mElevation = Float.NaN;
53     private float mRotation = Float.NaN;
54     private float mTransitionPathRotate = Float.NaN;
55     private float mRotationX = Float.NaN;
56     private float mRotationY = Float.NaN;
57     private float mScaleX = Float.NaN;
58     private float mScaleY = Float.NaN;
59     private float mTranslationX = Float.NaN;
60     private float mTranslationY = Float.NaN;
61     private float mTranslationZ = Float.NaN;
62     public static final int KEY_TYPE = 4;
63 
64     {
65         mType = KEY_TYPE;
66         mCustom = new HashMap<>();
67     }
68 
69     @Override
getAttributeNames(HashSet<String> attributes)70     public void getAttributeNames(HashSet<String> attributes) {
71         if (!Float.isNaN(mAlpha)) {
72             attributes.add(CycleType.S_ALPHA);
73         }
74         if (!Float.isNaN(mElevation)) {
75             attributes.add(CycleType.S_ELEVATION);
76         }
77         if (!Float.isNaN(mRotation)) {
78             attributes.add(CycleType.S_ROTATION_Z);
79         }
80         if (!Float.isNaN(mRotationX)) {
81             attributes.add(CycleType.S_ROTATION_X);
82         }
83         if (!Float.isNaN(mRotationY)) {
84             attributes.add(CycleType.S_ROTATION_Y);
85         }
86         if (!Float.isNaN(mScaleX)) {
87             attributes.add(CycleType.S_SCALE_X);
88         }
89         if (!Float.isNaN(mScaleY)) {
90             attributes.add(CycleType.S_SCALE_Y);
91         }
92         if (!Float.isNaN(mTransitionPathRotate)) {
93             attributes.add(CycleType.S_PATH_ROTATE);
94         }
95         if (!Float.isNaN(mTranslationX)) {
96             attributes.add(CycleType.S_TRANSLATION_X);
97         }
98         if (!Float.isNaN(mTranslationY)) {
99             attributes.add(CycleType.S_TRANSLATION_Y);
100         }
101         if (!Float.isNaN(mTranslationZ)) {
102             attributes.add(CycleType.S_TRANSLATION_Z);
103         }
104         if (mCustom.size() > 0) {
105             for (String s : mCustom.keySet()) {
106                 attributes.add(TypedValues.S_CUSTOM + "," + s);
107             }
108         }
109     }
110 
111     @Override
addValues(HashMap<String, SplineSet> splines)112     public void addValues(HashMap<String, SplineSet> splines) {
113 
114     }
115 
116     // @TODO: add description
117     @Override
setValue(int type, int value)118     public boolean setValue(int type, int value) {
119         switch (type) {
120             case CycleType.TYPE_CURVE_FIT:
121                 mCurveFit = value;
122                 return true;
123             case CycleType.TYPE_WAVE_SHAPE:
124                 mWaveShape = value;
125                 return true;
126             default:
127                 boolean ret = setValue(type, (float) value);
128                 if (ret) {
129                     return true;
130                 }
131                 return super.setValue(type, value);
132         }
133     }
134 
135     // @TODO: add description
136     @Override
setValue(int type, String value)137     public boolean setValue(int type, String value) {
138         switch (type) {
139             case CycleType.TYPE_EASING:
140                 mTransitionEasing = value;
141                 return true;
142             case CycleType.TYPE_CUSTOM_WAVE_SHAPE:
143                 mCustomWaveShape = value;
144                 return true;
145             default:
146                 return super.setValue(type, value);
147         }
148 
149     }
150 
151     // @TODO: add description
152     @Override
setValue(int type, float value)153     public boolean setValue(int type, float value) {
154         switch (type) {
155             case CycleType.TYPE_ALPHA:
156                 mAlpha = value;
157                 break;
158             case CycleType.TYPE_TRANSLATION_X:
159                 mTranslationX = value;
160                 break;
161             case CycleType.TYPE_TRANSLATION_Y:
162                 mTranslationY = value;
163                 break;
164             case CycleType.TYPE_TRANSLATION_Z:
165                 mTranslationZ = value;
166                 break;
167             case CycleType.TYPE_ELEVATION:
168                 mElevation = value;
169                 break;
170             case CycleType.TYPE_ROTATION_X:
171                 mRotationX = value;
172                 break;
173             case CycleType.TYPE_ROTATION_Y:
174                 mRotationY = value;
175                 break;
176             case CycleType.TYPE_ROTATION_Z:
177                 mRotation = value;
178                 break;
179             case CycleType.TYPE_SCALE_X:
180                 mScaleX = value;
181                 break;
182             case CycleType.TYPE_SCALE_Y:
183                 mScaleY = value;
184                 break;
185             case CycleType.TYPE_PROGRESS:
186                 mProgress = value;
187                 break;
188             case CycleType.TYPE_PATH_ROTATE:
189                 mTransitionPathRotate = value;
190                 break;
191             case CycleType.TYPE_WAVE_PERIOD:
192                 mWavePeriod = value;
193                 break;
194             case CycleType.TYPE_WAVE_OFFSET:
195                 mWaveOffset = value;
196                 break;
197             case CycleType.TYPE_WAVE_PHASE:
198                 mWavePhase = value;
199                 break;
200             default:
201                 return super.setValue(type, value);
202         }
203         return true;
204     }
205 
206     // @TODO: add description
getValue(String key)207     public float getValue(String key) {
208         switch (key) {
209             case CycleType.S_ALPHA:
210                 return mAlpha;
211             case CycleType.S_ELEVATION:
212                 return mElevation;
213             case CycleType.S_ROTATION_Z:
214                 return mRotation;
215             case CycleType.S_ROTATION_X:
216                 return mRotationX;
217             case CycleType.S_ROTATION_Y:
218                 return mRotationY;
219             case CycleType.S_PATH_ROTATE:
220                 return mTransitionPathRotate;
221             case CycleType.S_SCALE_X:
222                 return mScaleX;
223             case CycleType.S_SCALE_Y:
224                 return mScaleY;
225             case CycleType.S_TRANSLATION_X:
226                 return mTranslationX;
227             case CycleType.S_TRANSLATION_Y:
228                 return mTranslationY;
229             case CycleType.S_TRANSLATION_Z:
230                 return mTranslationZ;
231             case CycleType.S_WAVE_OFFSET:
232                 return mWaveOffset;
233             case CycleType.S_WAVE_PHASE:
234                 return mWavePhase;
235             case CycleType.S_PROGRESS:
236                 return mProgress;
237             default:
238                 return Float.NaN;
239         }
240     }
241 
242     @Override
clone()243     public MotionKey clone() {
244         return null;
245     }
246 
247     @Override
getId(String name)248     public int getId(String name) {
249         switch (name) {
250             case CycleType.S_CURVE_FIT:
251                 return CycleType.TYPE_CURVE_FIT;
252             case CycleType.S_VISIBILITY:
253                 return CycleType.TYPE_VISIBILITY;
254             case CycleType.S_ALPHA:
255                 return CycleType.TYPE_ALPHA;
256             case CycleType.S_TRANSLATION_X:
257                 return CycleType.TYPE_TRANSLATION_X;
258             case CycleType.S_TRANSLATION_Y:
259                 return CycleType.TYPE_TRANSLATION_Y;
260             case CycleType.S_TRANSLATION_Z:
261                 return CycleType.TYPE_TRANSLATION_Z;
262             case CycleType.S_ROTATION_X:
263                 return CycleType.TYPE_ROTATION_X;
264             case CycleType.S_ROTATION_Y:
265                 return CycleType.TYPE_ROTATION_Y;
266             case CycleType.S_ROTATION_Z:
267                 return CycleType.TYPE_ROTATION_Z;
268             case CycleType.S_SCALE_X:
269                 return CycleType.TYPE_SCALE_X;
270             case CycleType.S_SCALE_Y:
271                 return CycleType.TYPE_SCALE_Y;
272             case CycleType.S_PIVOT_X:
273                 return CycleType.TYPE_PIVOT_X;
274             case CycleType.S_PIVOT_Y:
275                 return CycleType.TYPE_PIVOT_Y;
276             case CycleType.S_PROGRESS:
277                 return CycleType.TYPE_PROGRESS;
278             case CycleType.S_PATH_ROTATE:
279                 return CycleType.TYPE_PATH_ROTATE;
280             case CycleType.S_EASING:
281                 return CycleType.TYPE_EASING;
282             case CycleType.S_WAVE_PERIOD:
283                 return CycleType.TYPE_WAVE_PERIOD;
284             case CycleType.S_WAVE_SHAPE:
285                 return CycleType.TYPE_WAVE_SHAPE;
286             case CycleType.S_WAVE_PHASE:
287                 return CycleType.TYPE_WAVE_PHASE;
288             case CycleType.S_WAVE_OFFSET:
289                 return CycleType.TYPE_WAVE_OFFSET;
290             case CycleType.S_CUSTOM_WAVE_SHAPE:
291                 return CycleType.TYPE_CUSTOM_WAVE_SHAPE;
292 
293         }
294         return -1;
295     }
296 
297     // @TODO: add description
addCycleValues(HashMap<String, KeyCycleOscillator> oscSet)298     public void addCycleValues(HashMap<String, KeyCycleOscillator> oscSet) {
299 
300         for (String key : oscSet.keySet()) {
301             if (key.startsWith(TypedValues.S_CUSTOM)) {
302                 String customKey = key.substring(TypedValues.S_CUSTOM.length() + 1);
303                 CustomVariable cValue = mCustom.get(customKey);
304                 if (cValue == null || cValue.getType() != Custom.TYPE_FLOAT) {
305                     continue;
306                 }
307 
308                 KeyCycleOscillator osc = oscSet.get(key);
309                 if (osc == null) {
310                     continue;
311                 }
312 
313                 osc.setPoint(mFramePosition, mWaveShape, mCustomWaveShape, -1, mWavePeriod,
314                         mWaveOffset, mWavePhase / 360, cValue.getValueToInterpolate(), cValue);
315                 continue;
316             }
317             float value = getValue(key);
318             if (Float.isNaN(value)) {
319                 continue;
320             }
321 
322             KeyCycleOscillator osc = oscSet.get(key);
323             if (osc == null) {
324                 continue;
325             }
326 
327             osc.setPoint(mFramePosition, mWaveShape, mCustomWaveShape,
328                     -1, mWavePeriod, mWaveOffset, mWavePhase / 360, value);
329         }
330     }
331 
332 
333     // @TODO: add description
dump()334     public void dump() {
335         System.out.println("MotionKeyCycle{"
336                 + "mWaveShape=" + mWaveShape
337                 + ", mWavePeriod=" + mWavePeriod
338                 + ", mWaveOffset=" + mWaveOffset
339                 + ", mWavePhase=" + mWavePhase
340                 + ", mRotation=" + mRotation
341                 + '}');
342     }
343 
344     // @TODO: add description
printAttributes()345     public void printAttributes() {
346         HashSet<String> nameSet = new HashSet<>();
347         getAttributeNames(nameSet);
348 
349         Utils.log(" ------------- " + mFramePosition + " -------------");
350         Utils.log("MotionKeyCycle{"
351                 + "Shape=" + mWaveShape
352                 + ", Period=" + mWavePeriod
353                 + ", Offset=" + mWaveOffset
354                 + ", Phase=" + mWavePhase
355                 + '}');
356         String[] names = nameSet.toArray(new String[0]);
357         for (int i = 0; i < names.length; i++) {
358             Utils.log(names[i] + ":" + getValue(names[i]));
359         }
360     }
361 
362 
363 }
364