MockFontProvider.java revision 2c4cbf16a9705a4fcb22a8de5cd8795745b01aa4
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", "large_a.ttf", "large_b.ttf", "large_c.ttf", "large_d.ttf"
45    };
46    private static final int SAMPLE_FONT_FILE_0_ID = 0;
47    private static final int LARGE_A_FILE_ID = 1;
48    private static final int LARGE_B_FILE_ID = 2;
49    private static final int LARGE_C_FILE_ID = 3;
50    private static final int LARGE_D_FILE_ID = 4;
51
52    static final String SINGLE_FONT_FAMILY_QUERY = "singleFontFamily";
53    static final String SINGLE_FONT_FAMILY2_QUERY = "singleFontFamily2";
54    static final String NOT_FOUND_QUERY = "notFound";
55    static final String UNAVAILABLE_QUERY = "unavailable";
56    static final String MALFORMED_QUERY = "malformed";
57    static final String NOT_FOUND_SECOND_QUERY = "notFoundSecond";
58    static final String NOT_FOUND_THIRD_QUERY = "notFoundThird";
59    static final String NEGATIVE_ERROR_CODE_QUERY = "negativeCode";
60    static final String MANDATORY_FIELDS_ONLY_QUERY = "mandatoryFields";
61    static final String STYLE_TEST_QUERY = "styleTest";
62
63    static class Font {
64        Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
65                int resultCode, boolean returnAllFields) {
66            mId = id;
67            mFileId = fileId;
68            mTtcIndex = ttcIndex;
69            mVarSettings = varSettings;
70            mWeight = weight;
71            mItalic = italic;
72            mResultCode = resultCode;
73            mReturnAllFields = returnAllFields;
74        }
75
76        public int getId() {
77            return mId;
78        }
79
80        public int getTtcIndex() {
81            return mTtcIndex;
82        }
83
84        public String getVarSettings() {
85            return mVarSettings;
86        }
87
88        public int getWeight() {
89            return mWeight;
90        }
91
92        public int getItalic() {
93            return mItalic;
94        }
95
96        public int getResultCode() {
97            return mResultCode;
98        }
99
100        public int getFileId() {
101            return mFileId;
102        }
103
104        public boolean isReturnAllFields() {
105            return mReturnAllFields;
106        }
107
108        private final int mId;
109        private final int mFileId;
110        private final int mTtcIndex;
111        private final String mVarSettings;
112        private final int mWeight;
113        private final int mItalic;
114        private final int mResultCode;
115        private final boolean mReturnAllFields;
116    };
117
118    private static final Map<String, Font[]> QUERY_MAP;
119    static {
120        HashMap<String, Font[]> map = new HashMap<>();
121        int id = 1;
122
123        map.put(SINGLE_FONT_FAMILY_QUERY, new Font[] {
124                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, "'wght' 100", 400, 0,
125                        Columns.RESULT_CODE_OK, true),
126        });
127
128        map.put(SINGLE_FONT_FAMILY2_QUERY, new Font[] {
129                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, "'wght' 100", 700, 1,
130                        Columns.RESULT_CODE_OK, true),
131        });
132
133        map.put(NOT_FOUND_QUERY, new Font[] {
134                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
135        });
136
137        map.put(UNAVAILABLE_QUERY, new Font[] {
138                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_UNAVAILABLE, true),
139        });
140
141        map.put(MALFORMED_QUERY, new Font[] {
142                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_MALFORMED_QUERY, true),
143        });
144
145        map.put(NOT_FOUND_SECOND_QUERY, new Font[] {
146                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK,
147                        true),
148                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
149        });
150
151        map.put(NOT_FOUND_THIRD_QUERY, new Font[] {
152                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK,
153                        true),
154                new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
155                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK,
156                        true),
157        });
158
159        map.put(NEGATIVE_ERROR_CODE_QUERY, new Font[] {
160                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, -5, true),
161        });
162
163        map.put(MANDATORY_FIELDS_ONLY_QUERY, new Font[] {
164                new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0,
165                        Columns.RESULT_CODE_OK, false),
166        });
167
168        map.put(STYLE_TEST_QUERY, new Font[] {
169                new Font(id++, LARGE_A_FILE_ID, 0, null, 400, 0 /* normal */,
170                        Columns.RESULT_CODE_OK, true),
171                new Font(id++, LARGE_B_FILE_ID, 0, null, 400, 1 /* italic */,
172                        Columns.RESULT_CODE_OK, true),
173                new Font(id++, LARGE_C_FILE_ID, 0, null, 700, 0 /* normal */,
174                        Columns.RESULT_CODE_OK, true),
175                new Font(id++, LARGE_D_FILE_ID, 0, null, 700, 1 /* italic */,
176                        Columns.RESULT_CODE_OK, true),
177        });
178
179        QUERY_MAP = Collections.unmodifiableMap(map);
180    }
181
182    private static Cursor buildCursor(Font[] in) {
183        if (!in[0].mReturnAllFields) {
184            MatrixCursor cursor = new MatrixCursor(new String[] { Columns._ID, Columns.FILE_ID });
185            for (Font font : in) {
186                cursor.addRow(new Object[] { font.getId(), font.getFileId() });
187            }
188            return cursor;
189        }
190        MatrixCursor cursor = new MatrixCursor(new String[] {
191                Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT,
192                Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID});
193        for (Font font : in) {
194            cursor.addRow(
195                    new Object[] { font.getId(), font.getTtcIndex(), font.getVarSettings(),
196                    font.getWeight(), font.getItalic(), font.getResultCode(), font.getFileId() });
197        }
198        return cursor;
199    }
200
201    public static void prepareFontFiles(Context context) {
202        final AssetManager mgr = context.getAssets();
203        for (String file : FONT_FILES) {
204            InputStream is = null;
205            try {
206                is = mgr.open("fonts/" + file);
207                copy(is, getCopiedFile(context, file));
208            } catch (IOException e) {
209                throw new RuntimeException(e);
210            } finally {
211                if (is != null) {
212                    try {
213                        is.close();
214                    } catch (IOException e) {
215                        // Do nothing.
216                    }
217                }
218            }
219        }
220    }
221
222    /**
223     * The caller is responsible for closing the given InputStream.
224     */
225    private static void copy(InputStream is, File file) throws IOException {
226        FileOutputStream fos = null;
227        try {
228            fos = new FileOutputStream(file, false);
229            byte[] buffer = new byte[1024];
230            int readLen;
231            while ((readLen = is.read(buffer)) != -1) {
232                fos.write(buffer, 0, readLen);
233            }
234        } finally {
235            if (fos != null) {
236                fos.close();
237            }
238        }
239    }
240
241    public static void cleanUpFontFiles(Context context) {
242        for (String file : FONT_FILES) {
243            getCopiedFile(context, file).delete();
244        }
245    }
246
247    public static File getCopiedFile(Context context, String path) {
248        return new File(context.getFilesDir(), path);
249    }
250
251    @Override
252    public ParcelFileDescriptor openFile(Uri uri, String mode) {
253        final int id = (int) ContentUris.parseId(uri);
254        final File targetFile = getCopiedFile(getContext(), FONT_FILES[id]);
255        try {
256            return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
257        } catch (FileNotFoundException e) {
258            throw new RuntimeException(
259                    "Failed to found font file. You might forget call prepareFontFiles in setUp");
260        }
261    }
262
263    @Override
264    public boolean onCreate() {
265        return true;
266    }
267
268    @Override
269    public String getType(Uri uri) {
270        return "vnd.android.cursor.dir/vnd.android.provider.font";
271    }
272
273    @Override
274    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
275            String sortOrder) {
276        return buildCursor(QUERY_MAP.get(selectionArgs[0]));
277    }
278
279    @Override
280    public Uri insert(Uri uri, ContentValues values) {
281        throw new UnsupportedOperationException("insert is not supported.");
282    }
283
284    @Override
285    public int delete(Uri uri, String selection, String[] selectionArgs) {
286        throw new UnsupportedOperationException("delete is not supported.");
287    }
288
289    @Override
290    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
291        throw new UnsupportedOperationException("update is not supported.");
292    }
293}
294