Home | History | Annotate | Download | only in shadows
      1 package com.xtremelabs.robolectric.shadows;
      2 
      3 import android.util.DisplayMetrics;
      4 import android.util.TypedValue;
      5 import com.xtremelabs.robolectric.internal.Implementation;
      6 import com.xtremelabs.robolectric.internal.Implements;
      7 import com.xtremelabs.robolectric.internal.RealObject;
      8 
      9 import static android.util.TypedValue.*;
     10 
     11 
     12 /**
     13  * Portions of this file were copied from the Android source code,
     14  * licenced under the Apache License, Version 2.0
     15  *
     16  * http://www.google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/util/TypedValue.java
     17  */
     18 
     19 @SuppressWarnings({"UnusedDeclaration"})
     20 @Implements(TypedValue.class)
     21 public class ShadowTypedValue {
     22 
     23     @RealObject TypedValue typedValue;
     24 
     25     @Implementation
     26     public final float getFloat() {
     27         return Float.intBitsToFloat(typedValue.data);
     28     }
     29 
     30     private static final float MANTISSA_MULT =
     31         1.0f / (1<<TypedValue.COMPLEX_MANTISSA_SHIFT);
     32     private static final float[] RADIX_MULTS = new float[] {
     33         1.0f*MANTISSA_MULT, 1.0f/(1<<7)*MANTISSA_MULT,
     34         1.0f/(1<<15)*MANTISSA_MULT, 1.0f/(1<<23)*MANTISSA_MULT
     35     };
     36 
     37     @Implementation
     38     public static float complexToFloat(int complex)
     39     {
     40         return (complex&(TypedValue.COMPLEX_MANTISSA_MASK
     41                    <<TypedValue.COMPLEX_MANTISSA_SHIFT))
     42             * RADIX_MULTS[(complex>>TypedValue.COMPLEX_RADIX_SHIFT)
     43                             & TypedValue.COMPLEX_RADIX_MASK];
     44     }
     45 
     46     @Implementation
     47     public static float complexToDimension(int data, DisplayMetrics metrics)
     48     {
     49         return applyDimension(
     50             (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
     51             complexToFloat(data),
     52             metrics);
     53     }
     54 
     55     @Implementation
     56     public static int complexToDimensionPixelOffset(int data,
     57             DisplayMetrics metrics)
     58     {
     59         return (int)applyDimension(
     60                 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
     61                 complexToFloat(data),
     62                 metrics);
     63     }
     64 
     65     @Implementation
     66     public static int complexToDimensionPixelSize(int data,
     67             DisplayMetrics metrics)
     68     {
     69         final float value = complexToFloat(data);
     70         final float f = applyDimension(
     71                 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
     72                 value,
     73                 metrics);
     74         final int res = (int)(f+0.5f);
     75         if (res != 0) return res;
     76         if (value == 0) return 0;
     77         if (value > 0) return 1;
     78         return -1;
     79     }
     80 
     81     @Implementation
     82     public static float complexToDimensionNoisy(int data, DisplayMetrics metrics)
     83     {
     84         float res = complexToDimension(data, metrics);
     85         System.out.println(
     86             "Dimension (0x" + ((data>>TypedValue.COMPLEX_MANTISSA_SHIFT)
     87                                & TypedValue.COMPLEX_MANTISSA_MASK)
     88             + "*" + (RADIX_MULTS[(data>>TypedValue.COMPLEX_RADIX_SHIFT)
     89                                 & TypedValue.COMPLEX_RADIX_MASK] / MANTISSA_MULT)
     90             + ")" + DIMENSION_UNIT_STRS[(data>>COMPLEX_UNIT_SHIFT)
     91                                 & COMPLEX_UNIT_MASK]
     92             + " = " + res);
     93         return res;
     94     }
     95 
     96     @Implementation
     97     public static float applyDimension(int unit, float value, DisplayMetrics metrics) {
     98         switch (unit) {
     99             case COMPLEX_UNIT_PX:
    100                 return value;
    101             case COMPLEX_UNIT_DIP:
    102                 return value * metrics.density;
    103             case COMPLEX_UNIT_SP:
    104                 return value * metrics.scaledDensity;
    105             case COMPLEX_UNIT_PT:
    106                 return value * metrics.xdpi * (1.0f / 72);
    107             case COMPLEX_UNIT_IN:
    108                 return value * metrics.xdpi;
    109             case COMPLEX_UNIT_MM:
    110                 return value * metrics.xdpi * (1.0f / 25.4f);
    111         }
    112         return 0;
    113     }
    114 
    115     @Implementation
    116     public float getDimension(DisplayMetrics metrics)
    117     {
    118         return complexToDimension(typedValue.data, metrics);
    119     }
    120 
    121     @Implementation
    122     public static float complexToFraction(int data, float base, float pbase)
    123     {
    124         switch ((data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK) {
    125         case COMPLEX_UNIT_FRACTION:
    126             return complexToFloat(data) * base;
    127         case COMPLEX_UNIT_FRACTION_PARENT:
    128             return complexToFloat(data) * pbase;
    129         }
    130         return 0;
    131     }
    132 
    133     @Implementation
    134     public float getFraction(float base, float pbase)
    135     {
    136         return complexToFraction(typedValue.data, base, pbase);
    137     }
    138 
    139     @Implementation
    140     public final CharSequence coerceToString()
    141     {
    142         int t = typedValue.type;
    143         if (t == TYPE_STRING) {
    144             return typedValue.string;
    145         }
    146         return coerceToString(t, typedValue.data);
    147     }
    148 
    149     private static final String[] DIMENSION_UNIT_STRS = new String[] {
    150         "px", "dip", "sp", "pt", "in", "mm"
    151     };
    152     private static final String[] FRACTION_UNIT_STRS = new String[] {
    153         "%", "%p"
    154     };
    155 
    156     @Implementation
    157     public static final String coerceToString(int type, int data)
    158     {
    159         switch (type) {
    160         case TYPE_NULL:
    161             return null;
    162         case TYPE_REFERENCE:
    163             return "@" + data;
    164         case TYPE_ATTRIBUTE:
    165             return "?" + data;
    166         case TYPE_FLOAT:
    167             return Float.toString(Float.intBitsToFloat(data));
    168         case TYPE_DIMENSION:
    169             return Float.toString(complexToFloat(data)) + DIMENSION_UNIT_STRS[
    170                 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK];
    171         case TYPE_FRACTION:
    172             return Float.toString(complexToFloat(data)*100) + FRACTION_UNIT_STRS[
    173                 (data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK];
    174         case TYPE_INT_HEX:
    175             return "0x" + Integer.toHexString(data);
    176         case TYPE_INT_BOOLEAN:
    177             return data != 0 ? "true" : "false";
    178         }
    179 
    180         if (type >= TYPE_FIRST_COLOR_INT && type <= TYPE_LAST_COLOR_INT) {
    181             return "#" + Integer.toHexString(data);
    182         } else if (type >= TYPE_FIRST_INT && type <= TYPE_LAST_INT) {
    183             return Integer.toString(data);
    184         }
    185 
    186         return null;
    187     }
    188 
    189     @Implementation
    190     public void setTo(TypedValue other)
    191     {
    192         typedValue.type = other.type;
    193         typedValue.string = other.string;
    194         typedValue.data = other.data;
    195         typedValue.assetCookie = other.assetCookie;
    196         typedValue.resourceId = other.resourceId;
    197         typedValue.density = other.density;
    198     }
    199 
    200     @Implementation
    201     public String toString()
    202     {
    203         StringBuilder sb = new StringBuilder();
    204         sb.append("TypedValue{t=0x").append(Integer.toHexString(typedValue.type));
    205         sb.append("/d=0x").append(Integer.toHexString(typedValue.data));
    206         if (typedValue.type == TYPE_STRING) {
    207             sb.append(" \"").append(typedValue.string != null ? typedValue.string : "<null>").append("\"");
    208         }
    209         if (typedValue.assetCookie != 0) {
    210             sb.append(" a=").append(typedValue.assetCookie);
    211         }
    212         if (typedValue.resourceId != 0) {
    213             sb.append(" r=0x").append(Integer.toHexString(typedValue.resourceId));
    214         }
    215         sb.append("}");
    216         return sb.toString();
    217     }
    218 }
    219