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