1 /*
2  * Copyright (C) 2022 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.motion.utils;
18 
19 import android.graphics.drawable.ColorDrawable;
20 import android.graphics.drawable.Drawable;
21 import android.util.Log;
22 import android.view.View;
23 
24 import androidx.constraintlayout.motion.widget.Debug;
25 import androidx.constraintlayout.widget.ConstraintAttribute;
26 
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29 
30 public class CustomSupport {
31     private static final String TAG = "CustomSupport";
32     private static final boolean DEBUG = false;
33     /**
34      * sets the interpolated value
35      * @param att
36      * @param view
37      * @param value
38      */
setInterpolatedValue(ConstraintAttribute att, View view, float[] value)39     public static void setInterpolatedValue(ConstraintAttribute att, View view, float[] value) {
40         Class<? extends View> viewClass = view.getClass();
41 
42         String methodName = "set" + att.getName();
43         try {
44             Method method;
45             switch (att.getType()) {
46                 case INT_TYPE:
47                     method = viewClass.getMethod(methodName, Integer.TYPE);
48                     method.invoke(view, (int) value[0]);
49                     break;
50                 case FLOAT_TYPE:
51                     method = viewClass.getMethod(methodName, Float.TYPE);
52                     method.invoke(view, value[0]);
53                     break;
54                 case COLOR_DRAWABLE_TYPE: {
55                     method = viewClass.getMethod(methodName, Drawable.class);
56                     int r = clamp((int) ((float) Math.pow(value[0], 1.0 / 2.2) * 255.0f));
57                     int g = clamp((int) ((float) Math.pow(value[1], 1.0 / 2.2) * 255.0f));
58                     int b = clamp((int) ((float) Math.pow(value[2], 1.0 / 2.2) * 255.0f));
59                     int a = clamp((int) (value[3] * 255.0f));
60                     int color = a << 24 | (r << 16) | (g << 8) | b;
61                     ColorDrawable drawable = new ColorDrawable(); // TODO cache
62                     drawable.setColor(color);
63                     method.invoke(view, drawable);
64                 }
65                 break;
66                 case COLOR_TYPE:
67                     method = viewClass.getMethod(methodName, Integer.TYPE);
68                     int r = clamp((int) ((float) Math.pow(value[0], 1.0 / 2.2) * 255.0f));
69                     int g = clamp((int) ((float) Math.pow(value[1], 1.0 / 2.2) * 255.0f));
70                     int b = clamp((int) ((float) Math.pow(value[2], 1.0 / 2.2) * 255.0f));
71                     int a = clamp((int) (value[3] * 255.0f));
72                     int color = a << 24 | (r << 16) | (g << 8) | b;
73                     method.invoke(view, color);
74                     break;
75                 case STRING_TYPE:
76                     throw new RuntimeException("unable to interpolate strings " + att.getName());
77 
78                 case BOOLEAN_TYPE:
79                     method = viewClass.getMethod(methodName, Boolean.TYPE);
80                     method.invoke(view, value[0] > 0.5f);
81                     break;
82                 case DIMENSION_TYPE:
83                     method = viewClass.getMethod(methodName, Float.TYPE);
84                     method.invoke(view, value[0]);
85                     break;
86                 default:
87                     if (DEBUG) {
88                         Log.v(TAG, att.getType().toString());
89                     }
90             }
91         } catch (NoSuchMethodException e) {
92             Log.e(TAG, "No method " + methodName + " on View \"" + Debug.getName(view) + "\"", e);
93         } catch (IllegalAccessException e) {
94             Log.e(TAG, "Cannot access method " + methodName + " on View \""
95                     + Debug.getName(view) + "\"", e);
96         } catch (InvocationTargetException e) {
97             Log.e(TAG, "Cannot invoke method " + methodName + " on View \""
98                     + Debug.getName(view) + "\"", e);
99         }
100     }
101 
clamp(int c)102     private static int clamp(int c) {
103         int n = 255;
104         c &= ~(c >> 31);
105         c -= n;
106         c &= (c >> 31);
107         c += n;
108         return c;
109     }
110 }
111