1package com.xtremelabs.robolectric.shadows;
2
3import android.app.Application;
4import android.content.Context;
5import android.content.res.Resources;
6import android.content.res.TypedArray;
7import android.util.AttributeSet;
8import com.xtremelabs.robolectric.internal.Implementation;
9import com.xtremelabs.robolectric.internal.Implements;
10import com.xtremelabs.robolectric.internal.RealObject;
11import com.xtremelabs.robolectric.res.ResourceLoader;
12
13import java.io.File;
14import java.io.FileInputStream;
15import java.io.FileNotFoundException;
16import java.io.FileOutputStream;
17import java.io.IOException;
18
19import static com.xtremelabs.robolectric.Robolectric.shadowOf;
20
21/**
22 * Calls through to the {@code resourceLoader} to actually load resources.
23 */
24@SuppressWarnings({"UnusedDeclaration"})
25@Implements(Context.class)
26abstract public class ShadowContext {
27    public static final File CACHE_DIR = createTempDir("android-cache");
28    public static final File EXTERNAL_CACHE_DIR = createTempDir("android-external-cache");
29    public static final File FILES_DIR = createTempDir("android-tmp");
30    public static final File EXTERNAL_FILES_DIR = createTempDir("android-external-files");
31
32    @RealObject private Context realContext;
33
34    @Implementation
35    public File getDir(String name, int mode) {
36        // TODO: honor operating mode.
37        File file = new File(FILES_DIR, name);
38        if (!file.exists()) {
39            file.mkdir();
40        }
41        return file;
42    }
43
44    @Implementation
45    public String getString(int resId) {
46        return realContext.getResources().getString(resId);
47    }
48
49    @Implementation
50    public CharSequence getText(int resId) {
51        return realContext.getResources().getText(resId);
52    }
53
54    @Implementation
55    public String getString(int resId, Object... formatArgs) {
56        return realContext.getResources().getString(resId, formatArgs);
57    }
58
59    @Implementation
60    abstract public Resources.Theme getTheme();
61
62    @Implementation
63    public final TypedArray obtainStyledAttributes(
64            int[] attrs) {
65        return getTheme().obtainStyledAttributes(attrs);
66    }
67
68    @Implementation
69    public final TypedArray obtainStyledAttributes(
70            int resid, int[] attrs) throws Resources.NotFoundException {
71        return getTheme().obtainStyledAttributes(resid, attrs);
72    }
73
74    @Implementation
75    public final TypedArray obtainStyledAttributes(
76            AttributeSet set, int[] attrs) {
77        return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
78    }
79
80    @Implementation
81    public final TypedArray obtainStyledAttributes(
82            AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
83        return getTheme().obtainStyledAttributes(
84            set, attrs, defStyleAttr, defStyleRes);
85    }
86
87    @Implementation
88    public File getCacheDir() {
89        CACHE_DIR.mkdirs();
90        return CACHE_DIR;
91    }
92
93    @Implementation
94    public File getFilesDir() {
95        FILES_DIR.mkdirs();
96        return FILES_DIR;
97    }
98
99    @Implementation
100    public File getExternalCacheDir() {
101        EXTERNAL_CACHE_DIR.mkdir();
102        return EXTERNAL_CACHE_DIR;
103    }
104
105    @Implementation
106    public File getExternalFilesDir(String type) {
107    	File f = (type == null) ? EXTERNAL_FILES_DIR : new File( EXTERNAL_FILES_DIR, type );
108        f.mkdirs();
109        return f;
110    }
111
112    @Implementation
113    public FileInputStream openFileInput(String path) throws FileNotFoundException {
114        return new FileInputStream(getFileStreamPath(path));
115    }
116
117    @Implementation
118    public FileOutputStream openFileOutput(String path, int mode) throws FileNotFoundException {
119        return new FileOutputStream(getFileStreamPath(path));
120    }
121
122    @Implementation
123    public File getFileStreamPath(String name) {
124        if (name.contains(File.separator)) {
125            throw new IllegalArgumentException("File " + name + " contains a path separator");
126        }
127        return new File(getFilesDir(), name);
128    }
129
130    @Implementation
131    public boolean deleteFile(String name) {
132        return getFileStreamPath(name).delete();
133    }
134
135    /**
136     * Non-Android accessor.
137     *
138     * @return the {@code ResourceLoader} associated with this {@code Context}
139     */
140    public ResourceLoader getResourceLoader() {
141        return shadowOf((Application) realContext.getApplicationContext()).getResourceLoader();
142    }
143
144    public static void clearFilesAndCache() {
145        clearFiles(FILES_DIR);
146        clearFiles(CACHE_DIR);
147        clearFiles(EXTERNAL_CACHE_DIR);
148        clearFiles(EXTERNAL_FILES_DIR);
149    }
150
151    public static void clearFiles(File dir) {
152        if (dir != null && dir.isDirectory()) {
153            File[] files = dir.listFiles();
154            if (files != null) {
155                for (File f : files) {
156                    if (f.isDirectory()) {
157                        clearFiles(f);
158                    }
159                    f.delete();
160                }
161            }
162        }
163    }
164
165    private static File createTempDir(String name) {
166        try {
167            File tmp = File.createTempFile(name, "robolectric");
168            if (!tmp.delete()) throw new IOException("could not delete "+tmp);
169            if (!tmp.mkdirs()) throw new IOException("could not create "+tmp);
170            tmp.deleteOnExit();
171
172            return tmp;
173        } catch (IOException e) {
174            throw new RuntimeException(e);
175        }
176    }
177}
178