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 package android.provider.cts; 17 18 import static android.provider.FontsContract.Columns; 19 20 import android.content.ContentProvider; 21 import android.content.ContentUris; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.content.res.AssetManager; 25 import android.database.Cursor; 26 import android.database.MatrixCursor; 27 import android.net.Uri; 28 import android.os.ParcelFileDescriptor; 29 30 import java.io.File; 31 import java.io.FileNotFoundException; 32 import java.io.FileOutputStream; 33 import java.io.IOException; 34 import java.io.InputStream; 35 import java.nio.file.Files; 36 import java.nio.file.StandardCopyOption; 37 import java.util.Collections; 38 import java.util.HashMap; 39 import java.util.Map; 40 41 public class MockFontProvider extends ContentProvider { 42 final static String AUTHORITY = "android.provider.fonts.cts.font"; 43 44 final static String[] FONT_FILES = { 45 "samplefont1.ttf", "samplefont2.ttf", "samplefont.ttc", 46 }; 47 private static final int SAMPLE_FONT_FILE_0_ID = 0; 48 private static final int SAMPLE_FONT_FILE_1_ID = 1; 49 private static final int SAMPLE_TTC_FONT_FILE_ID = 2; 50 51 static final String SINGLE_FONT_FAMILY_QUERY = "singleFontFamily"; 52 static final String ALL_ATTRIBUTE_VALUES_QUERY = "allAttributeValues"; 53 static final String MULTIPLE_FAMILY_QUERY = "multipleFontFamily"; 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 62 static class Font { Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic, int resultCode, boolean returnAllFields)63 public Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic, 64 int resultCode, boolean returnAllFields) { 65 mId = id; 66 mFileId = fileId; 67 mTtcIndex = ttcIndex; 68 mVarSettings = varSettings; 69 mWeight = weight; 70 mItalic = italic; 71 mResultCode = resultCode; 72 mReturnAllFields = returnAllFields; 73 } 74 getId()75 public int getId() { 76 return mId; 77 } 78 getTtcIndex()79 public int getTtcIndex() { 80 return mTtcIndex; 81 } 82 getVarSettings()83 public String getVarSettings() { 84 return mVarSettings; 85 } 86 getWeight()87 public int getWeight() { 88 return mWeight; 89 } 90 getItalic()91 public int getItalic() { 92 return mItalic; 93 } 94 getResultCode()95 public int getResultCode() { 96 return mResultCode; 97 } 98 getFileId()99 public int getFileId() { 100 return mFileId; 101 } 102 isReturnAllFields()103 public boolean isReturnAllFields() { 104 return mReturnAllFields; 105 } 106 107 private int mId; 108 private int mFileId; 109 private int mTtcIndex; 110 private String mVarSettings; 111 private int mWeight; 112 private int mItalic; 113 private int mResultCode; 114 private final boolean mReturnAllFields; 115 }; 116 117 private static Map<String, Font[]> QUERY_MAP; 118 static { 119 HashMap<String, Font[]> map = new HashMap<>(); 120 int id = 0; 121 map.put(SINGLE_FONT_FAMILY_QUERY, new Font[] { new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, true), })122 map.put(SINGLE_FONT_FAMILY_QUERY, new Font[] { 123 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, true), 124 }); 125 map.put(MULTIPLE_FAMILY_QUERY, new Font[] { new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, true), new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 1, Columns.RESULT_CODE_OK, true), new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, true), new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK, true), })126 map.put(MULTIPLE_FAMILY_QUERY, new Font[] { 127 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, true), 128 new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 1, Columns.RESULT_CODE_OK, true), 129 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, true), 130 new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK, true), 131 }); 132 map.put(ALL_ATTRIBUTE_VALUES_QUERY, new Font[] { new Font(id++, SAMPLE_TTC_FONT_FILE_ID, 0, "'wght' 100", 400, 0, Columns.RESULT_CODE_OK, true), new Font(id++, SAMPLE_TTC_FONT_FILE_ID, 1, "'wght' 100", 700, 1, Columns.RESULT_CODE_OK, true), })133 map.put(ALL_ATTRIBUTE_VALUES_QUERY, new Font[] { 134 new Font(id++, SAMPLE_TTC_FONT_FILE_ID, 0, "'wght' 100", 400, 0, 135 Columns.RESULT_CODE_OK, true), 136 new Font(id++, SAMPLE_TTC_FONT_FILE_ID, 1, "'wght' 100", 700, 1, 137 Columns.RESULT_CODE_OK, true), 138 }); 139 map.put(NOT_FOUND_QUERY, new Font[] { new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true), })140 map.put(NOT_FOUND_QUERY, new Font[] { 141 new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true), 142 }); 143 map.put(UNAVAILABLE_QUERY, new Font[] { new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_UNAVAILABLE, true), })144 map.put(UNAVAILABLE_QUERY, new Font[] { 145 new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_UNAVAILABLE, true), 146 }); 147 map.put(MALFORMED_QUERY, new Font[] { new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_MALFORMED_QUERY, true), })148 map.put(MALFORMED_QUERY, new Font[] { 149 new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_MALFORMED_QUERY, true), 150 }); 151 map.put(NOT_FOUND_SECOND_QUERY, new Font[] { new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, true), new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true), })152 map.put(NOT_FOUND_SECOND_QUERY, new Font[] { 153 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, 154 true), 155 new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true), 156 }); 157 map.put(NOT_FOUND_THIRD_QUERY, new Font[] { new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, true), new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true), new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, true), })158 map.put(NOT_FOUND_THIRD_QUERY, new Font[] { 159 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, 160 true), 161 new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true), 162 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK, 163 true), 164 }); 165 map.put(NEGATIVE_ERROR_CODE_QUERY, new Font[] { new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, -5, true), })166 map.put(NEGATIVE_ERROR_CODE_QUERY, new Font[] { 167 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, -5, true), 168 }); 169 map.put(MANDATORY_FIELDS_ONLY_QUERY, new Font[] { new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK, false), })170 map.put(MANDATORY_FIELDS_ONLY_QUERY, new Font[] { 171 new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, 172 Columns.RESULT_CODE_OK, false), 173 }); 174 175 176 QUERY_MAP = Collections.unmodifiableMap(map); 177 } 178 buildCursor(Font[] in)179 private static Cursor buildCursor(Font[] in) { 180 if (!in[0].mReturnAllFields) { 181 MatrixCursor cursor = new MatrixCursor(new String[] { Columns._ID, Columns.FILE_ID }); 182 for (Font font : in) { 183 MatrixCursor.RowBuilder builder = cursor.newRow(); 184 builder.add(Columns._ID, font.getId()); 185 builder.add(Columns.FILE_ID, font.getFileId()); 186 } 187 return cursor; 188 } 189 MatrixCursor cursor = new MatrixCursor(new String[] { 190 Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT, 191 Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID}); 192 for (Font font : in) { 193 MatrixCursor.RowBuilder builder = cursor.newRow(); 194 builder.add(Columns._ID, font.getId()); 195 builder.add(Columns.FILE_ID, font.getFileId()); 196 builder.add(Columns.TTC_INDEX, font.getTtcIndex()); 197 builder.add(Columns.VARIATION_SETTINGS, font.getVarSettings()); 198 builder.add(Columns.WEIGHT, font.getWeight()); 199 builder.add(Columns.ITALIC, font.getItalic()); 200 builder.add(Columns.RESULT_CODE, font.getResultCode()); 201 } 202 return cursor; 203 } 204 prepareFontFiles(Context context)205 public static void prepareFontFiles(Context context) { 206 final AssetManager mgr = context.getAssets(); 207 for (String path : FONT_FILES) { 208 try (InputStream is = mgr.open(path)) { 209 Files.copy(is, getCopiedFile(context, path).toPath(), 210 StandardCopyOption.REPLACE_EXISTING); 211 } catch (IOException e) { 212 throw new RuntimeException(e); 213 } 214 } 215 } 216 cleanUpFontFiles(Context context)217 public static void cleanUpFontFiles(Context context) { 218 for (String file : FONT_FILES) { 219 getCopiedFile(context, file).delete(); 220 } 221 } 222 getCopiedFile(Context context, String path)223 public static File getCopiedFile(Context context, String path) { 224 return new File(context.getFilesDir(), path); 225 } 226 227 @Override openFile(Uri uri, String mode)228 public ParcelFileDescriptor openFile(Uri uri, String mode) { 229 final int id = (int) ContentUris.parseId(uri); 230 final File targetFile = getCopiedFile(getContext(), FONT_FILES[id]); 231 try { 232 return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY); 233 } catch (FileNotFoundException e) { 234 throw new RuntimeException( 235 "Failed to find font file. Did you forget to call prepareFontFiles in setUp?"); 236 } 237 } 238 239 @Override onCreate()240 public boolean onCreate() { 241 return true; 242 } 243 244 @Override getType(Uri uri)245 public String getType(Uri uri) { 246 return "vnd.android.cursor.dir/vnd.android.provider.cts.font"; 247 } 248 249 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)250 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 251 String sortOrder) { 252 return buildCursor(QUERY_MAP.get(selectionArgs[0])); 253 } 254 255 @Override insert(Uri uri, ContentValues values)256 public Uri insert(Uri uri, ContentValues values) { 257 throw new UnsupportedOperationException("insert is not supported."); 258 } 259 260 @Override delete(Uri uri, String selection, String[] selectionArgs)261 public int delete(Uri uri, String selection, String[] selectionArgs) { 262 throw new UnsupportedOperationException("delete is not supported."); 263 } 264 265 @Override update(Uri uri, ContentValues values, String selection, String[] selectionArgs)266 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 267 throw new UnsupportedOperationException("update is not supported."); 268 } 269 } 270