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 getFloat()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 complexToFloat(int complex)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 complexToDimension(int data, DisplayMetrics metrics)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 complexToDimensionPixelOffset(int data, DisplayMetrics metrics)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 complexToDimensionPixelSize(int data, DisplayMetrics metrics)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 complexToDimensionNoisy(int data, DisplayMetrics metrics)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 applyDimension(int unit, float value, DisplayMetrics metrics)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 getDimension(DisplayMetrics metrics)116 public float getDimension(DisplayMetrics metrics) 117 { 118 return complexToDimension(typedValue.data, metrics); 119 } 120 121 @Implementation complexToFraction(int data, float base, float pbase)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 getFraction(float base, float pbase)134 public float getFraction(float base, float pbase) 135 { 136 return complexToFraction(typedValue.data, base, pbase); 137 } 138 139 @Implementation coerceToString()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 coerceToString(int type, int data)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 setTo(TypedValue other)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 toString()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