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