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 
17 package androidx.constraintlayout.core.motion;
18 /*
19  * Copyright (C) 2017 The Android Open Source Project
20  *
21  * Licensed under the Apache License, Version 2.0 (the "License");
22  * you may not use this file except in compliance with the License.
23  * You may obtain a copy of the License at
24  *
25  *      http://www.apache.org/licenses/LICENSE-2.0
26  *
27  * Unless required by applicable law or agreed to in writing, software
28  * distributed under the License is distributed on an "AS IS" BASIS,
29  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
30  * See the License for the specific language governing permissions and
31  * limitations under the License.
32  */
33 
34 
35 /**
36  * Defines non standard Attributes
37  *
38  *
39  */
40 public class CustomAttribute {
41     private static final String TAG = "TransitionLayout";
42     @SuppressWarnings("unused") private boolean mMethod = false;
43     String mName;
44     private AttributeType mType;
45     private int mIntegerValue;
46     private float mFloatValue;
47     @SuppressWarnings("unused") private String mStringValue;
48     boolean mBooleanValue;
49     private int mColorValue;
50 
51     public enum AttributeType {
52         INT_TYPE,
53         FLOAT_TYPE,
54         COLOR_TYPE,
55         COLOR_DRAWABLE_TYPE,
56         STRING_TYPE,
57         BOOLEAN_TYPE,
58         DIMENSION_TYPE,
59         REFERENCE_TYPE
60     }
61 
getType()62     public AttributeType getType() {
63         return mType;
64     }
65 
66     /**
67      * Continuous types are interpolated they are fired only at
68      */
isContinuous()69     public boolean isContinuous() {
70         switch (mType) {
71             case REFERENCE_TYPE:
72             case BOOLEAN_TYPE:
73             case STRING_TYPE:
74                 return false;
75             default:
76                 return true;
77         }
78     }
79 
setFloatValue(float value)80     public void setFloatValue(float value) {
81         mFloatValue = value;
82     }
83 
setColorValue(int value)84     public void setColorValue(int value) {
85         mColorValue = value;
86     }
87 
setIntValue(int value)88     public void setIntValue(int value) {
89         mIntegerValue = value;
90     }
91 
setStringValue(String value)92     public void setStringValue(String value) {
93         mStringValue = value;
94     }
95 
96     /**
97      * The number of interpolation values that need to be interpolated
98      * Typically 1 but 3 for colors.
99      *
100      * @return Typically 1 but 3 for colors.
101      */
numberOfInterpolatedValues()102     public int numberOfInterpolatedValues() {
103         switch (mType) {
104             case COLOR_TYPE:
105             case COLOR_DRAWABLE_TYPE:
106                 return 4;
107             default:
108                 return 1;
109         }
110     }
111 
112     /**
113      * Transforms value to a float for the purpose of interpolation
114      *
115      * @return interpolation value
116      */
getValueToInterpolate()117     public float getValueToInterpolate() {
118         switch (mType) {
119             case INT_TYPE:
120                 return mIntegerValue;
121             case FLOAT_TYPE:
122                 return mFloatValue;
123             case COLOR_TYPE:
124             case COLOR_DRAWABLE_TYPE:
125                 throw new RuntimeException("Color does not have a single color to interpolate");
126             case STRING_TYPE:
127                 throw new RuntimeException("Cannot interpolate String");
128             case BOOLEAN_TYPE:
129                 return mBooleanValue ? 1 : 0;
130             case DIMENSION_TYPE:
131                 return mFloatValue;
132             default:
133                 return Float.NaN;
134         }
135     }
136 
137     // @TODO: add description
getValuesToInterpolate(float[] ret)138     public void getValuesToInterpolate(float[] ret) {
139         switch (mType) {
140             case INT_TYPE:
141                 ret[0] = mIntegerValue;
142                 break;
143             case FLOAT_TYPE:
144                 ret[0] = mFloatValue;
145                 break;
146             case COLOR_DRAWABLE_TYPE:
147             case COLOR_TYPE:
148                 int a = 0xFF & (mColorValue >> 24);
149                 int r = 0xFF & (mColorValue >> 16);
150                 int g = 0xFF & (mColorValue >> 8);
151                 int b = 0xFF & mColorValue;
152                 float f_r = (float) Math.pow(r / 255.0f, 2.2);
153                 float f_g = (float) Math.pow(g / 255.0f, 2.2);
154                 float f_b = (float) Math.pow(b / 255.0f, 2.2);
155                 ret[0] = f_r;
156                 ret[1] = f_g;
157                 ret[2] = f_b;
158                 ret[3] = a / 255f;
159                 break;
160             case STRING_TYPE:
161                 throw new RuntimeException("Color does not have a single color to interpolate");
162             case BOOLEAN_TYPE:
163                 ret[0] = mBooleanValue ? 1 : 0;
164                 break;
165             case DIMENSION_TYPE:
166                 ret[0] = mFloatValue;
167                 break;
168             default:
169                 break;
170         }
171     }
172 
173     // @TODO: add description
setValue(float[] value)174     public void setValue(float[] value) {
175         switch (mType) {
176             case REFERENCE_TYPE:
177             case INT_TYPE:
178                 mIntegerValue = (int) value[0];
179                 break;
180             case FLOAT_TYPE:
181                 mFloatValue = value[0];
182                 break;
183             case COLOR_DRAWABLE_TYPE:
184             case COLOR_TYPE:
185                 mColorValue = hsvToRgb(value[0], value[1], value[2]);
186                 mColorValue = (mColorValue & 0xFFFFFF) | (clamp((int) (0xFF * value[3])) << 24);
187                 break;
188             case STRING_TYPE:
189                 throw new RuntimeException("Color does not have a single color to interpolate");
190             case BOOLEAN_TYPE:
191                 mBooleanValue = value[0] > 0.5;
192                 break;
193             case DIMENSION_TYPE:
194                 mFloatValue = value[0];
195                 break;
196             default:
197                 break;
198         }
199     }
200 
201     // @TODO: add description
hsvToRgb(float hue, float saturation, float value)202     public static int hsvToRgb(float hue, float saturation, float value) {
203         int h = (int) (hue * 6);
204         float f = hue * 6 - h;
205         int p = (int) (0.5f + 255 * value * (1 - saturation));
206         int q = (int) (0.5f + 255 * value * (1 - f * saturation));
207         int t = (int) (0.5f + 255 * value * (1 - (1 - f) * saturation));
208         int v = (int) (0.5f + 255 * value);
209         switch (h) {
210             case 0:
211                 return 0XFF000000 | (v << 16) + (t << 8) + p;
212             case 1:
213                 return 0XFF000000 | (q << 16) + (v << 8) + p;
214             case 2:
215                 return 0XFF000000 | (p << 16) + (v << 8) + t;
216             case 3:
217                 return 0XFF000000 | (p << 16) + (q << 8) + v;
218             case 4:
219                 return 0XFF000000 | (t << 16) + (p << 8) + v;
220             case 5:
221                 return 0XFF000000 | (v << 16) + (p << 8) + q;
222             default:
223                 return 0;
224         }
225     }
226 
227     /**
228      * test if the two attributes are different
229      */
diff(CustomAttribute customAttribute)230     public boolean diff(CustomAttribute customAttribute) {
231         if (customAttribute == null || mType != customAttribute.mType) {
232             return false;
233         }
234         switch (mType) {
235             case INT_TYPE:
236             case REFERENCE_TYPE:
237                 return mIntegerValue == customAttribute.mIntegerValue;
238             case FLOAT_TYPE:
239                 return mFloatValue == customAttribute.mFloatValue;
240             case COLOR_TYPE:
241             case COLOR_DRAWABLE_TYPE:
242                 return mColorValue == customAttribute.mColorValue;
243             case STRING_TYPE:
244                 return mIntegerValue == customAttribute.mIntegerValue;
245             case BOOLEAN_TYPE:
246                 return mBooleanValue == customAttribute.mBooleanValue;
247             case DIMENSION_TYPE:
248                 return mFloatValue == customAttribute.mFloatValue;
249             default:
250                 return false;
251         }
252     }
253 
CustomAttribute(String name, AttributeType attributeType)254     public CustomAttribute(String name, AttributeType attributeType) {
255         mName = name;
256         mType = attributeType;
257     }
258 
CustomAttribute(String name, AttributeType attributeType, Object value, boolean method)259     public CustomAttribute(String name, AttributeType attributeType, Object value, boolean method) {
260         mName = name;
261         mType = attributeType;
262         mMethod = method;
263         setValue(value);
264     }
265 
CustomAttribute(CustomAttribute source, Object value)266     public CustomAttribute(CustomAttribute source, Object value) {
267         mName = source.mName;
268         mType = source.mType;
269         setValue(value);
270 
271     }
272 
273     // @TODO: add description
setValue(Object value)274     public void setValue(Object value) {
275         switch (mType) {
276             case REFERENCE_TYPE:
277             case INT_TYPE:
278                 mIntegerValue = (Integer) value;
279                 break;
280             case FLOAT_TYPE:
281                 mFloatValue = (Float) value;
282                 break;
283             case COLOR_TYPE:
284             case COLOR_DRAWABLE_TYPE:
285                 mColorValue = (Integer) value;
286                 break;
287             case STRING_TYPE:
288                 mStringValue = (String) value;
289                 break;
290             case BOOLEAN_TYPE:
291                 mBooleanValue = (Boolean) value;
292                 break;
293             case DIMENSION_TYPE:
294                 mFloatValue = (Float) value;
295                 break;
296             default:
297                 break;
298         }
299     }
300 
clamp(int c)301     private static int clamp(int c) {
302         int n = 255;
303         c &= ~(c >> 31);
304         c -= n;
305         c &= (c >> 31);
306         c += n;
307         return c;
308     }
309 
310 }
311