blob: ed5f9168a82c1d64e771ddcc1bc9f885f6b5c9e6 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.core.provider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import androidx.core.provider.FontsContractCompat.Columns;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Provides a test Content Provider implementing {@link FontsContractCompat}.
*/
public class MockFontProvider extends ContentProvider {
public static final String AUTHORITY = "androidx.core.provider.fonts.font";
static final String[] FONT_FILES = {
"samplefont.ttf", "large_a.ttf", "large_b.ttf", "large_c.ttf", "large_d.ttf"
};
public static final int INVALID_FONT_FILE_ID = -1;
private static final int SAMPLE_FONT_FILE_0_ID = 0;
private static final int LARGE_A_FILE_ID = 1;
private static final int LARGE_B_FILE_ID = 2;
private static final int LARGE_C_FILE_ID = 3;
private static final int LARGE_D_FILE_ID = 4;
static final String SINGLE_FONT_FAMILY_QUERY = "singleFontFamily";
static final String SINGLE_FONT_FAMILY2_QUERY = "singleFontFamily2";
static final String NOT_FOUND_QUERY = "notFound";
static final String UNAVAILABLE_QUERY = "unavailable";
static final String MALFORMED_QUERY = "malformed";
static final String NOT_FOUND_SECOND_QUERY = "notFoundSecond";
static final String NOT_FOUND_THIRD_QUERY = "notFoundThird";
static final String NEGATIVE_ERROR_CODE_QUERY = "negativeCode";
static final String MANDATORY_FIELDS_ONLY_QUERY = "mandatoryFields";
static final String STYLE_TEST_QUERY = "styleTest";
static final String INVALID_URI = "invalidURI";
static class Font {
Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
int resultCode, boolean returnAllFields) {
mId = id;
mFileId = fileId;
mTtcIndex = ttcIndex;
mVarSettings = varSettings;
mWeight = weight;
mItalic = italic;
mResultCode = resultCode;
mReturnAllFields = returnAllFields;
}
public int getId() {
return mId;
}
public int getTtcIndex() {
return mTtcIndex;
}
public String getVarSettings() {
return mVarSettings;
}
public int getWeight() {
return mWeight;
}
public int getItalic() {
return mItalic;
}
public int getResultCode() {
return mResultCode;
}
public int getFileId() {
return mFileId;
}
public boolean isReturnAllFields() {
return mReturnAllFields;
}
private final int mId;
private final int mFileId;
private final int mTtcIndex;
private final String mVarSettings;
private final int mWeight;
private final int mItalic;
private final int mResultCode;
private final boolean mReturnAllFields;
};
private static final Map<String, Font[]> QUERY_MAP;
static {
HashMap<String, Font[]> map = new HashMap<>();
int id = 1;
map.put(SINGLE_FONT_FAMILY_QUERY, new Font[] {
new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, "'wght' 100", 400, 0,
Columns.RESULT_CODE_OK, true),
});
map.put(SINGLE_FONT_FAMILY2_QUERY, new Font[] {
new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, "'wght' 100", 700, 1,
Columns.RESULT_CODE_OK, true),
});
map.put(NOT_FOUND_QUERY, new Font[] {
new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_NOT_FOUND, true),
});
map.put(UNAVAILABLE_QUERY, new Font[] {
new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_FONT_UNAVAILABLE, true),
});
map.put(MALFORMED_QUERY, new Font[] {
new Font(0, 0, 0, null, 400, 0, Columns.RESULT_CODE_MALFORMED_QUERY, true),
});
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),
});
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),
});
map.put(NEGATIVE_ERROR_CODE_QUERY, new Font[] {
new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, -5, true),
});
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),
});
map.put(STYLE_TEST_QUERY, new Font[] {
new Font(id++, LARGE_A_FILE_ID, 0, null, 400, 0 /* normal */,
Columns.RESULT_CODE_OK, true),
new Font(id++, LARGE_B_FILE_ID, 0, null, 400, 1 /* italic */,
Columns.RESULT_CODE_OK, true),
new Font(id++, LARGE_C_FILE_ID, 0, null, 700, 0 /* normal */,
Columns.RESULT_CODE_OK, true),
new Font(id++, LARGE_D_FILE_ID, 0, null, 700, 1 /* italic */,
Columns.RESULT_CODE_OK, true),
});
map.put(INVALID_URI, new Font[] {
new Font(id++, INVALID_FONT_FILE_ID, 0, null, 400, 0,
Columns.RESULT_CODE_OK, true),
});
QUERY_MAP = Collections.unmodifiableMap(map);
}
private static Cursor buildCursor(Font[] in) {
if (!in[0].mReturnAllFields) {
MatrixCursor cursor = new MatrixCursor(new String[] { Columns._ID, Columns.FILE_ID });
for (Font font : in) {
cursor.addRow(new Object[] { font.getId(), font.getFileId() });
}
return cursor;
}
MatrixCursor cursor = new MatrixCursor(new String[] {
Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT,
Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID});
for (Font font : in) {
cursor.addRow(
new Object[] { font.getId(), font.getTtcIndex(), font.getVarSettings(),
font.getWeight(), font.getItalic(), font.getResultCode(), font.getFileId() });
}
return cursor;
}
public static void prepareFontFiles(Context context) {
final AssetManager mgr = context.getAssets();
for (String file : FONT_FILES) {
InputStream is = null;
try {
is = mgr.open("fonts/" + file);
File copied = getCopiedFile(context, file);
File parent = copied.getParentFile();
if (!parent.isDirectory()) {
parent.mkdirs();
parent.setReadable(true, false);
parent.setExecutable(true, false);
}
copy(is, copied);
copied.setReadable(true, false);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// Do nothing.
}
}
}
}
}
/**
* The caller is responsible for closing the given InputStream.
*/
private static void copy(InputStream is, File file) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file, false);
byte[] buffer = new byte[1024];
int readLen;
while ((readLen = is.read(buffer)) != -1) {
fos.write(buffer, 0, readLen);
}
} finally {
if (fos != null) {
fos.close();
}
}
}
public static void cleanUpFontFiles(Context context) {
for (String file : FONT_FILES) {
getCopiedFile(context, file).delete();
}
}
public static File getCopiedFile(Context context, String path) {
final File cacheDir = new File(context.getFilesDir(), "fontCache");
return new File(cacheDir, path);
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) {
final int id = (int) ContentUris.parseId(uri);
if (id < 0) {
return null;
}
final File targetFile = getCopiedFile(getContext(), FONT_FILES[id]);
try {
return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
} catch (FileNotFoundException e) {
throw new RuntimeException(
"Failed to found font file. You might forget call prepareFontFiles in setUp");
}
}
@Override
public boolean onCreate() {
return true;
}
@Override
public String getType(Uri uri) {
return "vnd.android.cursor.dir/vnd.android.provider.font";
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return buildCursor(QUERY_MAP.get(selectionArgs[0]));
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException("insert is not supported.");
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("delete is not supported.");
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("update is not supported.");
}
}