Expose Resources.getFont

Based on the work already done in aapt2, load a Font from a
resource id.

Test: WIP
Change-Id: Idc06bfbfd16452a328bfcc6ea9dcfb723b633f0c
This commit is contained in:
Clara Bayarri
2016-12-19 16:20:29 +00:00
parent bcd68cf520
commit 18e9f9f377
9 changed files with 225 additions and 11 deletions

View File

@@ -10681,6 +10681,7 @@ package android.content.res {
method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
method public float getFraction(int, int, int);
method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;

View File

@@ -11199,6 +11199,7 @@ package android.content.res {
method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
method public float getFraction(int, int, int);
method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;

View File

@@ -10713,6 +10713,7 @@ package android.content.res {
method public android.graphics.drawable.Drawable getDrawable(int, android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
method public deprecated android.graphics.drawable.Drawable getDrawableForDensity(int, int) throws android.content.res.Resources.NotFoundException;
method public android.graphics.drawable.Drawable getDrawableForDensity(int, int, android.content.res.Resources.Theme);
method public android.graphics.Typeface getFont(int) throws android.content.res.Resources.NotFoundException;
method public float getFraction(int, int, int);
method public int getIdentifier(java.lang.String, java.lang.String, java.lang.String);
method public int[] getIntArray(int) throws android.content.res.Resources.NotFoundException;

View File

@@ -40,6 +40,7 @@ import android.annotation.StyleableRes;
import android.annotation.XmlRes;
import android.content.pm.ActivityInfo;
import android.graphics.Movie;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.DrawableInflater;
@@ -333,7 +334,35 @@ public class Resources {
return res;
}
throw new NotFoundException("String resource ID #0x"
+ Integer.toHexString(id));
+ Integer.toHexString(id));
}
/**
* Return the Typeface value associated with a particular resource ID.
* {@more}
*
* @param id The desired resource identifier, as generated by the aapt
* tool. This integer encodes the package, type, and resource
* entry. The value 0 is an invalid identifier.
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
*
* @return Typeface The Typeface data associated with the resource.
*/
@NonNull public Typeface getFont(@StringRes int id) throws NotFoundException {
final TypedValue value = obtainTempTypedValue();
try {
final ResourcesImpl impl = mResourcesImpl;
impl.getValue(id, value, true);
Typeface typeface = impl.loadFont(value, id);
if (typeface != null) {
return typeface;
}
} finally {
releaseTempTypedValue(value);
}
throw new NotFoundException("Font resource ID #0x"
+ Integer.toHexString(id));
}
/**

View File

@@ -31,6 +31,7 @@ import android.annotation.StyleableRes;
import android.content.pm.ActivityInfo;
import android.content.pm.ActivityInfo.Config;
import android.content.res.Resources.NotFoundException;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.icu.text.PluralRules;
@@ -47,6 +48,7 @@ import android.util.Xml;
import android.view.Display;
import android.view.DisplayAdjustments;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Locale;
@@ -739,6 +741,36 @@ public class ResourcesImpl {
return dr;
}
/**
* Loads a font from XML or resources stream.
*/
@Nullable
public Typeface loadFont(TypedValue value, int id) {
if (value.string == null) {
throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+ Integer.toHexString(id) + ") is not a Font: " + value);
}
final String file = value.string.toString();
if (DEBUG_LOAD) {
Log.v(TAG, "Loading font for cookie " + value.assetCookie + ": " + file);
}
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
try {
if (file.endsWith(".xml")) {
// TODO handle xml type font definitions
} else {
return Typeface.createFromResources(
mAssets, value.string.toString(), value.assetCookie);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
return null;
}
/**
* Given the value and id, we can get the XML filename as in value.data, based on that, we
* first try to load CSL from the cache. If not found, try to get from the constant state.

View File

@@ -190,8 +190,8 @@ static void releaseAsset(const void* ptr, void* context) {
delete static_cast<Asset*>(context);
}
static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPtr,
jobject jassetMgr, jstring jpath) {
static jboolean FontFamily_addFontFromAssetManager(JNIEnv* env, jobject, jlong familyPtr,
jobject jassetMgr, jstring jpath, jint cookie, jboolean isAsset) {
NPE_CHECK_RETURN_ZERO(env, jassetMgr);
NPE_CHECK_RETURN_ZERO(env, jpath);
@@ -201,7 +201,18 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt
}
ScopedUtfChars str(env, jpath);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
if (str.c_str() == nullptr) {
return false;
}
Asset* asset;
if (isAsset) {
asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
} else {
asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
}
if (NULL == asset) {
return false;
}
@@ -234,8 +245,8 @@ static const JNINativeMethod gFontFamilyMethods[] = {
{ "nAddFont", "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont },
{ "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
(void*)FontFamily_addFontWeightStyle },
{ "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",
(void*)FontFamily_addFontFromAsset },
{ "nAddFontFromAssetManager", "(JLandroid/content/res/AssetManager;Ljava/lang/String;IZ)Z",
(void*)FontFamily_addFontFromAssetManager },
};
int register_android_graphics_FontFamily(JNIEnv* env)

View File

@@ -85,8 +85,9 @@ public class FontFamily {
return nAddFontWeightStyle(mNativePtr, font, ttcIndex, axes, weight, style);
}
public boolean addFontFromAsset(AssetManager mgr, String path) {
return nAddFontFromAsset(mNativePtr, mgr, path);
public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
boolean isAsset) {
return nAddFontFromAssetManager(mNativePtr, mgr, path, cookie, isAsset);
}
private static native long nCreateFamily(String lang, int variant);
@@ -95,6 +96,6 @@ public class FontFamily {
private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
int ttcIndex, List<FontListParser.Axis> listOfAxis,
int weight, boolean isItalic);
private static native boolean nAddFontFromAsset(long nativeFamily, AssetManager mgr,
String path);
private static native boolean nAddFontFromAssetManager(long nativeFamily, AssetManager mgr,
String path, int cookie, boolean isAsset);
}

View File

@@ -0,0 +1,113 @@
/*
* 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.graphics;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
/**
* Parser for xml type font resources.
* @hide
*/
public class FontResourcesParser {
private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android";
/* Parse fallback list (no names) */
public static FontListParser.Config parse(XmlPullParser parser)
throws XmlPullParserException, IOException {
int type;
//noinspection StatementWithEmptyBody
while ((type=parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
// Empty loop.
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
return readFamilies(parser);
}
private static FontListParser.Config readFamilies(XmlPullParser parser)
throws XmlPullParserException, IOException {
FontListParser.Config config = new FontListParser.Config();
parser.require(XmlPullParser.START_TAG, null, "font-family");
String tag = parser.getName();
if (tag.equals("font-family")) {
config.families.add(readFamily(parser));
} else {
skip(parser);
}
return config;
}
private static FontListParser.Family readFamily(XmlPullParser parser)
throws XmlPullParserException, IOException {
String name = parser.getAttributeValue(null, "name");
String lang = parser.getAttributeValue(null, "lang");
String variant = parser.getAttributeValue(null, "variant");
List<FontListParser.Font> fonts = new ArrayList<>();
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (tag.equals("font")) {
fonts.add(readFont(parser));
} else {
skip(parser);
}
}
return new FontListParser.Family(name, fonts, lang, variant);
}
/** Matches leading and trailing XML whitespace. */
private static final Pattern FILENAME_WHITESPACE_PATTERN =
Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
private static FontListParser.Font readFont(XmlPullParser parser)
throws XmlPullParserException, IOException {
List<FontListParser.Axis> axes = new ArrayList<>();
String weightStr = parser.getAttributeValue(ANDROID_NAMESPACE, "fontWeight");
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
boolean isItalic = "italic".equals(
parser.getAttributeValue(ANDROID_NAMESPACE, "fontStyle"));
String filename = parser.getAttributeValue(ANDROID_NAMESPACE, "font");
String fullFilename = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
return new FontListParser.Font(fullFilename, 0, axes, weight, isItalic);
}
private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
int depth = 1;
while (depth > 0) {
switch (parser.next()) {
case XmlPullParser.START_TAG:
depth++;
break;
case XmlPullParser.END_TAG:
depth--;
break;
}
}
}
}

View File

@@ -16,6 +16,7 @@
package android.graphics;
import android.annotation.NonNull;
import android.content.res.AssetManager;
import android.util.Log;
import android.util.LongSparseArray;
@@ -108,6 +109,30 @@ public class Typeface {
return (mStyle & ITALIC) != 0;
}
/**
* @hide
* Used by Resources.
*/
@NonNull
public static Typeface createFromResources(AssetManager mgr, String path, int cookie) {
if (sFallbackFonts != null) {
synchronized (sDynamicTypefaceCache) {
final String key = createAssetUid(mgr, path);
Typeface typeface = sDynamicTypefaceCache.get(key);
if (typeface != null) return typeface;
FontFamily fontFamily = new FontFamily();
if (fontFamily.addFontFromAssetManager(mgr, path, cookie, false /* isAsset */)) {
FontFamily[] families = { fontFamily };
typeface = createFromFamiliesWithDefault(families);
sDynamicTypefaceCache.put(key, typeface);
return typeface;
}
}
}
throw new RuntimeException("Font resource not found " + path);
}
/**
* 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.
@@ -195,7 +220,7 @@ public class Typeface {
if (typeface != null) return typeface;
FontFamily fontFamily = new FontFamily();
if (fontFamily.addFontFromAsset(mgr, path)) {
if (fontFamily.addFontFromAssetManager(mgr, path, 0, true /* isAsset */)) {
FontFamily[] families = { fontFamily };
typeface = createFromFamiliesWithDefault(families);
sDynamicTypefaceCache.put(key, typeface);