• 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 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