Declarative downloadable fonts

Implement support for downloadable font requests in xml. Given the
xml fonts feature in O, this adds support to not only declare
local font files as font resources, but also Downloadable fonts
from a fonts provider.

A provider returns a font family (of one or more files) given a
query, so the new attributes are added to the font-family tag.

Additionally, add support to pre-declare downloadable font resources
in the Android Manifest. These will then be fetched at app startup
time so they are available to use from the Typeface cache asap.

When retrieving downloadable fonts via resources, the cache is
checked to see if the font is already there and is used, otherwise
a request is sent to the provider and the default font is returned
as we need a result synchronously.

To do this, the developer declares an additional fonts xml resource
file with the list of fonts to preload and links it in the manifest
with a meta-data tag.

E.g.:

res/font/mydownloadedfont.xml

<font-family xmlns:android="http://schemas.android.com/apk/res/android"
        android:fontProviderAuthority="com.example.test.fontprovider"
        android:fontProviderQuery="myrequestedfont">
</font-family>

res/font/preloaded_fonts.xml

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
    <font android:font="@font/mydownloadedfont" />
</font-family>

and in the AndroidManifest.xml

<meta-data android:name="preloaded_fonts"
    android:resource="@font/preloaded_fonts" />

Bug: 34660500, 34658116
Test: WIP, need to add more
Change-Id: I1d92555e115e241bf23b59e6f5c6cca6c7361de7
This commit is contained in:
Clara Bayarri
2017-01-27 20:15:45 +00:00
parent 0bb700914c
commit 4b5a4d221f
14 changed files with 261 additions and 36 deletions

View File

@ -163,36 +163,54 @@ public class Typeface {
@Nullable
public static Typeface createFromResources(FontConfig config, AssetManager mgr, String path) {
if (sFallbackFonts != null) {
Typeface typeface = findFromCache(mgr, path);
if (typeface != null) return typeface;
List<FontConfig.Family> families = config.getFamilies();
if (families == null || families.isEmpty()) {
throw new RuntimeException(
"Font resource " + path + " contained no font families.");
}
if (families.size() > 1) {
throw new RuntimeException(
"Font resource " + path + " contained more than one family.");
}
FontConfig.Family family = families.get(0);
if (family.getProviderAuthority() != null && family.getQuery() != null) {
// Downloadable font
typeface = findFromCache(
family.getProviderAuthority(), family.getQuery());
if (typeface != null) {
return typeface;
}
// Downloaded font and it wasn't cached, request it again and return a
// default font instead (nothing we can do now).
create(new FontRequest(family.getProviderAuthority(), family.getQuery()),
NO_OP_REQUEST_CALLBACK);
return DEFAULT;
}
FontFamily fontFamily = new FontFamily();
List<FontConfig.Font> fonts = family.getFonts();
if (fonts == null || fonts.isEmpty()) {
throw new RuntimeException("Font resource " + path + " contained no fonts.");
}
for (int i = 0; i < fonts.size(); i++) {
FontConfig.Font font = fonts.get(i);
// TODO: Use style and weight info
if (!fontFamily.addFontFromAssetManager(mgr, font.getFontName(),
0 /* resourceCookie */, false /* isAsset */)) {
return null;
}
}
fontFamily.freeze();
FontFamily[] familyChain = { fontFamily };
typeface = createFromFamiliesWithDefault(familyChain);
synchronized (sDynamicTypefaceCache) {
final String key = createAssetUid(mgr, path);
Typeface typeface = sDynamicTypefaceCache.get(key);
if (typeface != null) return typeface;
List<FontConfig.Family> families = config.getFamilies();
if (families == null || families.isEmpty()) {
throw new RuntimeException("Font resource contained no fonts.");
}
if (families.size() > 1) {
throw new RuntimeException("Font resource contained more than one family.");
}
FontConfig.Family family = families.get(0);
FontFamily fontFamily = new FontFamily();
List<FontConfig.Font> fonts = family.getFonts();
for (int i = 0; i < fonts.size(); i++) {
FontConfig.Font font = fonts.get(i);
// TODO: Use style and weight info
if (!fontFamily.addFontFromAssetManager(mgr, font.getFontName(),
0 /* resourceCookie */, false /* isAsset */)) {
return null;
}
}
fontFamily.freeze();
FontFamily[] familyChain = { fontFamily };
typeface = createFromFamiliesWithDefault(familyChain);
sDynamicTypefaceCache.put(key, typeface);
return typeface;
}
return typeface;
}
return null;
}
@ -372,6 +390,18 @@ public class Typeface {
void onTypefaceRequestFailed(@FontRequestFailReason int reason);
}
private static final FontRequestCallback NO_OP_REQUEST_CALLBACK = new FontRequestCallback() {
@Override
public void onTypefaceRetrieved(Typeface typeface) {
// Do nothing.
}
@Override
public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {
// Do nothing.
}
};
/**
* Create a typeface object given a family name, and option style information.
* If null is passed for the name, then the "default" font will be chosen.