• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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