Merge "Expose Resources.getFont"
diff --git a/api/current.txt b/api/current.txt
index 2b07a5c..a59e2a1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10723,6 +10723,7 @@
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;
diff --git a/api/system-current.txt b/api/system-current.txt
index 7cb8aaf..ed52bd1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11245,6 +11245,7 @@
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;
diff --git a/api/test-current.txt b/api/test-current.txt
index 82715b3..3fe04f7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -10755,6 +10755,7 @@
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;
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ad11307..c3185a7 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -40,6 +40,7 @@
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 @@
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));
}
/**
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index eb010e4..05892e0 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -31,6 +31,7 @@
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.view.Display;
import android.view.DisplayAdjustments;
+import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Locale;
@@ -740,6 +742,36 @@
}
/**
+ * 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.
* Last, parse the XML and generate the CSL.
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 15e7165..2504e54 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -190,8 +190,8 @@
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 @@
}
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 @@
{ "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)
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index e48bf79..cd5071e8 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -85,8 +85,9 @@
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 @@
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);
}
diff --git a/graphics/java/android/graphics/FontResourcesParser.java b/graphics/java/android/graphics/FontResourcesParser.java
new file mode 100644
index 0000000..b4109cf
--- /dev/null
+++ b/graphics/java/android/graphics/FontResourcesParser.java
@@ -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;
+ }
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 2886f0d..eebe538 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -16,6 +16,7 @@
package android.graphics;
+import android.annotation.NonNull;
import android.content.res.AssetManager;
import android.util.Log;
import android.util.LongSparseArray;
@@ -109,6 +110,30 @@
}
/**
+ * @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.
* The resulting typeface object can be queried (getStyle()) to discover what
@@ -195,7 +220,7 @@
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);