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