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