1 package com.xtremelabs.robolectric.shadows; 2 3 import android.content.res.AssetManager; 4 import android.content.res.Configuration; 5 import android.content.res.Resources; 6 import android.content.res.TypedArray; 7 import android.graphics.BitmapFactory; 8 import android.graphics.drawable.BitmapDrawable; 9 import android.graphics.drawable.Drawable; 10 import android.graphics.drawable.NinePatchDrawable; 11 import android.util.AttributeSet; 12 import android.util.DisplayMetrics; 13 import android.util.TypedValue; 14 import android.view.Display; 15 import com.xtremelabs.robolectric.Robolectric; 16 import com.xtremelabs.robolectric.internal.Implementation; 17 import com.xtremelabs.robolectric.internal.Implements; 18 import com.xtremelabs.robolectric.internal.RealObject; 19 import com.xtremelabs.robolectric.res.ResourceExtractor; 20 import com.xtremelabs.robolectric.res.ResourceLoader; 21 22 import java.io.InputStream; 23 import java.util.HashMap; 24 import java.util.Locale; 25 26 import static com.xtremelabs.robolectric.Robolectric.newInstanceOf; 27 import static com.xtremelabs.robolectric.Robolectric.shadowOf; 28 29 /** 30 * Shadow of {@code Resources} that simulates the loading of resources 31 * 32 * @see com.xtremelabs.robolectric.RobolectricTestRunner#RobolectricTestRunner(Class, String, String) 33 */ 34 @SuppressWarnings({"UnusedDeclaration"}) 35 @Implements(Resources.class) 36 public class ShadowResources { 37 private float density = 1.0f; 38 Configuration configuration = null; 39 private DisplayMetrics displayMetrics; 40 private Display display; 41 bind(Resources resources, ResourceLoader resourceLoader)42 static Resources bind(Resources resources, ResourceLoader resourceLoader) { 43 ShadowResources shadowResources = shadowOf(resources); 44 if (shadowResources.resourceLoader != null) throw new RuntimeException("ResourceLoader already set!"); 45 shadowResources.resourceLoader = resourceLoader; 46 return resources; 47 } 48 49 @RealObject 50 Resources realResources; 51 private ResourceLoader resourceLoader; 52 53 @Implementation getIdentifier(String name, String defType, String defPackage)54 public int getIdentifier(String name, String defType, String defPackage) { 55 Integer index = 0; 56 57 ResourceExtractor resourceExtractor = resourceLoader.getResourceExtractor(); 58 59 index = resourceExtractor.getResourceId(defType + "/" + name); 60 if (index == null) { 61 return 0; 62 } 63 return index; 64 } 65 66 @Implementation getColor(int id)67 public int getColor(int id) throws Resources.NotFoundException { 68 return resourceLoader.getColorValue(id); 69 } 70 71 @Implementation getConfiguration()72 public Configuration getConfiguration() { 73 if (configuration == null) { 74 configuration = new Configuration(); 75 configuration.setToDefaults(); 76 } 77 if (configuration.locale == null) { 78 configuration.locale = Locale.getDefault(); 79 } 80 return configuration; 81 } 82 83 @Implementation getString(int id)84 public String getString(int id) throws Resources.NotFoundException { 85 return resourceLoader.getStringValue(id); 86 } 87 88 @Implementation getString(int id, Object... formatArgs)89 public String getString(int id, Object... formatArgs) throws Resources.NotFoundException { 90 String raw = getString(id); 91 return String.format(Locale.ENGLISH, raw, formatArgs); 92 } 93 94 @Implementation getQuantityString(int id, int quantity, Object... formatArgs)95 public String getQuantityString(int id, int quantity, Object... formatArgs) throws Resources.NotFoundException { 96 String raw = getQuantityString(id, quantity); 97 return String.format(Locale.ENGLISH, raw, formatArgs); 98 } 99 100 @Implementation getQuantityString(int id, int quantity)101 public String getQuantityString(int id, int quantity) throws Resources.NotFoundException { 102 return resourceLoader.getPluralStringValue(id, quantity); 103 } 104 105 @Implementation openRawResource(int id)106 public InputStream openRawResource(int id) throws Resources.NotFoundException { 107 return resourceLoader.getRawValue(id); 108 } 109 110 @Implementation getStringArray(int id)111 public String[] getStringArray(int id) throws Resources.NotFoundException { 112 String[] arrayValue = resourceLoader.getStringArrayValue(id); 113 if (arrayValue == null) { 114 throw new Resources.NotFoundException(); 115 } 116 return arrayValue; 117 } 118 119 @Implementation getTextArray(int id)120 public CharSequence[] getTextArray(int id) throws Resources.NotFoundException { 121 return getStringArray(id); 122 } 123 124 @Implementation getText(int id)125 public CharSequence getText(int id) throws Resources.NotFoundException { 126 return getString(id); 127 } 128 setDensity(float density)129 public void setDensity(float density) { 130 this.density = density; 131 } 132 setDisplay(Display display)133 public void setDisplay(Display display) { 134 this.display = display; 135 displayMetrics = null; 136 } 137 138 @Implementation getDisplayMetrics()139 public DisplayMetrics getDisplayMetrics() { 140 if (displayMetrics == null) { 141 if (display == null) { 142 display = Robolectric.newInstanceOf(Display.class); 143 } 144 145 displayMetrics = new DisplayMetrics(); 146 display.getMetrics(displayMetrics); 147 } 148 displayMetrics.density = this.density; 149 return displayMetrics; 150 } 151 152 @Implementation getDrawable(int drawableResourceId)153 public Drawable getDrawable(int drawableResourceId) throws Resources.NotFoundException { 154 155 ResourceLoader resLoader = Robolectric.shadowOf(Robolectric.application).getResourceLoader(); 156 157 Drawable xmlDrawable = resLoader.getXmlDrawable(drawableResourceId); 158 if (xmlDrawable != null) { 159 return xmlDrawable; 160 } 161 162 Drawable animDrawable = resLoader.getAnimDrawable(drawableResourceId); 163 if (animDrawable != null) { 164 return animDrawable; 165 } 166 167 Drawable colorDrawable = resLoader.getColorDrawable(drawableResourceId); 168 if (colorDrawable != null) { 169 return colorDrawable; 170 } 171 172 if (resLoader.isNinePatchDrawable(drawableResourceId)) { 173 return new NinePatchDrawable(realResources, null); 174 } 175 176 return new BitmapDrawable(realResources, BitmapFactory.decodeResource(realResources, drawableResourceId)); 177 } 178 179 @Implementation getDimension(int id)180 public float getDimension(int id) throws Resources.NotFoundException { 181 return resourceLoader.getDimenValue(id); 182 } 183 184 @Implementation getInteger(int id)185 public int getInteger(int id) throws Resources.NotFoundException { 186 return resourceLoader.getIntegerValue( id ); 187 } 188 189 @Implementation getDimensionPixelSize(int id)190 public int getDimensionPixelSize(int id) throws Resources.NotFoundException { 191 // The int value returned from here is probably going to be handed to TextView.setTextSize(), 192 // which takes a float. Avoid int-to-float conversion errors by returning a value generated from this 193 // resource ID but which isn't too big (resource values in R.java are all greater than 0x7f000000). 194 195 return (int) getDimension(id); 196 } 197 198 @Implementation getDimensionPixelOffset(int id)199 public int getDimensionPixelOffset(int id) throws Resources.NotFoundException { 200 return (int) getDimension(id); 201 } 202 203 @Implementation getAssets()204 public AssetManager getAssets() { 205 return ShadowAssetManager.bind(Robolectric.newInstanceOf(AssetManager.class), resourceLoader); 206 } 207 208 @Implementation newTheme()209 public final android.content.res.Resources.Theme newTheme() { 210 return newInstanceOf(Resources.Theme.class); 211 } 212 213 @Implements(Resources.Theme.class) 214 public static class ShadowTheme { 215 HashMap<Integer, TypedValue> attrMap = new HashMap<Integer, TypedValue>(); 216 217 @Implementation obtainStyledAttributes(int[] attrs)218 public TypedArray obtainStyledAttributes(int[] attrs) { 219 return obtainStyledAttributes(0, attrs); 220 } 221 222 @Implementation obtainStyledAttributes(int resid, int[] attrs)223 public TypedArray obtainStyledAttributes(int resid, int[] attrs) throws android.content.res.Resources.NotFoundException { 224 return obtainStyledAttributes(null, attrs, 0, 0); 225 } 226 227 @Implementation obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)228 public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) { 229 return newInstanceOf(TypedArray.class); 230 } 231 232 @Implementation resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs)233 public boolean resolveAttribute (int resid, TypedValue outValue, boolean resolveRefs) { 234 TypedValue foundValue = attrMap.get(resid); 235 if (foundValue != null) { 236 outValue.setTo(foundValue); 237 return true; 238 } 239 return false; 240 } 241 setAttribue(int attrId, TypedValue value)242 public void setAttribue(int attrId, TypedValue value) { 243 attrMap.put(attrId, value); 244 } 245 } 246 } 247