ShadowResources.java revision ec63d3ad017965dc341bd0ce15f07c65f35b4a90
1package com.xtremelabs.robolectric.shadows;
2
3import android.content.res.AssetManager;
4import android.content.res.Configuration;
5import android.content.res.Resources;
6import android.content.res.TypedArray;
7import android.graphics.BitmapFactory;
8import android.graphics.drawable.BitmapDrawable;
9import android.graphics.drawable.Drawable;
10import android.util.AttributeSet;
11import android.util.DisplayMetrics;
12import com.xtremelabs.robolectric.Robolectric;
13import com.xtremelabs.robolectric.internal.Implementation;
14import com.xtremelabs.robolectric.internal.Implements;
15import com.xtremelabs.robolectric.internal.RealObject;
16import com.xtremelabs.robolectric.res.ResourceLoader;
17
18import java.io.InputStream;
19import java.util.Locale;
20
21import static com.xtremelabs.robolectric.Robolectric.newInstanceOf;
22import static com.xtremelabs.robolectric.Robolectric.shadowOf;
23
24/**
25 * Shadow of {@code Resources} that simulates the loading of resources
26 *
27 * @see com.xtremelabs.robolectric.RobolectricTestRunner#RobolectricTestRunner(Class, String, String)
28 */
29@SuppressWarnings({"UnusedDeclaration"})
30@Implements(Resources.class)
31public class ShadowResources {
32    static Resources bind(Resources resources, ResourceLoader resourceLoader) {
33        ShadowResources shadowResources = shadowOf(resources);
34        if (shadowResources.resourceLoader != null) throw new RuntimeException("ResourceLoader already set!");
35        shadowResources.resourceLoader = resourceLoader;
36        return resources;
37    }
38
39    @RealObject Resources realResources;
40    private ResourceLoader resourceLoader;
41
42    @Implementation
43    public int getColor(int id) throws Resources.NotFoundException {
44        return resourceLoader.getColorValue(id);
45    }
46
47    @Implementation
48    public Configuration getConfiguration() {
49        Configuration configuration = new Configuration();
50        configuration.setToDefaults();
51        return configuration;
52    }
53
54    @Implementation
55    public String getString(int id) throws Resources.NotFoundException {
56        return resourceLoader.getStringValue(id);
57    }
58
59    @Implementation
60    public String getString(int id, Object... formatArgs) throws Resources.NotFoundException {
61        String raw = getString(id);
62        return String.format(Locale.ENGLISH, raw, formatArgs);
63    }
64
65    @Implementation
66    public InputStream openRawResource(int id) throws Resources.NotFoundException {
67        return resourceLoader.getRawValue(id);
68    }
69
70    @Implementation
71    public String[] getStringArray(int id) throws Resources.NotFoundException {
72        String[] arrayValue = resourceLoader.getStringArrayValue(id);
73        if (arrayValue == null) {
74            throw new Resources.NotFoundException();
75        }
76        return arrayValue;
77    }
78
79    @Implementation
80    public CharSequence[] getTextArray(int id) throws Resources.NotFoundException {
81        return getStringArray(id);
82    }
83
84    @Implementation
85    public CharSequence getText(int id) throws Resources.NotFoundException {
86        return getString(id);
87    }
88
89    @Implementation
90    public DisplayMetrics getDisplayMetrics() {
91        return new DisplayMetrics();
92    }
93
94    @Implementation
95    public Drawable getDrawable(int drawableResourceId) throws Resources.NotFoundException {
96        return new BitmapDrawable(BitmapFactory.decodeResource(realResources, drawableResourceId));
97    }
98
99    @Implementation
100    public float getDimension(int id) throws Resources.NotFoundException {
101        // todo: get this value from the xml resources and scale it by display metrics [xw 20101011]
102        if (resourceLoader.dimensions.containsKey(id)) {
103            return resourceLoader.dimensions.get(id);
104        }
105        return id - 0x7f000000;
106    }
107
108    @Implementation
109    public int getDimensionPixelSize(int id) throws Resources.NotFoundException {
110        // The int value returned from here is probably going to be handed to TextView.setTextSize(),
111        // which takes a float. Avoid int-to-float conversion errors by returning a value generated from this
112        // resource ID but which isn't too big (resource values in R.java are all greater than 0x7f000000).
113
114        return (int) getDimension(id);
115    }
116
117    @Implementation
118    public int getDimensionPixelOffset(int id) throws Resources.NotFoundException {
119        return (int) getDimension(id);
120    }
121
122    @Implementation
123    public AssetManager getAssets() {
124        return ShadowAssetManager.bind(Robolectric.newInstanceOf(AssetManager.class), resourceLoader);
125    }
126
127    @Implementation
128    public final android.content.res.Resources.Theme newTheme() {
129        return newInstanceOf(Resources.Theme.class);
130    }
131
132    /**
133     * Non-Android accessor that sets the value to be returned by {@link #getDimension(int)}
134     *
135     * @param id    ID to set the dimension for
136     * @param value value to be returned
137     */
138    public void setDimension(int id, int value) {
139        resourceLoader.dimensions.put(id, value);
140    }
141
142    @Implements(Resources.Theme.class)
143    public static class ShadowTheme {
144        @Implementation
145        public TypedArray obtainStyledAttributes(int[] attrs) {
146            return obtainStyledAttributes(0, attrs);
147        }
148
149        @Implementation
150        public TypedArray obtainStyledAttributes(int resid, int[] attrs) throws android.content.res.Resources.NotFoundException {
151            return obtainStyledAttributes(null, attrs, 0, 0);
152        }
153
154        @Implementation
155        public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
156            return newInstanceOf(TypedArray.class);
157        }
158    }
159}
160