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