Merge "Cache the Typeface based on the FontRequest." into oc-dev
am: 5b96e55d90
Change-Id: Ic185a25c605e7345afa214d3b50fd859135f7b9b
This commit is contained in:
@@ -44,6 +44,7 @@ import android.os.ParcelFileDescriptor;
|
||||
import android.os.Process;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.Log;
|
||||
import android.util.LruCache;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -181,6 +182,8 @@ public class FontsContract {
|
||||
@GuardedBy("mLock")
|
||||
private HandlerThread mThread;
|
||||
|
||||
private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
|
||||
|
||||
/** @hide */
|
||||
public FontsContract(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
@@ -476,6 +479,11 @@ public class FontsContract {
|
||||
* therefore the result is delivered to the given callback. See {@link FontRequest}.
|
||||
* Only one of the methods in callback will be invoked, depending on whether the request
|
||||
* succeeds or fails. These calls will happen on the caller thread.
|
||||
*
|
||||
* Note that the result Typeface may be cached internally and the same instance will be returned
|
||||
* the next time you call this method with the same request. If you want to bypass this cache,
|
||||
* use {@link #fetchFonts} and {@link #buildTypeface} instead.
|
||||
*
|
||||
* @param context A context to be used for fetching from font provider.
|
||||
* @param request A {@link FontRequest} object that identifies the provider and query for the
|
||||
* request. May not be null.
|
||||
@@ -486,8 +494,13 @@ public class FontsContract {
|
||||
@NonNull FontRequestCallback callback, @NonNull Handler handler) {
|
||||
|
||||
final Handler callerThreadHandler = new Handler();
|
||||
final Typeface cachedTypeface = sTypefaceCache.get(request.getIdentifier());
|
||||
if (cachedTypeface != null) {
|
||||
callerThreadHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
|
||||
return;
|
||||
}
|
||||
|
||||
handler.post(() -> {
|
||||
// TODO: Cache the result.
|
||||
FontFamilyResult result;
|
||||
try {
|
||||
result = fetchFonts(context, null /* cancellation signal */, request);
|
||||
@@ -497,6 +510,13 @@ public class FontsContract {
|
||||
return;
|
||||
}
|
||||
|
||||
// Same request might be dispatched during fetchFonts. Check the cache again.
|
||||
final Typeface anotherCachedTypeface = sTypefaceCache.get(request.getIdentifier());
|
||||
if (anotherCachedTypeface != null) {
|
||||
callerThreadHandler.post(() -> callback.onTypefaceRetrieved(anotherCachedTypeface));
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.getStatusCode() != FontFamilyResult.STATUS_OK) {
|
||||
switch (result.getStatusCode()) {
|
||||
case FontFamilyResult.STATUS_WRONG_CERTIFICATES:
|
||||
@@ -547,6 +567,7 @@ public class FontsContract {
|
||||
return;
|
||||
}
|
||||
|
||||
sTypefaceCache.put(request.getIdentifier(), typeface);
|
||||
callerThreadHandler.post(() -> callback.onTypefaceRetrieved(typeface));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1266,6 +1266,11 @@
|
||||
<meta-data android:name="com.android.frameworks.coretests.reference" android:resource="@xml/metadata" />
|
||||
</provider>
|
||||
|
||||
<provider android:name="android.provider.MockFontProvider"
|
||||
android:authorities="android.provider.fonts.font"
|
||||
android:exported="false"
|
||||
android:multiprocess="true" />
|
||||
|
||||
<!-- Application components used for content tests -->
|
||||
<provider android:name="android.content.MemoryFileProvider"
|
||||
android:authorities="android.content.MemoryFileProvider"
|
||||
|
||||
BIN
core/tests/coretests/assets/fonts/samplefont1.ttf
Normal file
BIN
core/tests/coretests/assets/fonts/samplefont1.ttf
Normal file
Binary file not shown.
177
core/tests/coretests/assets/fonts/samplefont1.ttx
Normal file
177
core/tests/coretests/assets/fonts/samplefont1.ttx
Normal file
@@ -0,0 +1,177 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
|
||||
|
||||
<GlyphOrder>
|
||||
<GlyphID id="0" name=".notdef"/>
|
||||
<GlyphID id="1" name="a"/>
|
||||
</GlyphOrder>
|
||||
|
||||
<head>
|
||||
<tableVersion value="1.0"/>
|
||||
<fontRevision value="1.0"/>
|
||||
<checkSumAdjustment value="0x640cdb2f"/>
|
||||
<magicNumber value="0x5f0f3cf5"/>
|
||||
<flags value="00000000 00000011"/>
|
||||
<unitsPerEm value="1000"/>
|
||||
<created value="Fri Mar 17 07:26:00 2017"/>
|
||||
<macStyle value="00000000 00000000"/>
|
||||
<lowestRecPPEM value="7"/>
|
||||
<fontDirectionHint value="2"/>
|
||||
<glyphDataFormat value="0"/>
|
||||
</head>
|
||||
|
||||
<hhea>
|
||||
<tableVersion value="1.0"/>
|
||||
<ascent value="1000"/>
|
||||
<descent value="-200"/>
|
||||
<lineGap value="0"/>
|
||||
<caretSlopeRise value="1"/>
|
||||
<caretSlopeRun value="0"/>
|
||||
<caretOffset value="0"/>
|
||||
<reserved0 value="0"/>
|
||||
<reserved1 value="0"/>
|
||||
<reserved2 value="0"/>
|
||||
<reserved3 value="0"/>
|
||||
<metricDataFormat value="0"/>
|
||||
</hhea>
|
||||
|
||||
<maxp>
|
||||
<tableVersion value="0x10000"/>
|
||||
<maxZones value="0"/>
|
||||
<maxTwilightPoints value="0"/>
|
||||
<maxStorage value="0"/>
|
||||
<maxFunctionDefs value="0"/>
|
||||
<maxInstructionDefs value="0"/>
|
||||
<maxStackElements value="0"/>
|
||||
<maxSizeOfInstructions value="0"/>
|
||||
<maxComponentElements value="0"/>
|
||||
</maxp>
|
||||
|
||||
<OS_2>
|
||||
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
|
||||
will be recalculated by the compiler -->
|
||||
<version value="3"/>
|
||||
<xAvgCharWidth value="594"/>
|
||||
<usWeightClass value="400"/>
|
||||
<usWidthClass value="5"/>
|
||||
<fsType value="00000000 00001000"/>
|
||||
<ySubscriptXSize value="650"/>
|
||||
<ySubscriptYSize value="600"/>
|
||||
<ySubscriptXOffset value="0"/>
|
||||
<ySubscriptYOffset value="75"/>
|
||||
<ySuperscriptXSize value="650"/>
|
||||
<ySuperscriptYSize value="600"/>
|
||||
<ySuperscriptXOffset value="0"/>
|
||||
<ySuperscriptYOffset value="350"/>
|
||||
<yStrikeoutSize value="50"/>
|
||||
<yStrikeoutPosition value="300"/>
|
||||
<sFamilyClass value="0"/>
|
||||
<panose>
|
||||
<bFamilyType value="0"/>
|
||||
<bSerifStyle value="0"/>
|
||||
<bWeight value="5"/>
|
||||
<bProportion value="0"/>
|
||||
<bContrast value="0"/>
|
||||
<bStrokeVariation value="0"/>
|
||||
<bArmStyle value="0"/>
|
||||
<bLetterForm value="0"/>
|
||||
<bMidline value="0"/>
|
||||
<bXHeight value="0"/>
|
||||
</panose>
|
||||
<ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
|
||||
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
|
||||
<achVendID value="UKWN"/>
|
||||
<fsSelection value="00000000 01000000"/>
|
||||
<usFirstCharIndex value="32"/>
|
||||
<usLastCharIndex value="122"/>
|
||||
<sTypoAscender value="800"/>
|
||||
<sTypoDescender value="-200"/>
|
||||
<sTypoLineGap value="200"/>
|
||||
<usWinAscent value="1000"/>
|
||||
<usWinDescent value="200"/>
|
||||
<ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
|
||||
<ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
|
||||
<sxHeight value="500"/>
|
||||
<sCapHeight value="700"/>
|
||||
<usDefaultChar value="0"/>
|
||||
<usBreakChar value="32"/>
|
||||
<usMaxContext value="0"/>
|
||||
</OS_2>
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="500" lsb="93"/>
|
||||
<mtx name="a" width="500" lsb="93"/>
|
||||
</hmtx>
|
||||
|
||||
<cmap>
|
||||
<tableVersion version="0"/>
|
||||
<cmap_format_4 platformID="3" platEncID="10" language="0">
|
||||
<map code="0x0061" name="a" />
|
||||
</cmap_format_4>
|
||||
</cmap>
|
||||
|
||||
<loca>
|
||||
<!-- The 'loca' table will be calculated by the compiler -->
|
||||
</loca>
|
||||
|
||||
<glyf>
|
||||
<TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
<TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
|
||||
</glyf>
|
||||
|
||||
<name>
|
||||
<namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
|
||||
Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
|
||||
SampleFont-Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
|
||||
Regular
|
||||
</namerecord>
|
||||
<namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
|
||||
Sample Font
|
||||
</namerecord>
|
||||
<namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
|
||||
SampleFont-Regular
|
||||
</namerecord>
|
||||
</name>
|
||||
|
||||
<post>
|
||||
<formatType value="3.0"/>
|
||||
<italicAngle value="0.0"/>
|
||||
<underlinePosition value="-75"/>
|
||||
<underlineThickness value="50"/>
|
||||
<isFixedPitch value="0"/>
|
||||
<minMemType42 value="0"/>
|
||||
<maxMemType42 value="0"/>
|
||||
<minMemType1 value="0"/>
|
||||
<maxMemType1 value="0"/>
|
||||
</post>
|
||||
|
||||
</ttFont>
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 android.provider;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.pm.Signature;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.Context;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.fonts.FontRequest;
|
||||
import android.provider.FontsContract;
|
||||
import android.provider.FontsContract.FontFamilyResult;
|
||||
import android.provider.FontsContract.FontInfo;
|
||||
import android.provider.FontsContract.Columns;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.os.Handler;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FontsContractE2ETest {
|
||||
private static final String AUTHORITY = "android.provider.fonts.font";
|
||||
private static final String PACKAGE = "com.android.frameworks.coretests";
|
||||
|
||||
// Signature to be used for authentication to access content provider.
|
||||
// In this test case, the content provider and consumer live in the same package, self package's
|
||||
// signature works.
|
||||
private static List<List<byte[]>> SIGNATURE;
|
||||
static {
|
||||
final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
try {
|
||||
PackageManager manager = context.getPackageManager();
|
||||
PackageInfo info = manager.getPackageInfo(
|
||||
context.getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
ArrayList<byte[]> out = new ArrayList<>();
|
||||
for (Signature sig : info.signatures) {
|
||||
out.add(sig.toByteArray());
|
||||
}
|
||||
SIGNATURE = new ArrayList<>();
|
||||
SIGNATURE.add(out);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockFontProvider.prepareFontFiles(
|
||||
InstrumentationRegistry.getInstrumentation().getTargetContext());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
MockFontProvider.cleanUpFontFiles(
|
||||
InstrumentationRegistry.getInstrumentation().getTargetContext());
|
||||
}
|
||||
|
||||
private static class TestCallback extends FontsContract.FontRequestCallback {
|
||||
private Typeface mTypeface;
|
||||
|
||||
private int mSuccessCallCount;
|
||||
private int mFailedCallCount;
|
||||
|
||||
public void onTypefaceRetrieved(Typeface typeface) {
|
||||
mTypeface = typeface;
|
||||
mSuccessCallCount++;
|
||||
}
|
||||
|
||||
public void onTypefaceRequestFailed(int reason) {
|
||||
mFailedCallCount++;
|
||||
}
|
||||
|
||||
public Typeface getTypeface() {
|
||||
return mTypeface;
|
||||
}
|
||||
|
||||
public int getSuccessCallCount() {
|
||||
return mSuccessCallCount;
|
||||
}
|
||||
|
||||
public int getFailedCallCount() {
|
||||
return mFailedCallCount;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typefaceCacheTest() throws NameNotFoundException {
|
||||
Instrumentation inst = InstrumentationRegistry.getInstrumentation();
|
||||
Context ctx = inst.getTargetContext();
|
||||
|
||||
final TestCallback callback = new TestCallback();
|
||||
inst.runOnMainSync(() -> {
|
||||
FontRequest request = new FontRequest(
|
||||
AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
|
||||
FontsContract.requestFont(ctx, request, callback, new Handler());
|
||||
});
|
||||
inst.waitForIdleSync();
|
||||
assertEquals(1, callback.getSuccessCallCount());
|
||||
assertEquals(0, callback.getFailedCallCount());
|
||||
assertNotNull(callback.getTypeface());
|
||||
|
||||
final TestCallback callback2 = new TestCallback();
|
||||
inst.runOnMainSync(() -> {
|
||||
FontRequest request = new FontRequest(
|
||||
AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
|
||||
FontsContract.requestFont(ctx, request, callback2, new Handler());
|
||||
});
|
||||
inst.waitForIdleSync();
|
||||
assertEquals(1, callback2.getSuccessCallCount());
|
||||
assertEquals(0, callback2.getFailedCallCount());
|
||||
assertSame(callback.getTypeface(), callback2.getTypeface());
|
||||
|
||||
final TestCallback callback3 = new TestCallback();
|
||||
inst.runOnMainSync(() -> {
|
||||
FontRequest request = new FontRequest(
|
||||
AUTHORITY, PACKAGE, "singleFontFamily2", SIGNATURE);
|
||||
FontsContract.requestFont(ctx, request, callback3, new Handler());
|
||||
});
|
||||
inst.waitForIdleSync();
|
||||
assertEquals(1, callback3.getSuccessCallCount());
|
||||
assertEquals(0, callback3.getFailedCallCount());
|
||||
assertNotSame(callback.getTypeface(), callback3.getTypeface());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typefaceNotCacheTest() throws NameNotFoundException {
|
||||
Instrumentation inst = InstrumentationRegistry.getInstrumentation();
|
||||
Context ctx = inst.getTargetContext();
|
||||
|
||||
FontRequest request = new FontRequest(
|
||||
AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
|
||||
FontFamilyResult result = FontsContract.fetchFonts(
|
||||
ctx, null /* cancellation signal */, request);
|
||||
assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
|
||||
Typeface typeface = FontsContract.buildTypeface(
|
||||
ctx, null /* cancellation signal */, result.getFonts());
|
||||
|
||||
FontFamilyResult result2 = FontsContract.fetchFonts(
|
||||
ctx, null /* cancellation signal */, request);
|
||||
assertEquals(FontFamilyResult.STATUS_OK, result2.getStatusCode());
|
||||
Typeface typeface2 = FontsContract.buildTypeface(
|
||||
ctx, null /* cancellation signal */, result2.getFonts());
|
||||
|
||||
// Neighter fetchFonts nor buildTypeface should cache the Typeface.
|
||||
assertNotSame(typeface, typeface2);
|
||||
}
|
||||
}
|
||||
202
core/tests/coretests/src/android/provider/MockFontProvider.java
Normal file
202
core/tests/coretests/src/android/provider/MockFontProvider.java
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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 android.provider;
|
||||
|
||||
import static android.provider.FontsContract.Columns;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.content.res.AssetManager;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.graphics.fonts.FontVariationAxis;
|
||||
import android.net.Uri;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class MockFontProvider extends ContentProvider {
|
||||
final static String AUTHORITY = "android.provider.fonts.font";
|
||||
|
||||
final static String[] FONT_FILES = {
|
||||
"samplefont1.ttf",
|
||||
};
|
||||
private static final int SAMPLE_FONT_FILE_0_ID = 0;
|
||||
private static final int SAMPLE_FONT_FILE_1_ID = 1;
|
||||
|
||||
static class Font {
|
||||
public Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
|
||||
int resultCode) {
|
||||
mId = id;
|
||||
mFileId = fileId;
|
||||
mTtcIndex = ttcIndex;
|
||||
mVarSettings = varSettings;
|
||||
mWeight = weight;
|
||||
mItalic = italic;
|
||||
mResultCode = resultCode;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private int mId;
|
||||
private int mFileId;
|
||||
private int mTtcIndex;
|
||||
private String mVarSettings;
|
||||
private int mWeight;
|
||||
private int mItalic;
|
||||
private int mResultCode;
|
||||
};
|
||||
|
||||
private static Map<String, Font[]> QUERY_MAP;
|
||||
static {
|
||||
HashMap<String, Font[]> map = new HashMap<>();
|
||||
int id = 0;
|
||||
|
||||
map.put("singleFontFamily", new Font[] {
|
||||
new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
|
||||
});
|
||||
|
||||
map.put("singleFontFamily2", new Font[] {
|
||||
new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 0, Columns.RESULT_CODE_OK),
|
||||
});
|
||||
|
||||
QUERY_MAP = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
private static Cursor buildCursor(Font[] in) {
|
||||
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) {
|
||||
MatrixCursor.RowBuilder builder = cursor.newRow();
|
||||
builder.add(Columns._ID, font.getId());
|
||||
builder.add(Columns.FILE_ID, font.getFileId());
|
||||
builder.add(Columns.TTC_INDEX, font.getTtcIndex());
|
||||
builder.add(Columns.VARIATION_SETTINGS, font.getVarSettings());
|
||||
builder.add(Columns.WEIGHT, font.getWeight());
|
||||
builder.add(Columns.ITALIC, font.getItalic());
|
||||
builder.add(Columns.RESULT_CODE, font.getResultCode());
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public MockFontProvider() {
|
||||
}
|
||||
|
||||
public static void prepareFontFiles(Context context) {
|
||||
final AssetManager mgr = context.getAssets();
|
||||
for (String file : FONT_FILES) {
|
||||
try (InputStream is = mgr.open("fonts/" + file)) {
|
||||
Files.copy(is, getCopiedFile(context, file).toPath(),
|
||||
StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void cleanUpFontFiles(Context context) {
|
||||
for (String file : FONT_FILES) {
|
||||
getCopiedFile(context, file).delete();
|
||||
}
|
||||
}
|
||||
|
||||
public static File getCopiedFile(Context context, String path) {
|
||||
return new File(context.getFilesDir(), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) {
|
||||
final int id = (int)ContentUris.parseId(uri);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
@@ -35,6 +35,9 @@ public final class FontRequest implements Parcelable {
|
||||
private final String mQuery;
|
||||
private final List<List<byte[]>> mCertificates;
|
||||
|
||||
// Used for key of the cache.
|
||||
private final String mIdentifier;
|
||||
|
||||
/**
|
||||
* @param providerAuthority The authority of the Font Provider to be used for the request. This
|
||||
* should be a system installed app.
|
||||
@@ -49,6 +52,8 @@ public final class FontRequest implements Parcelable {
|
||||
mQuery = Preconditions.checkNotNull(query);
|
||||
mProviderPackage = Preconditions.checkNotNull(providerPackage);
|
||||
mCertificates = Collections.emptyList();
|
||||
mIdentifier = new StringBuilder(mProviderAuthority).append("-").append(mProviderPackage)
|
||||
.append("-").append(mQuery).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +73,8 @@ public final class FontRequest implements Parcelable {
|
||||
mProviderPackage = Preconditions.checkNotNull(providerPackage);
|
||||
mQuery = Preconditions.checkNotNull(query);
|
||||
mCertificates = Preconditions.checkNotNull(certificates);
|
||||
mIdentifier = new StringBuilder(mProviderAuthority).append("-").append(mProviderPackage)
|
||||
.append("-").append(mQuery).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,6 +109,11 @@ public final class FontRequest implements Parcelable {
|
||||
return mCertificates;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public String getIdentifier() {
|
||||
return mIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
@@ -121,6 +133,8 @@ public final class FontRequest implements Parcelable {
|
||||
mQuery = in.readString();
|
||||
mCertificates = new ArrayList<>();
|
||||
in.readList(mCertificates, null);
|
||||
mIdentifier = new StringBuilder(mProviderAuthority).append("-").append(mProviderPackage)
|
||||
.append("-").append(mQuery).toString();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<FontRequest> CREATOR =
|
||||
|
||||
Reference in New Issue
Block a user