1package com.xtremelabs.robolectric.shadows;
2
3import android.content.res.Resources;
4import android.graphics.Bitmap;
5import android.graphics.BitmapFactory;
6import android.graphics.Point;
7import android.graphics.Rect;
8import android.net.Uri;
9import com.xtremelabs.robolectric.Robolectric;
10import com.xtremelabs.robolectric.internal.Implementation;
11import com.xtremelabs.robolectric.internal.Implements;
12import com.xtremelabs.robolectric.util.Join;
13
14import java.io.InputStream;
15import java.util.ArrayList;
16import java.util.HashMap;
17import java.util.List;
18import java.util.Map;
19
20import static com.xtremelabs.robolectric.Robolectric.shadowOf;
21
22@SuppressWarnings({"UnusedDeclaration"})
23@Implements(BitmapFactory.class)
24public class ShadowBitmapFactory {
25    private static Map<String, Point> widthAndHeightMap = new HashMap<String, Point>();
26
27    @Implementation
28    public static Bitmap decodeResource(Resources res, int id) {
29        Bitmap bitmap = create("resource:" + getResourceName(id));
30        shadowOf(bitmap).setLoadedFromResourceId(id);
31        return bitmap;
32    }
33
34    @Implementation
35    public static Bitmap decodeResource(Resources res, int id, BitmapFactory.Options options) {
36        Bitmap bitmap = create("resource:" + getResourceName(id), options);
37        shadowOf(bitmap).setLoadedFromResourceId(id);
38        return bitmap;
39    }
40
41    private static String getResourceName(int id) {
42        return shadowOf(Robolectric.application).getResourceLoader().getNameForId(id);
43    }
44
45    @Implementation
46    public static Bitmap decodeFile(String pathName) {
47        return create("file:" + pathName);
48    }
49
50    @Implementation
51    public static Bitmap decodeFile(String pathName, BitmapFactory.Options options) {
52        return create("file:" + pathName, options);
53    }
54
55    @Implementation
56    public static Bitmap decodeStream(InputStream is) {
57        return decodeStream(is, null, new BitmapFactory.Options());
58    }
59
60    @Implementation
61    public static Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts) {
62        return create(is.toString().replaceFirst("stream for ", ""), opts);
63    }
64
65    static Bitmap create(String name) {
66        return create(name, new BitmapFactory.Options());
67    }
68
69    public static Bitmap create(String name, BitmapFactory.Options options) {
70        Bitmap bitmap = Robolectric.newInstanceOf(Bitmap.class);
71        ShadowBitmap shadowBitmap = shadowOf(bitmap);
72        shadowBitmap.appendDescription("Bitmap for " + name);
73
74        String optionsString = stringify(options);
75        if (optionsString.length() > 0) {
76            shadowBitmap.appendDescription(" with options ");
77            shadowBitmap.appendDescription(optionsString);
78        }
79
80        Point widthAndHeight = widthAndHeightMap.get(name);
81        if (widthAndHeight == null) {
82            widthAndHeight = new Point(100, 100);
83        }
84
85        shadowBitmap.setWidth(widthAndHeight.x);
86        shadowBitmap.setHeight(widthAndHeight.y);
87        options.outWidth = widthAndHeight.x;
88        options.outHeight = widthAndHeight.y;
89        return bitmap;
90    }
91
92    public static void provideWidthAndHeightHints(Uri uri, int width, int height) {
93        widthAndHeightMap.put(uri.toString(), new Point(width, height));
94    }
95
96    public static void provideWidthAndHeightHints(int resourceId, int width, int height) {
97        widthAndHeightMap.put("resource:" + getResourceName(resourceId), new Point(width, height));
98    }
99
100    public static void provideWidthAndHeightHints(String file, int width, int height) {
101        widthAndHeightMap.put("file:" + file, new Point(width, height));
102    }
103
104    private static String stringify(BitmapFactory.Options options) {
105        List<String> opts = new ArrayList<String>();
106
107        if (options.inJustDecodeBounds) opts.add("inJustDecodeBounds");
108        if (options.inSampleSize > 1) opts.add("inSampleSize=" + options.inSampleSize);
109
110        return Join.join(", ", opts);
111    }
112
113    public static void reset() {
114        widthAndHeightMap.clear();
115    }
116}
117