1 /* 2 * Copyright (C) 2007 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 android.util; 18 19 import android.annotation.AnyRes; 20 import android.annotation.FloatRange; 21 import android.annotation.IntDef; 22 import android.annotation.IntRange; 23 import android.annotation.NonNull; 24 import android.content.pm.ActivityInfo.Config; 25 import android.ravenwood.annotation.RavenwoodKeepWholeClass; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 30 /** 31 * Container for a dynamically typed data value. Primarily used with 32 * {@link android.content.res.Resources} for holding resource values. 33 */ 34 @RavenwoodKeepWholeClass 35 public class TypedValue { 36 /** The value contains no data. */ 37 public static final int TYPE_NULL = 0x00; 38 39 /** The <var>data</var> field holds a resource identifier. */ 40 public static final int TYPE_REFERENCE = 0x01; 41 /** The <var>data</var> field holds an attribute resource 42 * identifier (referencing an attribute in the current theme 43 * style, not a resource entry). */ 44 public static final int TYPE_ATTRIBUTE = 0x02; 45 /** The <var>string</var> field holds string data. In addition, if 46 * <var>data</var> is non-zero then it is the string block 47 * index of the string and <var>assetCookie</var> is the set of 48 * assets the string came from. */ 49 public static final int TYPE_STRING = 0x03; 50 /** The <var>data</var> field holds an IEEE 754 floating point number. */ 51 public static final int TYPE_FLOAT = 0x04; 52 /** The <var>data</var> field holds a complex number encoding a 53 * dimension value. */ 54 public static final int TYPE_DIMENSION = 0x05; 55 /** The <var>data</var> field holds a complex number encoding a fraction 56 * of a container. */ 57 public static final int TYPE_FRACTION = 0x06; 58 59 /** Identifies the start of plain integer values. Any type value 60 * from this to {@link #TYPE_LAST_INT} means the 61 * <var>data</var> field holds a generic integer value. */ 62 public static final int TYPE_FIRST_INT = 0x10; 63 64 /** The <var>data</var> field holds a number that was 65 * originally specified in decimal. */ 66 public static final int TYPE_INT_DEC = 0x10; 67 /** The <var>data</var> field holds a number that was 68 * originally specified in hexadecimal (0xn). */ 69 public static final int TYPE_INT_HEX = 0x11; 70 /** 71 * {@link #data} holds 0 to represent {@code false}, or a value different from 0 to represent 72 * {@code true}. 73 */ 74 public static final int TYPE_INT_BOOLEAN = 0x12; 75 /** Identifies the start of integer values that were specified as 76 * color constants (starting with '#'). */ 77 public static final int TYPE_FIRST_COLOR_INT = 0x1c; 78 79 /** The <var>data</var> field holds a color that was originally 80 * specified as #aarrggbb. */ 81 public static final int TYPE_INT_COLOR_ARGB8 = 0x1c; 82 /** The <var>data</var> field holds a color that was originally 83 * specified as #rrggbb. */ 84 public static final int TYPE_INT_COLOR_RGB8 = 0x1d; 85 /** The <var>data</var> field holds a color that was originally 86 * specified as #argb. */ 87 public static final int TYPE_INT_COLOR_ARGB4 = 0x1e; 88 /** The <var>data</var> field holds a color that was originally 89 * specified as #rgb. */ 90 public static final int TYPE_INT_COLOR_RGB4 = 0x1f; 91 92 /** Identifies the end of integer values that were specified as color 93 * constants. */ 94 public static final int TYPE_LAST_COLOR_INT = 0x1f; 95 96 /** Identifies the end of plain integer values. */ 97 public static final int TYPE_LAST_INT = 0x1f; 98 99 /* ------------------------------------------------------------ */ 100 101 /** Complex data: bit location of unit information. */ 102 public static final int COMPLEX_UNIT_SHIFT = 0; 103 /** Complex data: mask to extract unit information (after shifting by 104 * {@link #COMPLEX_UNIT_SHIFT}). This gives us 16 possible types, as 105 * defined below. */ 106 public static final int COMPLEX_UNIT_MASK = 0xf; 107 108 private static final float INCHES_PER_PT = (1.0f / 72); 109 private static final float INCHES_PER_MM = (1.0f / 25.4f); 110 111 /** @hide **/ 112 @IntDef(prefix = "COMPLEX_UNIT_", value = { 113 COMPLEX_UNIT_PX, 114 COMPLEX_UNIT_DIP, 115 COMPLEX_UNIT_SP, 116 COMPLEX_UNIT_PT, 117 COMPLEX_UNIT_IN, 118 COMPLEX_UNIT_MM, 119 }) 120 @Retention(RetentionPolicy.SOURCE) 121 public @interface ComplexDimensionUnit {} 122 123 /** {@link #TYPE_DIMENSION} complex unit: Value is raw pixels. */ 124 public static final int COMPLEX_UNIT_PX = 0; 125 /** {@link #TYPE_DIMENSION} complex unit: Value is Device Independent 126 * Pixels. */ 127 public static final int COMPLEX_UNIT_DIP = 1; 128 /** {@link #TYPE_DIMENSION} complex unit: Value is a scaled pixel. */ 129 public static final int COMPLEX_UNIT_SP = 2; 130 /** {@link #TYPE_DIMENSION} complex unit: Value is in points. */ 131 public static final int COMPLEX_UNIT_PT = 3; 132 /** {@link #TYPE_DIMENSION} complex unit: Value is in inches. */ 133 public static final int COMPLEX_UNIT_IN = 4; 134 /** {@link #TYPE_DIMENSION} complex unit: Value is in millimeters. */ 135 public static final int COMPLEX_UNIT_MM = 5; 136 137 /** {@link #TYPE_FRACTION} complex unit: A basic fraction of the overall 138 * size. */ 139 public static final int COMPLEX_UNIT_FRACTION = 0; 140 /** {@link #TYPE_FRACTION} complex unit: A fraction of the parent size. */ 141 public static final int COMPLEX_UNIT_FRACTION_PARENT = 1; 142 143 /** Complex data: where the radix information is, telling where the decimal 144 * place appears in the mantissa. */ 145 public static final int COMPLEX_RADIX_SHIFT = 4; 146 /** Complex data: mask to extract radix information (after shifting by 147 * {@link #COMPLEX_RADIX_SHIFT}). This give us 4 possible fixed point 148 * representations as defined below. */ 149 public static final int COMPLEX_RADIX_MASK = 0x3; 150 151 /** Complex data: the mantissa is an integral number -- i.e., 0xnnnnnn.0 */ 152 public static final int COMPLEX_RADIX_23p0 = 0; 153 /** Complex data: the mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn */ 154 public static final int COMPLEX_RADIX_16p7 = 1; 155 /** Complex data: the mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn */ 156 public static final int COMPLEX_RADIX_8p15 = 2; 157 /** Complex data: the mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn */ 158 public static final int COMPLEX_RADIX_0p23 = 3; 159 160 /** Complex data: bit location of mantissa information. */ 161 public static final int COMPLEX_MANTISSA_SHIFT = 8; 162 /** Complex data: mask to extract mantissa information (after shifting by 163 * {@link #COMPLEX_MANTISSA_SHIFT}). This gives us 23 bits of precision; 164 * the top bit is the sign. */ 165 public static final int COMPLEX_MANTISSA_MASK = 0xffffff; 166 167 /* ------------------------------------------------------------ */ 168 169 /** 170 * {@link #TYPE_NULL} data indicating the value was not specified. 171 */ 172 public static final int DATA_NULL_UNDEFINED = 0; 173 /** 174 * {@link #TYPE_NULL} data indicating the value was explicitly set to null. 175 */ 176 public static final int DATA_NULL_EMPTY = 1; 177 178 /* ------------------------------------------------------------ */ 179 180 /** 181 * If {@link #density} is equal to this value, then the density should be 182 * treated as the system's default density value: {@link DisplayMetrics#DENSITY_DEFAULT}. 183 */ 184 public static final int DENSITY_DEFAULT = 0; 185 186 /** 187 * If {@link #density} is equal to this value, then there is no density 188 * associated with the resource and it should not be scaled. 189 */ 190 public static final int DENSITY_NONE = 0xffff; 191 192 /* ------------------------------------------------------------ */ 193 194 /** The type held by this value, as defined by the constants here. 195 * This tells you how to interpret the other fields in the object. */ 196 public int type; 197 198 /** If the value holds a string, this is it. */ 199 public CharSequence string; 200 201 /** Basic data in the value, interpreted according to {@link #type} */ 202 public int data; 203 204 /** Additional information about where the value came from; only 205 * set for strings. */ 206 public int assetCookie; 207 208 /** If Value came from a resource, this holds the corresponding resource id. */ 209 @AnyRes 210 public int resourceId; 211 212 /** 213 * If the value came from a resource, these are the configurations for 214 * which its contents can change. 215 * 216 * <p>For example, if a resource has a value defined for the -land resource qualifier, 217 * this field will have the {@link android.content.pm.ActivityInfo#CONFIG_ORIENTATION} bit set. 218 * </p> 219 * 220 * @see android.content.pm.ActivityInfo#CONFIG_MCC 221 * @see android.content.pm.ActivityInfo#CONFIG_MNC 222 * @see android.content.pm.ActivityInfo#CONFIG_LOCALE 223 * @see android.content.pm.ActivityInfo#CONFIG_TOUCHSCREEN 224 * @see android.content.pm.ActivityInfo#CONFIG_KEYBOARD 225 * @see android.content.pm.ActivityInfo#CONFIG_KEYBOARD_HIDDEN 226 * @see android.content.pm.ActivityInfo#CONFIG_NAVIGATION 227 * @see android.content.pm.ActivityInfo#CONFIG_ORIENTATION 228 * @see android.content.pm.ActivityInfo#CONFIG_SCREEN_LAYOUT 229 * @see android.content.pm.ActivityInfo#CONFIG_UI_MODE 230 * @see android.content.pm.ActivityInfo#CONFIG_SCREEN_SIZE 231 * @see android.content.pm.ActivityInfo#CONFIG_SMALLEST_SCREEN_SIZE 232 * @see android.content.pm.ActivityInfo#CONFIG_DENSITY 233 * @see android.content.pm.ActivityInfo#CONFIG_LAYOUT_DIRECTION 234 * @see android.content.pm.ActivityInfo#CONFIG_COLOR_MODE 235 * 236 */ 237 public @Config int changingConfigurations = -1; 238 239 /** 240 * If the Value came from a resource, this holds the corresponding pixel density. 241 * */ 242 public int density; 243 244 /** 245 * If the Value came from a style resource or a layout resource (set in an XML layout), this 246 * holds the corresponding style or layout resource id against which the attribute was resolved. 247 */ 248 public int sourceResourceId; 249 250 /** 251 * Whether the value uses feature flags that need to be evaluated at runtime. 252 * @hide 253 */ 254 public boolean usesFeatureFlags = false; 255 256 /* ------------------------------------------------------------ */ 257 258 /** Return the data for this value as a float. Only use for values 259 * whose type is {@link #TYPE_FLOAT}. */ getFloat()260 public final float getFloat() { 261 return Float.intBitsToFloat(data); 262 } 263 264 private static final float MANTISSA_MULT = 265 1.0f / (1<<TypedValue.COMPLEX_MANTISSA_SHIFT); 266 private static final float[] RADIX_MULTS = new float[] { 267 1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT, 268 1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT 269 }; 270 271 /** 272 * Determine if a value is a color. 273 * 274 * This works by comparing {@link #type} to {@link #TYPE_FIRST_COLOR_INT} 275 * and {@link #TYPE_LAST_COLOR_INT}. 276 * 277 * @return true if this value is a color 278 */ isColorType()279 public boolean isColorType() { 280 return (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT); 281 } 282 283 /** 284 * Retrieve the base value from a complex data integer. This uses the 285 * {@link #COMPLEX_MANTISSA_MASK} and {@link #COMPLEX_RADIX_MASK} fields of 286 * the data to compute a floating point representation of the number they 287 * describe. The units are ignored. 288 * 289 * @param complex A complex data value. 290 * 291 * @return A floating point value corresponding to the complex data. 292 */ complexToFloat(int complex)293 public static float complexToFloat(int complex) 294 { 295 return (complex&(TypedValue.COMPLEX_MANTISSA_MASK 296 <<TypedValue.COMPLEX_MANTISSA_SHIFT)) 297 * RADIX_MULTS[(complex>>TypedValue.COMPLEX_RADIX_SHIFT) 298 & TypedValue.COMPLEX_RADIX_MASK]; 299 } 300 301 /** 302 * Converts a complex data value holding a dimension to its final floating 303 * point value. The given <var>data</var> must be structured as a 304 * {@link #TYPE_DIMENSION}. 305 * 306 * @param data A complex data value holding a unit, magnitude, and 307 * mantissa. 308 * @param metrics Current display metrics to use in the conversion -- 309 * supplies display density and scaling information. 310 * 311 * @return The complex floating point value multiplied by the appropriate 312 * metrics depending on its unit. 313 */ complexToDimension(int data, DisplayMetrics metrics)314 public static float complexToDimension(int data, DisplayMetrics metrics) 315 { 316 return applyDimension( 317 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, 318 complexToFloat(data), 319 metrics); 320 } 321 322 /** 323 * Converts a complex data value holding a dimension to its final value 324 * as an integer pixel offset. This is the same as 325 * {@link #complexToDimension}, except the raw floating point value is 326 * truncated to an integer (pixel) value. 327 * The given <var>data</var> must be structured as a 328 * {@link #TYPE_DIMENSION}. 329 * 330 * @param data A complex data value holding a unit, magnitude, and 331 * mantissa. 332 * @param metrics Current display metrics to use in the conversion -- 333 * supplies display density and scaling information. 334 * 335 * @return The number of pixels specified by the data and its desired 336 * multiplier and units. 337 */ complexToDimensionPixelOffset(int data, DisplayMetrics metrics)338 public static int complexToDimensionPixelOffset(int data, 339 DisplayMetrics metrics) 340 { 341 return (int)applyDimension( 342 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, 343 complexToFloat(data), 344 metrics); 345 } 346 347 /** 348 * Converts a complex data value holding a dimension to its final value 349 * as an integer pixel size. This is the same as 350 * {@link #complexToDimension}, except the raw floating point value is 351 * converted to an integer (pixel) value for use as a size. A size 352 * conversion involves rounding the base value, and ensuring that a 353 * non-zero base value is at least one pixel in size. 354 * The given <var>data</var> must be structured as a 355 * {@link #TYPE_DIMENSION}. 356 * 357 * @param data A complex data value holding a unit, magnitude, and 358 * mantissa. 359 * @param metrics Current display metrics to use in the conversion -- 360 * supplies display density and scaling information. 361 * 362 * @return The number of pixels specified by the data and its desired 363 * multiplier and units. 364 */ complexToDimensionPixelSize(int data, DisplayMetrics metrics)365 public static int complexToDimensionPixelSize(int data, 366 DisplayMetrics metrics) 367 { 368 final float value = complexToFloat(data); 369 final float f = applyDimension( 370 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK, 371 value, 372 metrics); 373 final int res = (int) ((f >= 0) ? (f + 0.5f) : (f - 0.5f)); 374 if (res != 0) return res; 375 if (value == 0) return 0; 376 if (value > 0) return 1; 377 return -1; 378 } 379 380 /** 381 * @hide Was accidentally exposed in API level 1 for debugging purposes. 382 * Kept for compatibility just in case although the debugging code has been removed. 383 */ 384 @Deprecated complexToDimensionNoisy(int data, DisplayMetrics metrics)385 public static float complexToDimensionNoisy(int data, DisplayMetrics metrics) 386 { 387 return complexToDimension(data, metrics); 388 } 389 390 /** 391 * Return the complex unit type for this value. For example, a dimen type 392 * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Only use for values 393 * whose type is {@link #TYPE_DIMENSION}. 394 * 395 * @return The complex unit type. 396 */ getComplexUnit()397 public int getComplexUnit() { 398 return getUnitFromComplexDimension(data); 399 } 400 401 /** 402 * Return the complex unit type for the given complex dimension. For example, a dimen type 403 * with value 12sp will return {@link #COMPLEX_UNIT_SP}. Use with values created with {@link 404 * #createComplexDimension(int, int)} etc. 405 * 406 * @return The complex unit type. 407 * 408 * @hide 409 */ getUnitFromComplexDimension(int complexDimension)410 public static int getUnitFromComplexDimension(int complexDimension) { 411 return COMPLEX_UNIT_MASK & (complexDimension >> TypedValue.COMPLEX_UNIT_SHIFT); 412 } 413 414 /** 415 * Converts an unpacked complex data value holding a dimension to its final floating point pixel 416 * value. The two parameters <var>unit</var> and <var>value</var> are as in {@link 417 * #TYPE_DIMENSION}. 418 * 419 * <p>To convert the other way, e.g. from pixels to DP, use {@link #deriveDimension(int, float, 420 * DisplayMetrics)}. 421 * 422 * @param unit The unit to convert from. 423 * @param value The value to apply the unit to. 424 * @param metrics Current display metrics to use in the conversion -- 425 * supplies display density and scaling information. 426 * 427 * @return The equivalent pixel value—i.e. the complex floating point value multiplied by the 428 * appropriate metrics depending on its unit—or zero if unit is not valid. 429 */ applyDimension(@omplexDimensionUnit int unit, float value, DisplayMetrics metrics)430 public static float applyDimension(@ComplexDimensionUnit int unit, float value, 431 DisplayMetrics metrics) 432 { 433 switch (unit) { 434 case COMPLEX_UNIT_PX: 435 return value; 436 case COMPLEX_UNIT_DIP: 437 return value * metrics.density; 438 case COMPLEX_UNIT_SP: 439 if (metrics.fontScaleConverter != null) { 440 return applyDimension( 441 COMPLEX_UNIT_DIP, 442 metrics.fontScaleConverter.convertSpToDp(value), 443 metrics); 444 } else { 445 return value * metrics.scaledDensity; 446 } 447 case COMPLEX_UNIT_PT: 448 return value * metrics.xdpi * INCHES_PER_PT; 449 case COMPLEX_UNIT_IN: 450 return value * metrics.xdpi; 451 case COMPLEX_UNIT_MM: 452 return value * metrics.xdpi * INCHES_PER_MM; 453 } 454 return 0; 455 } 456 457 458 /** 459 * Converts a pixel value to the given dimension, e.g. PX to DP. 460 * 461 * <p>This is the inverse of {@link #applyDimension(int, float, DisplayMetrics)} 462 * 463 * @param unitToConvertTo The unit to convert to. 464 * @param pixelValue The raw pixels value to convert from. 465 * @param metrics Current display metrics to use in the conversion -- 466 * supplies display density and scaling information. 467 * 468 * @return A dimension value equivalent to the given number of pixels 469 * @throws IllegalArgumentException if unitToConvertTo is not valid. 470 */ deriveDimension( @omplexDimensionUnit int unitToConvertTo, float pixelValue, @NonNull DisplayMetrics metrics)471 public static float deriveDimension( 472 @ComplexDimensionUnit int unitToConvertTo, 473 float pixelValue, 474 @NonNull DisplayMetrics metrics) { 475 switch (unitToConvertTo) { 476 case COMPLEX_UNIT_PX: 477 return pixelValue; 478 case COMPLEX_UNIT_DIP: { 479 // Avoid divide-by-zero, and return 0 since that's what the inverse function will do 480 if (metrics.density == 0) { 481 return 0; 482 } 483 return pixelValue / metrics.density; 484 } 485 case COMPLEX_UNIT_SP: 486 if (metrics.fontScaleConverter != null) { 487 final float dpValue = deriveDimension(COMPLEX_UNIT_DIP, pixelValue, metrics); 488 return metrics.fontScaleConverter.convertDpToSp(dpValue); 489 } else { 490 if (metrics.scaledDensity == 0) { 491 return 0; 492 } 493 return pixelValue / metrics.scaledDensity; 494 } 495 case COMPLEX_UNIT_PT: { 496 if (metrics.xdpi == 0) { 497 return 0; 498 } 499 return pixelValue / metrics.xdpi / INCHES_PER_PT; 500 } 501 case COMPLEX_UNIT_IN: { 502 if (metrics.xdpi == 0) { 503 return 0; 504 } 505 return pixelValue / metrics.xdpi; 506 } 507 case COMPLEX_UNIT_MM: { 508 if (metrics.xdpi == 0) { 509 return 0; 510 } 511 return pixelValue / metrics.xdpi / INCHES_PER_MM; 512 } 513 default: 514 throw new IllegalArgumentException("Invalid unitToConvertTo " + unitToConvertTo); 515 } 516 } 517 518 /** 519 * Converts a pixel value to the given dimension, e.g. PX to DP. 520 * 521 * <p>This is just an alias of {@link #deriveDimension(int, float, DisplayMetrics)} with an 522 * easier-to-find name. 523 * 524 * @param unitToConvertTo The unit to convert to. 525 * @param pixelValue The raw pixels value to convert from. 526 * @param metrics Current display metrics to use in the conversion -- 527 * supplies display density and scaling information. 528 * 529 * @return A dimension value equivalent to the given number of pixels 530 * @throws IllegalArgumentException if unitToConvertTo is not valid. 531 */ convertPixelsToDimension( @omplexDimensionUnit int unitToConvertTo, float pixelValue, @NonNull DisplayMetrics metrics)532 public static float convertPixelsToDimension( 533 @ComplexDimensionUnit int unitToConvertTo, 534 float pixelValue, 535 @NonNull DisplayMetrics metrics) { 536 return deriveDimension(unitToConvertTo, pixelValue, metrics); 537 } 538 539 /** 540 * Converts a dimension value to raw pixels, e.g. DP to PX. 541 * 542 * <p>This is just an alias of {@link #applyDimension(int, float, DisplayMetrics)} with an 543 * easier-to-find name. 544 * 545 * @param unitToConvertFrom The unit to convert from. 546 * @param value The dimension value to apply the unit to. 547 * @param metrics Current display metrics to use in the conversion -- 548 * supplies display density and scaling information. 549 * 550 * @return The equivalent pixel value—i.e. the complex floating point value multiplied by the 551 * appropriate metrics depending on its unit—or zero if unit is not valid. 552 */ convertDimensionToPixels( @omplexDimensionUnit int unitToConvertFrom, float value, @NonNull DisplayMetrics metrics)553 public static float convertDimensionToPixels( 554 @ComplexDimensionUnit int unitToConvertFrom, 555 float value, 556 @NonNull DisplayMetrics metrics) { 557 return applyDimension(unitToConvertFrom, value, metrics); 558 } 559 560 /** 561 * Return the data for this value as a dimension. Only use for values 562 * whose type is {@link #TYPE_DIMENSION}. 563 * 564 * @param metrics Current display metrics to use in the conversion -- 565 * supplies display density and scaling information. 566 * 567 * @return The complex floating point value multiplied by the appropriate 568 * metrics depending on its unit. 569 */ getDimension(DisplayMetrics metrics)570 public float getDimension(DisplayMetrics metrics) 571 { 572 return complexToDimension(data, metrics); 573 } 574 575 /** 576 * Construct a complex data integer. This validates the radix and the magnitude of the 577 * mantissa, and sets the {@link TypedValue#COMPLEX_MANTISSA_MASK} and 578 * {@link TypedValue#COMPLEX_RADIX_MASK} components as provided. The units are not set. 579 ** 580 * @param mantissa an integer representing the mantissa. 581 * @param radix a radix option, e.g. {@link TypedValue#COMPLEX_RADIX_23p0}. 582 * @return A complex data integer representing the value. 583 * @hide 584 */ createComplex(@ntRangefrom = -0x800000, to = 0x7FFFFF) int mantissa, int radix)585 private static int createComplex(@IntRange(from = -0x800000, to = 0x7FFFFF) int mantissa, 586 int radix) { 587 if (mantissa < -0x800000 || mantissa >= 0x800000) { 588 throw new IllegalArgumentException("Magnitude of mantissa is too large: " + mantissa); 589 } 590 if (radix < TypedValue.COMPLEX_RADIX_23p0 || radix > TypedValue.COMPLEX_RADIX_0p23) { 591 throw new IllegalArgumentException("Invalid radix: " + radix); 592 } 593 return ((mantissa & TypedValue.COMPLEX_MANTISSA_MASK) << TypedValue.COMPLEX_MANTISSA_SHIFT) 594 | (radix << TypedValue.COMPLEX_RADIX_SHIFT); 595 } 596 597 /** 598 * Convert a base value to a complex data integer. This sets the {@link 599 * TypedValue#COMPLEX_MANTISSA_MASK} and {@link TypedValue#COMPLEX_RADIX_MASK} fields of the 600 * data to create a floating point representation of the given value. The units are not set. 601 * 602 * <p>This is the inverse of {@link TypedValue#complexToFloat(int)}. 603 * 604 * @param value An integer value. 605 * @return A complex data integer representing the value. 606 * @hide 607 */ intToComplex(int value)608 public static int intToComplex(int value) { 609 if (value < -0x800000 || value >= 0x800000) { 610 throw new IllegalArgumentException("Magnitude of the value is too large: " + value); 611 } 612 return createComplex(value, TypedValue.COMPLEX_RADIX_23p0); 613 } 614 615 /** 616 * Convert a base value to a complex data integer. This sets the {@link 617 * TypedValue#COMPLEX_MANTISSA_MASK} and {@link TypedValue#COMPLEX_RADIX_MASK} fields of the 618 * data to create a floating point representation of the given value. The units are not set. 619 * 620 * <p>This is the inverse of {@link TypedValue#complexToFloat(int)}. 621 * 622 * @param value A floating point value. 623 * @return A complex data integer representing the value. 624 * @hide 625 */ floatToComplex(@loatRangefrom = -0x800000, to = 0x7FFFFF) float value)626 public static int floatToComplex(@FloatRange(from = -0x800000, to = 0x7FFFFF) float value) { 627 // validate that the magnitude fits in this representation 628 if (value < (float) -0x800000 - .5f || value >= (float) 0x800000 - .5f) { 629 throw new IllegalArgumentException("Magnitude of the value is too large: " + value); 630 } 631 try { 632 // If there's no fraction, use integer representation, as that's clearer 633 if (value == (float) (int) value) { 634 return createComplex((int) value, TypedValue.COMPLEX_RADIX_23p0); 635 } 636 float absValue = Math.abs(value); 637 // If the magnitude is 0, we don't need any magnitude digits 638 if (absValue < 1f) { 639 return createComplex(Math.round(value * (1 << 23)), TypedValue.COMPLEX_RADIX_0p23); 640 } 641 // If the magnitude is less than 2^8, use 8 magnitude digits 642 if (absValue < (float) (1 << 8)) { 643 return createComplex(Math.round(value * (1 << 15)), TypedValue.COMPLEX_RADIX_8p15); 644 } 645 // If the magnitude is less than 2^16, use 16 magnitude digits 646 if (absValue < (float) (1 << 16)) { 647 return createComplex(Math.round(value * (1 << 7)), TypedValue.COMPLEX_RADIX_16p7); 648 } 649 // The magnitude requires all 23 digits 650 return createComplex(Math.round(value), TypedValue.COMPLEX_RADIX_23p0); 651 } catch (IllegalArgumentException ex) { 652 // Wrap exception so as to include the value argument in the message. 653 throw new IllegalArgumentException("Unable to convert value to complex: " + value, ex); 654 } 655 } 656 657 /** 658 * <p>Creates a complex data integer that stores a dimension value and units. 659 * 660 * <p>The resulting value can be passed to e.g. 661 * {@link TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)} to calculate the pixel 662 * value for the dimension. 663 * 664 * @param value the value of the dimension 665 * @param units the units of the dimension, e.g. {@link TypedValue#COMPLEX_UNIT_DIP} 666 * @return A complex data integer representing the value and units of the dimension. 667 * @hide 668 */ createComplexDimension( @ntRangefrom = -0x800000, to = 0x7FFFFF) int value, @ComplexDimensionUnit int units)669 public static int createComplexDimension( 670 @IntRange(from = -0x800000, to = 0x7FFFFF) int value, 671 @ComplexDimensionUnit int units) { 672 if (units < TypedValue.COMPLEX_UNIT_PX || units > TypedValue.COMPLEX_UNIT_MM) { 673 throw new IllegalArgumentException("Must be a valid COMPLEX_UNIT_*: " + units); 674 } 675 return intToComplex(value) | units; 676 } 677 678 /** 679 * <p>Creates a complex data integer that stores a dimension value and units. 680 * 681 * <p>The resulting value can be passed to e.g. 682 * {@link TypedValue#complexToDimensionPixelOffset(int, DisplayMetrics)} to calculate the pixel 683 * value for the dimension. 684 * 685 * @param value the value of the dimension 686 * @param units the units of the dimension, e.g. {@link TypedValue#COMPLEX_UNIT_DIP} 687 * @return A complex data integer representing the value and units of the dimension. 688 * @hide 689 */ createComplexDimension( @loatRangefrom = -0x800000, to = 0x7FFFFF) float value, @ComplexDimensionUnit int units)690 public static int createComplexDimension( 691 @FloatRange(from = -0x800000, to = 0x7FFFFF) float value, 692 @ComplexDimensionUnit int units) { 693 if (units < TypedValue.COMPLEX_UNIT_PX || units > TypedValue.COMPLEX_UNIT_MM) { 694 throw new IllegalArgumentException("Must be a valid COMPLEX_UNIT_*: " + units); 695 } 696 return floatToComplex(value) | units; 697 } 698 699 /** 700 * Converts a complex data value holding a fraction to its final floating 701 * point value. The given <var>data</var> must be structured as a 702 * {@link #TYPE_FRACTION}. 703 * 704 * @param data A complex data value holding a unit, magnitude, and 705 * mantissa. 706 * @param base The base value of this fraction. In other words, a 707 * standard fraction is multiplied by this value. 708 * @param pbase The parent base value of this fraction. In other 709 * words, a parent fraction (nn%p) is multiplied by this 710 * value. 711 * 712 * @return The complex floating point value multiplied by the appropriate 713 * base value depending on its unit. 714 */ complexToFraction(int data, float base, float pbase)715 public static float complexToFraction(int data, float base, float pbase) 716 { 717 switch ((data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK) { 718 case COMPLEX_UNIT_FRACTION: 719 return complexToFloat(data) * base; 720 case COMPLEX_UNIT_FRACTION_PARENT: 721 return complexToFloat(data) * pbase; 722 } 723 return 0; 724 } 725 726 /** 727 * Return the data for this value as a fraction. Only use for values whose 728 * type is {@link #TYPE_FRACTION}. 729 * 730 * @param base The base value of this fraction. In other words, a 731 * standard fraction is multiplied by this value. 732 * @param pbase The parent base value of this fraction. In other 733 * words, a parent fraction (nn%p) is multiplied by this 734 * value. 735 * 736 * @return The complex floating point value multiplied by the appropriate 737 * base value depending on its unit. 738 */ getFraction(float base, float pbase)739 public float getFraction(float base, float pbase) 740 { 741 return complexToFraction(data, base, pbase); 742 } 743 744 /** 745 * Regardless of the actual type of the value, try to convert it to a 746 * string value. For example, a color type will be converted to a 747 * string of the form #aarrggbb. 748 * 749 * @return CharSequence The coerced string value. If the value is 750 * null or the type is not known, null is returned. 751 */ coerceToString()752 public final CharSequence coerceToString() 753 { 754 int t = type; 755 if (t == TYPE_STRING) { 756 return string; 757 } 758 return coerceToString(t, data); 759 } 760 761 private static final String[] DIMENSION_UNIT_STRS = new String[] { 762 "px", "dip", "sp", "pt", "in", "mm" 763 }; 764 private static final String[] FRACTION_UNIT_STRS = new String[] { 765 "%", "%p" 766 }; 767 768 /** 769 * Perform type conversion as per {@link #coerceToString()} on an 770 * explicitly supplied type and data. 771 * 772 * @param type The data type identifier. 773 * @param data The data value. 774 * 775 * @return String The coerced string value. If the value is 776 * null or the type is not known, null is returned. 777 */ coerceToString(int type, int data)778 public static final String coerceToString(int type, int data) 779 { 780 switch (type) { 781 case TYPE_NULL: 782 return null; 783 case TYPE_REFERENCE: 784 return "@" + data; 785 case TYPE_ATTRIBUTE: 786 return "?" + data; 787 case TYPE_FLOAT: 788 return Float.toString(Float.intBitsToFloat(data)); 789 case TYPE_DIMENSION: 790 return Float.toString(complexToFloat(data)) + DIMENSION_UNIT_STRS[ 791 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK]; 792 case TYPE_FRACTION: 793 return Float.toString(complexToFloat(data)*100) + FRACTION_UNIT_STRS[ 794 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK]; 795 case TYPE_INT_HEX: 796 return "0x" + Integer.toHexString(data); 797 case TYPE_INT_BOOLEAN: 798 return data != 0 ? "true" : "false"; 799 } 800 801 if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) { 802 return "#" + Integer.toHexString(data); 803 } else if (type >= TYPE_FIRST_INT && type <= TYPE_LAST_INT) { 804 return Integer.toString(data); 805 } 806 807 return null; 808 } 809 setTo(TypedValue other)810 public void setTo(TypedValue other) 811 { 812 type = other.type; 813 string = other.string; 814 data = other.data; 815 assetCookie = other.assetCookie; 816 resourceId = other.resourceId; 817 density = other.density; 818 } 819 toString()820 public String toString() 821 { 822 StringBuilder sb = new StringBuilder(); 823 sb.append("TypedValue{t=0x").append(Integer.toHexString(type)); 824 sb.append("/d=0x").append(Integer.toHexString(data)); 825 if (type == TYPE_STRING) { 826 sb.append(" \"").append(string != null ? string : "<null>").append("\""); 827 } 828 if (assetCookie != 0) { 829 sb.append(" a=").append(assetCookie); 830 } 831 if (resourceId != 0) { 832 sb.append(" r=0x").append(Integer.toHexString(resourceId)); 833 } 834 sb.append("}"); 835 return sb.toString(); 836 } 837 } 838