MockFontProvider.java revision 60fbdd688327ffb0b0dc48fb0b296c1c87455a8d
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v4.provider;
18
19import android.content.ContentProvider;
20import android.content.ContentUris;
21import android.content.ContentValues;
22import android.content.Context;
23import android.content.res.AssetManager;
24import android.database.Cursor;
25import android.database.MatrixCursor;
26import android.net.Uri;
27import android.os.ParcelFileDescriptor;
28import android.support.v4.provider.FontsContractCompat.Columns;
29
30import java.io.File;
31import java.io.FileNotFoundException;
32import java.io.FileOutputStream;
33import java.io.IOException;
34import java.io.InputStream;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.Map;
38
39/**
40 * Provides a test Content Provider implementing {@link FontsContractCompat}.
41 */
42public class MockFontProvider extends ContentProvider {
43    static final String[] FONT_FILES = {
44            "samplefont.ttf",
45    };
46    private static final int SAMPLE_FONT_FILE_0_ID = 0;
47
48    static final String SINGLE_FONT_FAMILY_QUERY = "singleFontFamily";
49    static final String SINGLE_FONT_FAMILY2_QUERY = "singleFontFamily2";
50    static final String NOT_FOUND_QUERY = "notFound";
51    static final String UNAVAILABLE_QUERY = "unavailable";
52    static final String MALFORMED_QUERY = "malformed";
53    static final String NOT_FOUND_SECOND_QUERY = "notFoundSecond";
54    static final String NOT_FOUND_THIRD_QUERY = "notFoundThird";
55    static final String NEGATIVE_ERROR_CODE_QUERY = "negativeCode";
56    static final String MANDATORY_FIELDS_ONLY_QUERY = "mandatoryFields";
57
58    static class Font {
59        Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
60                int resultCode, boolean returnAllFields) {
61            mId = id;
62            mFileId = fileId;
63            mTtcIndex = ttcIndex;
64            mVarSettings = varSettings;
65            mWeight = weight;
66            mItalic = italic;
67            mResultCode = resultCode;
68            mReturnAllFields = returnAllFields;
69        }
70
71        public int getId() {
72            return mId;
73        }
74
75        public int getTtcIndex() {
76            return mTtcIndex;
77        }
78
79        public String getVarSettings() {
80            return mVarSettings;
81        }
82
83        public int getWeight() {
84            return mWeight;
85        }
86
87        public int getItalic() {
88            return mItalic;
89        }
90
91        public int getResultCode() {
92            return mResultCode;
93        }
94
95        public int getFileId() {
96            return mFileId;
97        }
98
99        public boolean isReturnAllFields() {
100            return mReturnAllFields;
101        }
102
103        private final int mId;
104        private final int mFileId;
105        private final int mTtcIndex;
106        private final String mVarSettings;
107        private final int mWeight;
108        private final int mItalic;
109        private final int mResultCode;
110        private final boolean mReturnAllFields;
111    };
112
113    private static final Map<String, Font[]> QUERY_MAP;
114    static {
115        HashMap<String, Font[]> map = new HashMap<>();
116        int id = 1;
117
118        map.put(SINGLE_FONT_FAMILY_QUERY, new Font[] {
119                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, "'wght' 100", 400, 0,
120                        Columns.RESULT_CODE_OK, true),
121        });
122
123        map.put(SINGLE_FONT_FAMILY2_QUERY, new Font[] {
124                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, "'wght' 100", 700, 1,
125                        Columns.RESULT_CODE_OK, true),
126        });
127
128        map.put(NOT_FOUND_QUERY, new Font[] {
129                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
130        });
131
132        map.put(UNAVAILABLE_QUERY, new Font[] {
133                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_UNAVAILABLE, true),
134        });
135
136        map.put(MALFORMED_QUERY, new Font[] {
137                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_MALFORMED_QUERY, true),
138        });
139
140        map.put(NOT_FOUND_SECOND_QUERY, new Font[] {
141                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK,
142                        true),
143                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
144        });
145
146        map.put(NOT_FOUND_THIRD_QUERY, new Font[] {
147                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK,
148                        true),
149                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
150                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK,
151                        true),
152        });
153
154        map.put(NEGATIVE_ERROR_CODE_QUERY, new Font[] {
155                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, -5, true),
156        });
157
158        map.put(MANDATORY_FIELDS_ONLY_QUERY, new Font[] {
159                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0,
160                        Columns.RESULT_CODE_OK, false),
161        });
162
163        QUERY_MAP = Collections.unmodifiableMap(map);
164    }
165
166    private static Cursor buildCursor(Font[] in) {
167        if (!in[0].mReturnAllFields) {
168            MatrixCursor cursor = new MatrixCursor(new String[] { Columns._ID, Columns.FILE_ID });
169            for (Font font : in) {
170                cursor.addRow(new Object[] { font.getId(), font.getFileId() });
171            }
172            return cursor;
173        }
174        MatrixCursor cursor = new MatrixCursor(new String[] {
175                Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT,
176                Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID});
177        for (Font font : in) {
178            cursor.addRow(
179                    new Object[] { font.getId(), font.getTtcIndex(), font.getVarSettings(),
180                    font.getWeight(), font.getItalic(), font.getResultCode(), font.getFileId() });
181        }
182        return cursor;
183    }
184
185    public static void prepareFontFiles(Context context) {
186        final AssetManager mgr = context.getAssets();
187        for (String file : FONT_FILES) {
188            InputStream is = null;
189            try {
190                is = mgr.open("fonts/" + file);
191                copy(is, getCopiedFile(context, file));
192            } catch (IOException e) {
193                throw new RuntimeException(e);
194            } finally {
195                if (is != null) {
196                    try {
197                        is.close();
198                    } catch (IOException e) {
199                        // Do nothing.
200                    }
201                }
202            }
203        }
204    }
205
206    /**
207     * The caller is responsible for closing the given InputStream.
208     */
209    private static void copy(InputStream is, File file) throws IOException {
210        FileOutputStream fos = null;
211        try {
212            fos = new FileOutputStream(file, false);
213            byte[] buffer = new byte[1024];
214            int readLen;
215            while ((readLen = is.read(buffer)) != -1) {
216                fos.write(buffer, 0, readLen);
217            }
218        } finally {
219            if (fos != null) {
220                fos.close();
221            }
222        }
223    }
224
225    public static void cleanUpFontFiles(Context context) {
226        for (String file : FONT_FILES) {
227            getCopiedFile(context, file).delete();
228        }
229    }
230
231    public static File getCopiedFile(Context context, String path) {
232        return new File(context.getFilesDir(), path);
233    }
234
235    @Override
236    public ParcelFileDescriptor openFile(Uri uri, String mode) {
237        final int id = (int) ContentUris.parseId(uri);
238        final File targetFile = getCopiedFile(getContext(), FONT_FILES[id]);
239        try {
240            return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
241        } catch (FileNotFoundException e) {
242            throw new RuntimeException(
243                    "Failed to found font file. You might forget call prepareFontFiles in setUp");
244        }
245    }
246
247    @Override
248    public boolean onCreate() {
249        return true;
250    }
251
252    @Override
253    public String getType(Uri uri) {
254        return "vnd.android.cursor.dir/vnd.android.provider.font";
255    }
256
257    @Override
258    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
259            String sortOrder) {
260        return buildCursor(QUERY_MAP.get(selectionArgs[0]));
261    }
262
263    @Override
264    public Uri insert(Uri uri, ContentValues values) {
265        throw new UnsupportedOperationException("insert is not supported.");
266    }
267
268    @Override
269    public int delete(Uri uri, String selection, String[] selectionArgs) {
270        throw new UnsupportedOperationException("delete is not supported.");
271    }
272
273    @Override
274    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
275        throw new UnsupportedOperationException("update is not supported.");
276    }
277}
278