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.SplineSet;
20 import androidx.constraintlayout.core.motion.utils.TypedValues;
21 
22 import java.util.HashMap;
23 import java.util.HashSet;
24 
25 public class MotionKeyAttributes extends MotionKey {
26     static final String NAME = "KeyAttribute";
27     private static final String TAG = "KeyAttributes";
28     @SuppressWarnings("unused") private static final boolean DEBUG = false;
29     @SuppressWarnings("unused") private String mTransitionEasing;
30     private int mCurveFit = -1;
31     @SuppressWarnings("unused") private int mVisibility = 0;
32     private float mAlpha = Float.NaN;
33     private float mElevation = Float.NaN;
34     private float mRotation = Float.NaN;
35     private float mRotationX = Float.NaN;
36     private float mRotationY = Float.NaN;
37     private float mPivotX = Float.NaN;
38     private float mPivotY = 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 
47     public static final int KEY_TYPE = 1;
48 
49     {
50         mType = KEY_TYPE;
51         mCustom = new HashMap<>();
52     }
53 
54     @Override
getAttributeNames(HashSet<String> attributes)55     public void getAttributeNames(HashSet<String> attributes) {
56 
57         if (!Float.isNaN(mAlpha)) {
58             attributes.add(AttributesType.S_ALPHA);
59         }
60         if (!Float.isNaN(mElevation)) {
61             attributes.add(AttributesType.S_ELEVATION);
62         }
63         if (!Float.isNaN(mRotation)) {
64             attributes.add(AttributesType.S_ROTATION_Z);
65         }
66         if (!Float.isNaN(mRotationX)) {
67             attributes.add(AttributesType.S_ROTATION_X);
68         }
69         if (!Float.isNaN(mRotationY)) {
70             attributes.add(AttributesType.S_ROTATION_Y);
71         }
72         if (!Float.isNaN(mPivotX)) {
73             attributes.add(AttributesType.S_PIVOT_X);
74         }
75         if (!Float.isNaN(mPivotY)) {
76             attributes.add(AttributesType.S_PIVOT_Y);
77         }
78         if (!Float.isNaN(mTranslationX)) {
79             attributes.add(AttributesType.S_TRANSLATION_X);
80         }
81         if (!Float.isNaN(mTranslationY)) {
82             attributes.add(AttributesType.S_TRANSLATION_Y);
83         }
84         if (!Float.isNaN(mTranslationZ)) {
85             attributes.add(AttributesType.S_TRANSLATION_Z);
86         }
87         if (!Float.isNaN(mTransitionPathRotate)) {
88             attributes.add(AttributesType.S_PATH_ROTATE);
89         }
90         if (!Float.isNaN(mScaleX)) {
91             attributes.add(AttributesType.S_SCALE_X);
92         }
93         if (!Float.isNaN(mScaleY)) {
94             attributes.add(AttributesType.S_SCALE_Y);
95         }
96         if (!Float.isNaN(mProgress)) {
97             attributes.add(AttributesType.S_PROGRESS);
98         }
99         if (mCustom.size() > 0) {
100             for (String s : mCustom.keySet()) {
101                 attributes.add(TypedValues.S_CUSTOM + "," + s);
102             }
103         }
104     }
105 
106     @Override
addValues(HashMap<String, SplineSet> splines)107     public void addValues(HashMap<String, SplineSet> splines) {
108         for (String s : splines.keySet()) {
109             SplineSet splineSet = splines.get(s);
110             if (splineSet == null) {
111                 continue;
112             }
113             // TODO support custom
114             if (s.startsWith(AttributesType.S_CUSTOM)) {
115                 String cKey = s.substring(AttributesType.S_CUSTOM.length() + 1);
116                 CustomVariable cValue = mCustom.get(cKey);
117                 if (cValue != null) {
118                     ((SplineSet.CustomSpline) splineSet).setPoint(mFramePosition, cValue);
119                 }
120                 continue;
121             }
122             switch (s) {
123                 case AttributesType.S_ALPHA:
124                     if (!Float.isNaN(mAlpha)) {
125                         splineSet.setPoint(mFramePosition, mAlpha);
126                     }
127                     break;
128                 case AttributesType.S_ELEVATION:
129                     if (!Float.isNaN(mElevation)) {
130                         splineSet.setPoint(mFramePosition, mElevation);
131                     }
132                     break;
133                 case AttributesType.S_ROTATION_Z:
134                     if (!Float.isNaN(mRotation)) {
135                         splineSet.setPoint(mFramePosition, mRotation);
136                     }
137                     break;
138                 case AttributesType.S_ROTATION_X:
139                     if (!Float.isNaN(mRotationX)) {
140                         splineSet.setPoint(mFramePosition, mRotationX);
141                     }
142                     break;
143                 case AttributesType.S_ROTATION_Y:
144                     if (!Float.isNaN(mRotationY)) {
145                         splineSet.setPoint(mFramePosition, mRotationY);
146                     }
147                     break;
148                 case AttributesType.S_PIVOT_X:
149                     if (!Float.isNaN(mRotationX)) {
150                         splineSet.setPoint(mFramePosition, mPivotX);
151                     }
152                     break;
153                 case AttributesType.S_PIVOT_Y:
154                     if (!Float.isNaN(mRotationY)) {
155                         splineSet.setPoint(mFramePosition, mPivotY);
156                     }
157                     break;
158                 case AttributesType.S_PATH_ROTATE:
159                     if (!Float.isNaN(mTransitionPathRotate)) {
160                         splineSet.setPoint(mFramePosition, mTransitionPathRotate);
161                     }
162                     break;
163                 case AttributesType.S_SCALE_X:
164                     if (!Float.isNaN(mScaleX)) {
165                         splineSet.setPoint(mFramePosition, mScaleX);
166                     }
167                     break;
168                 case AttributesType.S_SCALE_Y:
169                     if (!Float.isNaN(mScaleY)) {
170                         splineSet.setPoint(mFramePosition, mScaleY);
171                     }
172                     break;
173                 case AttributesType.S_TRANSLATION_X:
174                     if (!Float.isNaN(mTranslationX)) {
175                         splineSet.setPoint(mFramePosition, mTranslationX);
176                     }
177                     break;
178                 case AttributesType.S_TRANSLATION_Y:
179                     if (!Float.isNaN(mTranslationY)) {
180                         splineSet.setPoint(mFramePosition, mTranslationY);
181                     }
182                     break;
183                 case AttributesType.S_TRANSLATION_Z:
184                     if (!Float.isNaN(mTranslationZ)) {
185                         splineSet.setPoint(mFramePosition, mTranslationZ);
186                     }
187                     break;
188                 case AttributesType.S_PROGRESS:
189                     if (!Float.isNaN(mProgress)) {
190                         splineSet.setPoint(mFramePosition, mProgress);
191                     }
192                     break;
193                 default:
194                     System.err.println("not supported by KeyAttributes " + s);
195             }
196         }
197     }
198 
199     @Override
clone()200     public MotionKey clone() {
201         return null;
202     }
203 
204     // @TODO: add description
205     @Override
setValue(int type, int value)206     public boolean setValue(int type, int value) {
207 
208         switch (type) {
209             case AttributesType.TYPE_VISIBILITY:
210                 mVisibility = value;
211                 break;
212             case AttributesType.TYPE_CURVE_FIT:
213                 mCurveFit = value;
214                 break;
215             case TypedValues.TYPE_FRAME_POSITION:
216                 mFramePosition = value;
217                 break;
218             default:
219                 if (!setValue(type, value)) {
220                     return super.setValue(type, value);
221                 }
222         }
223         return true;
224     }
225 
226     // @TODO: add description
227     @Override
setValue(int type, float value)228     public boolean setValue(int type, float value) {
229         switch (type) {
230             case AttributesType.TYPE_ALPHA:
231                 mAlpha = value;
232                 break;
233             case AttributesType.TYPE_TRANSLATION_X:
234                 mTranslationX = value;
235                 break;
236             case AttributesType.TYPE_TRANSLATION_Y:
237                 mTranslationY = value;
238                 break;
239             case AttributesType.TYPE_TRANSLATION_Z:
240                 mTranslationZ = value;
241                 break;
242             case AttributesType.TYPE_ELEVATION:
243                 mElevation = value;
244                 break;
245             case AttributesType.TYPE_ROTATION_X:
246                 mRotationX = value;
247                 break;
248             case AttributesType.TYPE_ROTATION_Y:
249                 mRotationY = value;
250                 break;
251             case AttributesType.TYPE_ROTATION_Z:
252                 mRotation = value;
253                 break;
254             case AttributesType.TYPE_SCALE_X:
255                 mScaleX = value;
256                 break;
257             case AttributesType.TYPE_SCALE_Y:
258                 mScaleY = value;
259                 break;
260             case AttributesType.TYPE_PIVOT_X:
261                 mPivotX = value;
262                 break;
263             case AttributesType.TYPE_PIVOT_Y:
264                 mPivotY = value;
265                 break;
266             case AttributesType.TYPE_PROGRESS:
267                 mProgress = value;
268                 break;
269             case AttributesType.TYPE_PATH_ROTATE:
270                 mTransitionPathRotate = value;
271                 break;
272             case TypedValues.TYPE_FRAME_POSITION:
273                 mTransitionPathRotate = value;
274                 break;
275             default:
276                 return super.setValue(type, value);
277         }
278         return true;
279     }
280 
281     // @TODO: add description
282     @Override
setInterpolation(HashMap<String, Integer> interpolation)283     public void setInterpolation(HashMap<String, Integer> interpolation) {
284         if (!Float.isNaN(mAlpha)) {
285             interpolation.put(AttributesType.S_ALPHA, mCurveFit);
286         }
287         if (!Float.isNaN(mElevation)) {
288             interpolation.put(AttributesType.S_ELEVATION, mCurveFit);
289         }
290         if (!Float.isNaN(mRotation)) {
291             interpolation.put(AttributesType.S_ROTATION_Z, mCurveFit);
292         }
293         if (!Float.isNaN(mRotationX)) {
294             interpolation.put(AttributesType.S_ROTATION_X, mCurveFit);
295         }
296         if (!Float.isNaN(mRotationY)) {
297             interpolation.put(AttributesType.S_ROTATION_Y, mCurveFit);
298         }
299         if (!Float.isNaN(mPivotX)) {
300             interpolation.put(AttributesType.S_PIVOT_X, mCurveFit);
301         }
302         if (!Float.isNaN(mPivotY)) {
303             interpolation.put(AttributesType.S_PIVOT_Y, mCurveFit);
304         }
305         if (!Float.isNaN(mTranslationX)) {
306             interpolation.put(AttributesType.S_TRANSLATION_X, mCurveFit);
307         }
308         if (!Float.isNaN(mTranslationY)) {
309             interpolation.put(AttributesType.S_TRANSLATION_Y, mCurveFit);
310         }
311         if (!Float.isNaN(mTranslationZ)) {
312             interpolation.put(AttributesType.S_TRANSLATION_Z, mCurveFit);
313         }
314         if (!Float.isNaN(mTransitionPathRotate)) {
315             interpolation.put(AttributesType.S_PATH_ROTATE, mCurveFit);
316         }
317         if (!Float.isNaN(mScaleX)) {
318             interpolation.put(AttributesType.S_SCALE_X, mCurveFit);
319         }
320         if (!Float.isNaN(mScaleY)) {
321             interpolation.put(AttributesType.S_SCALE_Y, mCurveFit);
322         }
323         if (!Float.isNaN(mProgress)) {
324             interpolation.put(AttributesType.S_PROGRESS, mCurveFit);
325         }
326         if (mCustom.size() > 0) {
327             for (String s : mCustom.keySet()) {
328                 interpolation.put(AttributesType.S_CUSTOM + "," + s, mCurveFit);
329             }
330         }
331     }
332 
333     // @TODO: add description
334     @Override
setValue(int type, String value)335     public boolean setValue(int type, String value) {
336         switch (type) {
337             case AttributesType.TYPE_EASING:
338                 mTransitionEasing = value;
339                 break;
340 
341             case TypedValues.TYPE_TARGET:
342                 mTargetString = value;
343                 break;
344             default:
345                 return super.setValue(type, value);
346         }
347         return true;
348     }
349 
350     @Override
getId(String name)351     public int getId(String name) {
352         return AttributesType.getId(name);
353     }
354 
getCurveFit()355     public int getCurveFit() {
356         return mCurveFit;
357     }
358 
359     // @TODO: add description
printAttributes()360     public void printAttributes() {
361         HashSet<String> nameSet = new HashSet<>();
362         getAttributeNames(nameSet);
363 
364         System.out.println(" ------------- " + mFramePosition + " -------------");
365         String[] names = nameSet.toArray(new String[0]);
366         for (int i = 0; i < names.length; i++) {
367             int id = AttributesType.getId(names[i]);
368             System.out.println(names[i] + ":" + getFloatValue(id));
369         }
370     }
371 
getFloatValue(int id)372     private float getFloatValue(int id) {
373         switch (id) {
374             case AttributesType.TYPE_ALPHA:
375                 return mAlpha;
376             case AttributesType.TYPE_TRANSLATION_X:
377                 return mTranslationX;
378             case AttributesType.TYPE_TRANSLATION_Y:
379                 return mTranslationY;
380             case AttributesType.TYPE_TRANSLATION_Z:
381                 return mTranslationZ;
382             case AttributesType.TYPE_ELEVATION:
383                 return mElevation;
384             case AttributesType.TYPE_ROTATION_X:
385                 return mRotationX;
386             case AttributesType.TYPE_ROTATION_Y:
387                 return mRotationY;
388             case AttributesType.TYPE_ROTATION_Z:
389                 return mRotation;
390             case AttributesType.TYPE_SCALE_X:
391                 return mScaleX;
392             case AttributesType.TYPE_SCALE_Y:
393                 return mScaleY;
394             case AttributesType.TYPE_PIVOT_X:
395                 return mPivotX;
396             case AttributesType.TYPE_PIVOT_Y:
397                 return mPivotY;
398             case AttributesType.TYPE_PROGRESS:
399                 return mProgress;
400             case AttributesType.TYPE_PATH_ROTATE:
401                 return mTransitionPathRotate;
402             case TypedValues.TYPE_FRAME_POSITION:
403                 return mFramePosition;
404             default:
405                 return Float.NaN;
406         }
407     }
408 }
409