diff options
| author | 2018-07-31 13:57:01 -0700 | |
|---|---|---|
| committer | 2018-08-14 11:17:12 -0700 | |
| commit | eaa917e6946ac9debd6a7f06609d8d0c6907377d (patch) | |
| tree | bbf26cedc46e647dc18b004b5d246143dea3e106 /graphics/java | |
| parent | 9359a6a24d56e40f9c54c42039b68c95dddb440a (diff) | |
Rewrite system fallback construction with new FontFamily
Bug: 111133573
Bug: 112196940
Test: atest CtsWidgetTestCases:EditTextTest
CtsWidgetTestCases:TextViewFadingEdgeTest
FrameworksCoreTests:TextViewFallbackLineSpacingTest
FrameworksCoreTests:TextViewTest FrameworksCoreTests:TypefaceTest
CtsGraphicsTestCases:TypefaceTest CtsWidgetTestCases:TextViewTest
CtsTextTestCases FrameworksCoreTests:android.text
CtsWidgetTestCases:TextViewPrecomputedTextTest
CtsGraphicsTestCases:android.graphics.fonts
Change-Id: I69e21940eaec4427f62abe59ae003b4f60855f22
Diffstat (limited to 'graphics/java')
| -rw-r--r-- | graphics/java/android/graphics/Typeface.java | 237 | ||||
| -rw-r--r-- | graphics/java/android/graphics/fonts/FontFamily.java | 21 | ||||
| -rw-r--r-- | graphics/java/android/graphics/fonts/SystemFonts.java | 260 |
3 files changed, 328 insertions, 190 deletions
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 522d7a51e69b..7fa748461c2d 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -28,13 +28,13 @@ import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.graphics.fonts.FontVariationAxis; +import android.graphics.fonts.SystemFonts; import android.net.Uri; import android.provider.FontRequest; import android.provider.FontsContract; import android.text.FontConfig; import android.util.ArrayMap; import android.util.Base64; -import android.util.Log; import android.util.LongSparseArray; import android.util.LruCache; import android.util.SparseArray; @@ -47,12 +47,9 @@ import dalvik.annotation.optimization.CriticalNative; import libcore.util.NativeAllocationRegistry; -import org.xmlpull.v1.XmlPullParserException; - import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; @@ -121,10 +118,14 @@ public class Typeface { private static final Object sDynamicCacheLock = new Object(); static Typeface sDefaultTypeface; + + // Following two fields are not used but left for hiddenapi private list @UnsupportedAppUsage static final Map<String, Typeface> sSystemFontMap; + + // We cannot support sSystemFallbackMap since we will migrate to public FontFamily API. @UnsupportedAppUsage - static final Map<String, FontFamily[]> sSystemFallbackMap; + static final Map<String, FontFamily[]> sSystemFallbackMap = Collections.emptyMap(); /** * @hide @@ -566,11 +567,7 @@ public class Typeface { return null; } - Typeface base = sSystemFontMap.get(mFallbackFamilyName); - if (base == null) { - base = sDefaultTypeface; - } - + final Typeface base = getSystemDefaultTypeface(mFallbackFamilyName); if (mWeight == RESOLVE_BY_FONT_TABLE && mItalic == RESOLVE_BY_FONT_TABLE) { return base; } @@ -687,7 +684,7 @@ public class Typeface { * @return The best matching typeface. */ public static Typeface create(String familyName, @Style int style) { - return create(sSystemFontMap.get(familyName), style); + return create(getSystemDefaultTypeface(familyName), style); } /** @@ -897,7 +894,9 @@ public class Typeface { * Create a new typeface from an array of font families. * * @param families array of font families + * @deprecated */ + @Deprecated @UnsupportedAppUsage private static Typeface createFromFamilies(FontFamily[] families) { long[] ptrArray = new long[families.length]; @@ -909,6 +908,21 @@ public class Typeface { } /** + * Create a new typeface from an array of android.graphics.fonts.FontFamily. + * + * @param families array of font families + */ + private static Typeface createFromFamilies( + @Nullable android.graphics.fonts.FontFamily[] families) { + final long[] ptrArray = new long[families.length]; + for (int i = 0; i < families.length; ++i) { + ptrArray[i] = families[i].getNativePtr(); + } + return new Typeface(nativeCreateFromArray(ptrArray, + RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE)); + } + + /** * This method is used by supportlib-v27. * TODO: Remove private API use in supportlib: http://b/72665240 */ @@ -934,16 +948,13 @@ public class Typeface { @UnsupportedAppUsage private static Typeface createFromFamiliesWithDefault(FontFamily[] families, String fallbackName, int weight, int italic) { - FontFamily[] fallback = sSystemFallbackMap.get(fallbackName); - if (fallback == null) { - fallback = sSystemFallbackMap.get(DEFAULT_FAMILY); - } + android.graphics.fonts.FontFamily[] fallback = SystemFonts.getSystemFallback(fallbackName); long[] ptrArray = new long[families.length + fallback.length]; for (int i = 0; i < families.length; i++) { ptrArray[i] = families[i].mNativePtr; } for (int i = 0; i < fallback.length; i++) { - ptrArray[i + families.length] = fallback[i].mNativePtr; + ptrArray[i + families.length] = fallback[i].getNativePtr(); } return new Typeface(nativeCreateFromArray(ptrArray, weight, italic)); } @@ -961,191 +972,41 @@ public class Typeface { mWeight = nativeGetWeight(ni); } - private static @Nullable ByteBuffer mmap(String fullPath) { - try (FileInputStream file = new FileInputStream(fullPath)) { - final FileChannel fileChannel = file.getChannel(); - final long fontSize = fileChannel.size(); - return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); - } catch (IOException e) { - Log.e(TAG, "Error mapping font file " + fullPath); - return null; - } - } - - private static @Nullable FontFamily createFontFamily( - String familyName, List<FontConfig.Font> fonts, String[] languageTags, int variant, - Map<String, ByteBuffer> cache, String fontDir) { - final FontFamily family = new FontFamily(languageTags, variant); - for (int i = 0; i < fonts.size(); i++) { - final FontConfig.Font font = fonts.get(i); - final String fullPath = fontDir + font.getFontName(); - ByteBuffer buffer = cache.get(fullPath); - if (buffer == null) { - if (cache.containsKey(fullPath)) { - continue; // Already failed to mmap. Skip it. - } - buffer = mmap(fullPath); - cache.put(fullPath, buffer); - if (buffer == null) { - continue; - } - } - if (!family.addFontFromBuffer(buffer, font.getTtcIndex(), font.getAxes(), - font.getWeight(), font.isItalic() ? STYLE_ITALIC : STYLE_NORMAL)) { - Log.e(TAG, "Error creating font " + fullPath + "#" + font.getTtcIndex()); - } - } - if (!family.freeze()) { - Log.e(TAG, "Unable to load Family: " + familyName + " : " - + Arrays.toString(languageTags)); - return null; - } - return family; + private static Typeface getSystemDefaultTypeface(@NonNull String familyName) { + Typeface tf = sSystemFontMap.get(familyName); + return tf == null ? Typeface.DEFAULT : tf; } - private static void pushFamilyToFallback(FontConfig.Family xmlFamily, - ArrayMap<String, ArrayList<FontFamily>> fallbackMap, - Map<String, ByteBuffer> cache, - String fontDir) { - - final String[] languageTags = xmlFamily.getLanguages(); - final int variant = xmlFamily.getVariant(); - - final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>(); - final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts = new ArrayMap<>(); - - // Collect default fallback and specific fallback fonts. - for (final FontConfig.Font font : xmlFamily.getFonts()) { - final String fallbackName = font.getFallbackFor(); - if (fallbackName == null) { - defaultFonts.add(font); - } else { - ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(fallbackName); - if (fallback == null) { - fallback = new ArrayList<>(); - specificFallbackFonts.put(fallbackName, fallback); - } - fallback.add(font); - } + /** @hide */ + @VisibleForTesting + public static void initSystemDefaultTypefaces(Map<String, Typeface> systemFontMap, + Map<String, android.graphics.fonts.FontFamily[]> fallbacks, + FontConfig.Alias[] aliases) { + for (Map.Entry<String, android.graphics.fonts.FontFamily[]> entry : fallbacks.entrySet()) { + systemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue())); } - final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( - xmlFamily.getName(), defaultFonts, languageTags, variant, cache, fontDir); - - // Insert family into fallback map. - for (int i = 0; i < fallbackMap.size(); i++) { - final ArrayList<FontConfig.Font> fallback = - specificFallbackFonts.get(fallbackMap.keyAt(i)); - if (fallback == null) { - if (defaultFamily != null) { - fallbackMap.valueAt(i).add(defaultFamily); - } - } else { - final FontFamily family = createFontFamily( - xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir); - if (family != null) { - fallbackMap.valueAt(i).add(family); - } else if (defaultFamily != null) { - fallbackMap.valueAt(i).add(defaultFamily); - } else { - // There is no valid for for default fallback. Ignore. - } - } + for (FontConfig.Alias alias : aliases) { + final Typeface base = systemFontMap.get(alias.getToName()); + final int weight = alias.getWeight(); + final Typeface newFace = weight == 400 ? base : + new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); + systemFontMap.put(alias.getName(), newFace); } } - /** - * Build the system fallback from xml file. - * - * @param xmlPath A full path string to the fonts.xml file. - * @param fontDir A full path string to the system font directory. This must end with - * slash('/'). - * @param fontMap An output system font map. Caller must pass empty map. - * @param fallbackMap An output system fallback map. Caller must pass empty map. - * @hide - */ - @VisibleForTesting + // Following methods are left for layoutlib + // TODO: Remove once layoutlib stop calling buildSystemFallback + /** @hide */ public static void buildSystemFallback(String xmlPath, String fontDir, ArrayMap<String, Typeface> fontMap, ArrayMap<String, FontFamily[]> fallbackMap) { - try { - final FileInputStream fontsIn = new FileInputStream(xmlPath); - final FontConfig fontConfig = FontListParser.parse(fontsIn); - - final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>(); - final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies(); - - final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>(); - // First traverse families which have a 'name' attribute to create fallback map. - for (final FontConfig.Family xmlFamily : xmlFamilies) { - final String familyName = xmlFamily.getName(); - if (familyName == null) { - continue; - } - final FontFamily family = createFontFamily( - xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()), - xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir); - if (family == null) { - continue; - } - final ArrayList<FontFamily> fallback = new ArrayList<>(); - fallback.add(family); - fallbackListMap.put(familyName, fallback); - } - - // Then, add fallback fonts to the each fallback map. - for (int i = 0; i < xmlFamilies.length; i++) { - final FontConfig.Family xmlFamily = xmlFamilies[i]; - // The first family (usually the sans-serif family) is always placed immediately - // after the primary family in the fallback. - if (i == 0 || xmlFamily.getName() == null) { - pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir); - } - } - - // Build the font map and fallback map. - for (int i = 0; i < fallbackListMap.size(); i++) { - final String fallbackName = fallbackListMap.keyAt(i); - final List<FontFamily> familyList = fallbackListMap.valueAt(i); - final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]); - - fallbackMap.put(fallbackName, families); - final long[] ptrArray = new long[families.length]; - for (int j = 0; j < families.length; j++) { - ptrArray[j] = families[j].mNativePtr; - } - fontMap.put(fallbackName, new Typeface(nativeCreateFromArray( - ptrArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE))); - } - - // Insert alias to font maps. - for (final FontConfig.Alias alias : fontConfig.getAliases()) { - Typeface base = fontMap.get(alias.getToName()); - Typeface newFace = base; - int weight = alias.getWeight(); - if (weight != 400) { - newFace = new Typeface(nativeCreateWeightAlias(base.native_instance, weight)); - } - fontMap.put(alias.getName(), newFace); - } - } catch (RuntimeException e) { - Log.w(TAG, "Didn't create default family (most likely, non-Minikin build)", e); - // TODO: normal in non-Minikin case, remove or make error when Minikin-only - } catch (FileNotFoundException e) { - Log.e(TAG, "Error opening " + xmlPath, e); - } catch (IOException e) { - Log.e(TAG, "Error reading " + xmlPath, e); - } catch (XmlPullParserException e) { - Log.e(TAG, "XML parse exception for " + xmlPath, e); - } } static { - final ArrayMap<String, Typeface> systemFontMap = new ArrayMap<>(); - final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>(); - buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", systemFontMap, - systemFallbackMap); + final HashMap<String, Typeface> systemFontMap = new HashMap<>(); + initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(), + SystemFonts.getAliases()); sSystemFontMap = Collections.unmodifiableMap(systemFontMap); - sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap); setDefault(sSystemFontMap.get(DEFAULT_FAMILY)); diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java index 74b58ea76b2f..dc213ea56f99 100644 --- a/graphics/java/android/graphics/fonts/FontFamily.java +++ b/graphics/java/android/graphics/fonts/FontFamily.java @@ -18,6 +18,9 @@ package android.graphics.fonts; import android.annotation.IntRange; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.text.FontConfig; +import android.text.TextUtils; import com.android.internal.util.Preconditions; @@ -107,11 +110,25 @@ public class FontFamily { * @return a font family */ public @NonNull FontFamily build() { + return build(null, FontConfig.Family.VARIANT_DEFAULT); + } + + /** @hide */ + public @NonNull FontFamily build(@Nullable String[] langTags, int variant) { final long builderPtr = nInitBuilder(); for (int i = 0; i < mFonts.size(); ++i) { nAddFont(builderPtr, mFonts.get(i).getNativePtr()); } - final long ptr = nBuild(builderPtr); + final String langString; + if (langTags == null || langTags.length == 0) { + langString = null; + } else if (langTags.length == 1) { + langString = langTags[0]; + } else { + langString = TextUtils.join(",", langTags); + } + + final long ptr = nBuild(builderPtr, langString, variant); final FontFamily family = new FontFamily(mFonts, ptr); sFamilyRegistory.registerNativeAllocation(family, ptr); return family; @@ -124,7 +141,7 @@ public class FontFamily { private static native long nInitBuilder(); @CriticalNative private static native void nAddFont(long builderPtr, long fontPtr); - private static native long nBuild(long builderPtr); + private static native long nBuild(long builderPtr, String langTags, int variant); @CriticalNative private static native long nGetReleaseNativeFamily(); } diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java new file mode 100644 index 000000000000..bd49130c11c6 --- /dev/null +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -0,0 +1,260 @@ +/* + * Copyright 2018 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.fonts; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.graphics.FontListParser; +import android.text.FontConfig; +import android.util.ArrayMap; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + +import org.xmlpull.v1.XmlPullParserException; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Provides the system font configurations. + * @hide + */ +public class SystemFonts { + private static final String TAG = "SystemFonts"; + private static final String DEFAULT_FAMILY = "sans-serif"; + + private SystemFonts() {} // Do not instansiate. + + static final Map<String, FontFamily[]> sSystemFallbackMap; + static final FontConfig.Alias[] sAliases; + + /** + * Returns fallback list for the given family name. + * + * If no fallback found for the given family name, returns fallback for the default family. + * + * @param familyName family name, e.g. "serif" + */ + public static @NonNull FontFamily[] getSystemFallback(@Nullable String familyName) { + final FontFamily[] families = sSystemFallbackMap.get(familyName); + return families == null ? sSystemFallbackMap.get(DEFAULT_FAMILY) : families; + } + + /** + * Returns raw system fallback map. + * + * This method is intended to be used only by Typeface static initializer. + */ + public static @NonNull Map<String, FontFamily[]> getRawSystemFallbackMap() { + return sSystemFallbackMap; + } + + /** + * Returns a list of aliases. + * + * This method is intended to be used only by Typeface static initializer. + */ + public static @NonNull FontConfig.Alias[] getAliases() { + return sAliases; + } + + private static @Nullable ByteBuffer mmap(@NonNull String fullPath) { + try (FileInputStream file = new FileInputStream(fullPath)) { + final FileChannel fileChannel = file.getChannel(); + final long fontSize = fileChannel.size(); + return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize); + } catch (IOException e) { + Log.e(TAG, "Error mapping font file " + fullPath); + return null; + } + } + + private static void pushFamilyToFallback(@NonNull FontConfig.Family xmlFamily, + @NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap, + @NonNull Map<String, ByteBuffer> cache, + @NonNull String fontDir) { + + final String[] languageTags = xmlFamily.getLanguages(); + final int variant = xmlFamily.getVariant(); + + final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>(); + final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts = new ArrayMap<>(); + + // Collect default fallback and specific fallback fonts. + for (final FontConfig.Font font : xmlFamily.getFonts()) { + final String fallbackName = font.getFallbackFor(); + if (fallbackName == null) { + defaultFonts.add(font); + } else { + ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(fallbackName); + if (fallback == null) { + fallback = new ArrayList<>(); + specificFallbackFonts.put(fallbackName, fallback); + } + fallback.add(font); + } + } + + final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily( + xmlFamily.getName(), defaultFonts, languageTags, variant, cache, fontDir); + + // Insert family into fallback map. + for (int i = 0; i < fallbackMap.size(); i++) { + final ArrayList<FontConfig.Font> fallback = + specificFallbackFonts.get(fallbackMap.keyAt(i)); + if (fallback == null) { + if (defaultFamily != null) { + fallbackMap.valueAt(i).add(defaultFamily); + } + } else { + final FontFamily family = createFontFamily( + xmlFamily.getName(), fallback, languageTags, variant, cache, fontDir); + if (family != null) { + fallbackMap.valueAt(i).add(family); + } else if (defaultFamily != null) { + fallbackMap.valueAt(i).add(defaultFamily); + } else { + // There is no valid for for default fallback. Ignore. + } + } + } + } + + private static @Nullable FontFamily createFontFamily(@NonNull String familyName, + @NonNull List<FontConfig.Font> fonts, + @NonNull String[] languageTags, + @FontConfig.Family.Variant int variant, + @NonNull Map<String, ByteBuffer> cache, + @NonNull String fontDir) { + if (fonts.size() == 0) { + return null; + } + + FontFamily.Builder b = null; + for (int i = 0; i < fonts.size(); i++) { + final FontConfig.Font fontConfig = fonts.get(i); + final String fullPath = fontDir + fontConfig.getFontName(); + ByteBuffer buffer = cache.get(fullPath); + if (buffer == null) { + if (cache.containsKey(fullPath)) { + continue; // Already failed to mmap. Skip it. + } + buffer = mmap(fullPath); + cache.put(fullPath, buffer); + if (buffer == null) { + continue; + } + } + + final Font font = new Font.Builder(buffer) + .setWeight(fontConfig.getWeight()) + .setItalic(fontConfig.isItalic()) + .setTtcIndex(fontConfig.getTtcIndex()) + .setFontVariationSettings(fontConfig.getAxes()) + .build(); + + if (b == null) { + b = new FontFamily.Builder(font); + } else { + b.addFont(font); + } + } + return b == null ? null : b.build(languageTags, variant); + } + + /** + * Build the system fallback from xml file. + * + * @param xmlPath A full path string to the fonts.xml file. + * @param fontDir A full path string to the system font directory. This must end with + * slash('/'). + * @param fallbackMap An output system fallback map. Caller must pass empty map. + * @return a list of aliases + * @hide + */ + @VisibleForTesting + public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath, + @NonNull String fontDir, + @NonNull ArrayMap<String, FontFamily[]> fallbackMap) { + try { + final FileInputStream fontsIn = new FileInputStream(xmlPath); + final FontConfig fontConfig = FontListParser.parse(fontsIn); + + final HashMap<String, ByteBuffer> bufferCache = new HashMap<String, ByteBuffer>(); + final FontConfig.Family[] xmlFamilies = fontConfig.getFamilies(); + + final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>(); + // First traverse families which have a 'name' attribute to create fallback map. + for (final FontConfig.Family xmlFamily : xmlFamilies) { + final String familyName = xmlFamily.getName(); + if (familyName == null) { + continue; + } + final FontFamily family = createFontFamily( + xmlFamily.getName(), Arrays.asList(xmlFamily.getFonts()), + xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache, fontDir); + if (family == null) { + continue; + } + final ArrayList<FontFamily> fallback = new ArrayList<>(); + fallback.add(family); + fallbackListMap.put(familyName, fallback); + } + + // Then, add fallback fonts to the each fallback map. + for (int i = 0; i < xmlFamilies.length; i++) { + final FontConfig.Family xmlFamily = xmlFamilies[i]; + // The first family (usually the sans-serif family) is always placed immediately + // after the primary family in the fallback. + if (i == 0 || xmlFamily.getName() == null) { + pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache, fontDir); + } + } + + // Build the font map and fallback map. + for (int i = 0; i < fallbackListMap.size(); i++) { + final String fallbackName = fallbackListMap.keyAt(i); + final List<FontFamily> familyList = fallbackListMap.valueAt(i); + final FontFamily[] families = familyList.toArray(new FontFamily[familyList.size()]); + + fallbackMap.put(fallbackName, families); + } + + return fontConfig.getAliases(); + } catch (IOException | XmlPullParserException e) { + Log.e(TAG, "Failed initialize system fallbacks.", e); + return null; + } + } + + static { + final ArrayMap<String, FontFamily[]> systemFallbackMap = new ArrayMap<>(); + sAliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", + systemFallbackMap); + sSystemFallbackMap = Collections.unmodifiableMap(systemFallbackMap); + } + +} |