summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2021-01-20 04:18:20 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-01-20 04:18:20 +0000
commit903dc9269f78153202339c9728c50f477bacae2e (patch)
tree97bf075ae3a2311651379383d731b8c2292e3b2e
parent121f5679a863ccb301a05380e0061454fed3e123 (diff)
parentf5859819cdbfe5e3e7f3eefbe4530ca3170f542d (diff)
Merge "Refactor font parser for making SystemApi."
-rw-r--r--core/java/android/text/FontConfig.java330
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java134
-rw-r--r--core/tests/coretests/src/android/graphics/TypefaceTest.java10
-rw-r--r--core/tests/coretests/src/android/text/FontFallbackSetup.java23
-rw-r--r--graphics/java/android/graphics/FontListParser.java137
-rw-r--r--graphics/java/android/graphics/Typeface.java34
-rw-r--r--graphics/java/android/graphics/fonts/FontCustomizationParser.java81
-rw-r--r--graphics/java/android/graphics/fonts/FontFamily.java26
-rw-r--r--graphics/java/android/graphics/fonts/SystemFonts.java223
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerService.java113
10 files changed, 715 insertions, 396 deletions
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 1878d61c78ac..8492363eb503 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -19,171 +19,268 @@ package android.text;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
-import android.net.Uri;
import android.os.Build;
+import android.os.LocaleList;
+import java.io.File;
import java.lang.annotation.Retention;
+import java.util.List;
/**
* Font configuration descriptions for System fonts.
- * @hide
+ * @hide // TODO Make this SystemApi.
*/
public final class FontConfig {
- private final @NonNull Family[] mFamilies;
- private final @NonNull Alias[] mAliases;
+ private final @NonNull List<Family> mFamilies;
+ private final @NonNull List<Alias> mAliases;
- public FontConfig(@NonNull Family[] families, @NonNull Alias[] aliases) {
+ /**
+ * Construct a SystemFontConfig instance.
+ *
+ * @param families a list of font families.
+ * @param aliases a list of aliases.
+ *
+ * @hide Only system server can create this instance and passed via IPC.
+ */
+ public FontConfig(@NonNull List<Family> families, @NonNull List<Alias> aliases) {
mFamilies = families;
mAliases = aliases;
}
/**
* Returns the ordered list of families included in the system fonts.
+ *
+ * @return a list of font families.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public @NonNull Family[] getFamilies() {
+ public @NonNull List<Family> getFontFamilies() {
return mFamilies;
}
/**
* Returns the list of aliases defined for the font families in the system fonts.
+ *
+ * @return a list of font families.
*/
- public @NonNull Alias[] getAliases() {
+ public @NonNull List<Alias> getAliases() {
return mAliases;
}
/**
- * Class that holds information about a Font.
+ * Returns the ordered list of families included in the system fonts.
+ * @deprecated Use getFontFamilies instead.
+ */
+ @Deprecated
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ public @NonNull Family[] getFamilies() {
+ return mFamilies.toArray(new Family[0]);
+ }
+
+ /**
+ * A class represents single font entry in system font configuration.
*/
public static final class Font {
- private final @NonNull String mFontName;
- private final int mTtcIndex;
- private final @NonNull FontVariationAxis[] mAxes;
- private final int mWeight;
- private final boolean mIsItalic;
- private Uri mUri;
- private final String mFallbackFor;
+ private final @NonNull File mFilePath;
+ private final @Nullable File mOriginalPath;
+ private final @NonNull FontStyle mStyle;
+ private final @IntRange(from = 0) int mIndex;
+ private final @NonNull String mFontVariationSettings;
+ private final @Nullable String mFallback;
/**
- * @hide
+ * Construct a Font instance.
+ *
+ * @hide Only system server can create this instance and passed via IPC.
*/
- public Font(@NonNull String fontName, int ttcIndex, @NonNull FontVariationAxis[] axes,
- int weight, boolean isItalic, String fallbackFor) {
- mFontName = fontName;
- mTtcIndex = ttcIndex;
- mAxes = axes;
- mWeight = weight;
- mIsItalic = isItalic;
- mFallbackFor = fallbackFor;
+ public Font(@NonNull File filePath, @Nullable File originalPath, @NonNull FontStyle style,
+ @IntRange(from = 0) int index, @NonNull String fontVariationSettings,
+ @Nullable String fallback) {
+ mFilePath = filePath;
+ mOriginalPath = originalPath;
+ mStyle = style;
+ mIndex = index;
+ mFontVariationSettings = fontVariationSettings;
+ mFallback = fallback;
+ }
+
+ /**
+ * Returns a file to the font file.
+ *
+ * @return a font file.
+ */
+ public @NonNull File getFilePath() {
+ return mFilePath;
+ }
+
+ /**
+ * Returns an original font file in the system directory.
+ *
+ * If the font file is not updated, returns null.
+ *
+ * @return returns the original font file in the system if the font file is updated. Returns
+ * null if the font file is not updated.
+ */
+ public @Nullable File getOriginalPath() {
+ return mOriginalPath;
+ }
+
+ /**
+ * Returns a font style.
+ *
+ * @return a font style.
+ */
+ public @NonNull FontStyle getStyle() {
+ return mStyle;
+ }
+
+ /**
+ * Returns a font index.
+ *
+ * @return a font index.
+ */
+ public @IntRange(from = 0) int getIndex() {
+ return mIndex;
}
/**
- * Returns the name associated by the system to this font.
+ * Return a font variation settings.
+ *
+ * @return a font variation settings.
*/
- public @NonNull String getFontName() {
- return mFontName;
+ public @NonNull String getFontVariationSettings() {
+ return mFontVariationSettings;
+ }
+
+ /**
+ * Returns font family name that uses this font as a fallback.
+ *
+ * If this font is a fallback for the default font family, this is null.
+ *
+ * @return a font family name.
+ */
+ public @Nullable String getFallback() {
+ return mFallback;
}
/**
* Returns the index to be used to access this font when accessing a TTC file.
+ * @deprecated Use getIndex instead.
+ * @hide
*/
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int getTtcIndex() {
- return mTtcIndex;
+ return mIndex;
}
/**
* Returns the list of axes associated to this font.
+ * @deprecated Use getFontVariationSettings
+ * @hide
*/
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public @NonNull FontVariationAxis[] getAxes() {
- return mAxes;
+ return FontVariationAxis.fromFontVariationSettings(mFontVariationSettings);
}
/**
* Returns the weight value for this font.
+ * @deprecated Use getStyle instead.
+ * @hide
*/
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int getWeight() {
- return mWeight;
+ return getStyle().getWeight();
}
/**
* Returns whether this font is italic.
+ * @deprecated Use getStyle instead.
+ * @hide
*/
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isItalic() {
- return mIsItalic;
- }
-
- /**
- * Returns the content uri associated to this font.
- *
- * You can reach to the font contents by calling {@link
- * android.content.ContentResolver#openInputStream}.
- */
- public @Nullable Uri getUri() {
- return mUri;
- }
-
- public void setUri(@NonNull Uri uri) {
- mUri = uri;
- }
-
- public String getFallbackFor() {
- return mFallbackFor;
+ return getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC;
}
}
/**
- * Class that holds information about a Font alias.
+ * A class represents alias between named font families.
+ *
+ * In the system font configuration, an font family can be an alias of another font family with
+ * different font weight. For example, "sans-serif-medium" can be a medium weight of
+ * sans-serif font family.
*/
public static final class Alias {
- private final @NonNull String mName;
- private final @NonNull String mToName;
- private final int mWeight;
+ private final @NonNull String mAliasName;
+ private final @NonNull String mReferName;
+ private final @IntRange(from = 0, to = 1000) int mWeight;
- public Alias(@NonNull String name, @NonNull String toName, int weight) {
- mName = name;
- mToName = toName;
+ /**
+ * Construct an alias instance.
+ *
+ * @param aliasName an alias of the named font family.
+ * @param referName a referring font family name.
+ * @param weight a font weight of the referring font family.
+ * @hide Only system server can create this instance and passed via IPC.
+ */
+ public Alias(@NonNull String aliasName, @NonNull String referName,
+ @IntRange(from = 0, to = 1000) int weight) {
+ mAliasName = aliasName;
+ mReferName = referName;
mWeight = weight;
}
/**
- * Returns the new name for the alias.
+ * An alias of the named font family.
+ *
+ * @return an alias of the named font family.
*/
- public @NonNull String getName() {
- return mName;
+ public @NonNull String getAliasName() {
+ return mAliasName;
}
/**
- * Returns the existing name to which this alias points to.
+ * A name of font family referring from {@link #getAliasName()}
+ *
+ * @return a referring font family name.
*/
- public @NonNull String getToName() {
- return mToName;
+ public @NonNull String getReferName() {
+ return mReferName;
}
/**
- * Returns the weight associated with this alias.
+ * A font weight of the referring font family.
+ *
+ * @return a font weight of the referring font family.
*/
- public int getWeight() {
+ public @IntRange(from = 0, to = 1000) int getWeight() {
return mWeight;
}
}
/**
- * Class that holds information about a Font family.
+ * A class represents single font family entry in system font configuration.
+ *
+ * <p>
+ * A font family is a bundle of fonts for drawing text in various styles.
+ * For example, regular style font and bold style font can be bundled into a single font family,
+ * then system will select the correct style font from family for drawing.
*/
public static final class Family {
- private final @NonNull String mName;
- private final @NonNull Font[] mFonts;
- // Comma separated BCP47 complient locale strings
- private final @NonNull String mLanguages;
+ private final @NonNull List<Font> mFonts;
+ private final @Nullable String mName;
+ private final @Nullable LocaleList mLocaleList;
+ private final @Variant int mVariant;
/** @hide */
@Retention(SOURCE)
@@ -212,52 +309,105 @@ public final class FontConfig {
/**
* Value for font variant.
*
- * Indiates the font is for elegant variant.
+ * Indicates the font is for elegant variant.
* @see android.graphics.Paint#setElegantTextHeight
*/
public static final int VARIANT_ELEGANT = 2;
- // Must be same with Minikin's variant values.
- // See frameworks/minikin/include/minikin/FontFamily.h
- private final @Variant int mVariant;
-
- public Family(@NonNull String name, @NonNull Font[] fonts, @NonNull String languages,
- @Variant int variant) {
- mName = name;
+ /**
+ * Construct a family instance.
+ *
+ * @hide Only system server can create this instance and passed via IPC.
+ */
+ public Family(@NonNull List<Font> fonts, @Nullable String name,
+ @Nullable LocaleList localeList, @Variant int variant) {
mFonts = fonts;
- mLanguages = languages;
+ mName = name;
+ mLocaleList = localeList;
mVariant = variant;
}
/**
- * Returns the name given by the system to this font family.
+ * Returns a list of font files in this family.
+ *
+ * @return a list of font files.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public @Nullable String getName() {
+ public @NonNull List<Font> getFontList() {
+ return mFonts;
+ }
+
+ /**
+ * Returns a family name if this family defines a new fallback.
+ *
+ * @return non-null if a family name is associated. Otherwise null.
+ */
+ public @Nullable String getFallbackName() {
return mName;
}
/**
- * Returns the list of fonts included in this family.
+ * Returns a locale list if associated.
+ *
+ * @return non-null if a locale list is associated. Otherwise null.
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public @Nullable Font[] getFonts() {
- return mFonts;
+ public @NonNull LocaleList getLocaleList() {
+ return mLocaleList;
}
/**
- * Returns the comma separated BCP47 complient languages for this family. May be null.
+ * Returns a text height variant.
+ *
+ * @return text height variant.
*/
- public @NonNull String getLanguages() {
- return mLanguages;
+ public @Variant int getTextHeightVariant() {
+ return mVariant;
}
/**
- * Returns the font variant for this family, e.g. "elegant" or "compact". May be null.
+ * Returns a family variant associated.
+ *
+ * @return a family variant.
+ * @deprecated Use getTextHeightVariant instead.
+ * @hide
*/
+ @Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public @Variant int getVariant() {
return mVariant;
}
+
+ /**
+ * Returns a family name if associated.
+ *
+ * @return non-null if a family name is associated. Otherwise null.
+ * @deprecated Use getFallbackName instead.
+ * @hide
+ */
+ @Deprecated
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ public @Nullable String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the list of fonts included in this family.
+ * @deprecated Use getFontFiles instead
+ * @hide
+ */
+ @Deprecated
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ public @Nullable Font[] getFonts() {
+ return mFonts.toArray(new Font[0]);
+ }
+
+ /**
+ * Returns the comma separated BCP47 compliant languages for this family. May be null.
+ * @deprecated Use getLocaleList instead
+ * @hide
+ */
+ @Deprecated
+ public @NonNull String getLanguages() {
+ return mLocaleList.toLanguageTags();
+ }
}
}
diff --git a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
index 465ea172b1c0..65ea2a8373aa 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceSystemFallbackTest.java
@@ -21,6 +21,8 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.fonts.FontCustomizationParser;
@@ -44,7 +46,6 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
@@ -139,27 +140,55 @@ public class TypefaceSystemFallbackTest {
}
}
- private static void buildSystemFallback(String xml,
- FontCustomizationParser.Result oemCustomization, ArrayMap<String, Typeface> fontMap,
- ArrayMap<String, FontFamily[]> fallbackMap) {
+ private static void buildSystemFallback(
+ @NonNull String xml,
+ @Nullable String oemXml,
+ @NonNull ArrayMap<String, Typeface> outFontMap,
+ @NonNull ArrayMap<String, FontFamily[]> outFallbackMap) {
try (FileOutputStream fos = new FileOutputStream(TEST_FONTS_XML)) {
- fos.write(xml.getBytes(Charset.forName("UTF-8")));
+ fos.write(xml.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new RuntimeException(e);
}
+
+ String oemXmlPath;
+ if (oemXml != null) {
+ try (FileOutputStream fos = new FileOutputStream(TEST_OEM_XML)) {
+ fos.write(oemXml.getBytes(StandardCharsets.UTF_8));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ oemXmlPath = TEST_OEM_XML;
+ } else {
+ oemXmlPath = null;
+ }
+
Map<String, File> updatableFontMap = new HashMap<>();
for (File file : new File(TEST_UPDATABLE_FONT_DIR).listFiles()) {
updatableFontMap.put(file.getName(), file);
}
- final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(TEST_FONTS_XML,
- TEST_FONT_DIR, updatableFontMap, oemCustomization, fallbackMap);
- Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
+ FontConfig fontConfig;
+ try {
+ fontConfig = FontListParser.parse(
+ TEST_FONTS_XML, TEST_FONT_DIR, oemXmlPath, TEST_OEM_DIR, updatableFontMap);
+ } catch (IOException | XmlPullParserException e) {
+ throw new RuntimeException(e);
+ }
+
+ Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
+ Map<String, Typeface> typefaceMap = SystemFonts.buildSystemTypefaces(
+ fontConfig, fallbackMap);
+
+ outFontMap.clear();
+ outFontMap.putAll(typefaceMap);
+ outFallbackMap.clear();
+ outFallbackMap.putAll(fallbackMap);
}
private static FontCustomizationParser.Result readFontCustomization(String oemXml) {
try (InputStream is = new ByteArrayInputStream(oemXml.getBytes(StandardCharsets.UTF_8))) {
- return FontCustomizationParser.parse(is, TEST_OEM_DIR);
+ return FontCustomizationParser.parse(is, TEST_OEM_DIR, null);
} catch (IOException | XmlPullParserException e) {
throw new RuntimeException(e);
}
@@ -167,19 +196,22 @@ public class TypefaceSystemFallbackTest {
@Test
public void testBuildSystemFallback() {
- final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
- final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
-
- final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(SYSTEM_FONTS_XML,
- SYSTEM_FONT_DIR, oemCustomization, fallbackMap);
+ FontConfig fontConfig;
+ try {
+ fontConfig = FontListParser.parse(
+ SYSTEM_FONTS_XML, SYSTEM_FONT_DIR, null, TEST_OEM_DIR, null);
+ } catch (IOException | XmlPullParserException e) {
+ throw new RuntimeException(e);
+ }
+ assertFalse(fontConfig.getAliases().isEmpty());
+ assertFalse(fontConfig.getFontFamilies().isEmpty());
- assertNotNull(aliases);
+ Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
assertFalse(fallbackMap.isEmpty());
- Typeface.initSystemDefaultTypefaces(fontMap, fallbackMap, aliases);
- assertFalse(fontMap.isEmpty());
+ Map<String, Typeface> typefaceMap = SystemFonts.buildSystemTypefaces(
+ fontConfig, fallbackMap);
+ assertFalse(typefaceMap.isEmpty());
}
@Test
@@ -199,10 +231,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
assertEquals(1, fontMap.size());
assertTrue(fontMap.containsKey("sans-serif"));
@@ -229,10 +259,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -277,10 +305,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -324,10 +350,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -376,10 +400,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -424,10 +446,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -465,10 +485,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -506,10 +524,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -556,10 +572,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
paint.setTypeface(fontMap.get("sans-serif"));
@@ -600,10 +614,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -641,10 +653,8 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -679,10 +689,8 @@ public class TypefaceSystemFallbackTest {
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- readFontCustomization(oemXml);
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -717,10 +725,8 @@ public class TypefaceSystemFallbackTest {
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- readFontCustomization(oemXml);
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -751,10 +757,8 @@ public class TypefaceSystemFallbackTest {
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- readFontCustomization(oemXml);
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -804,10 +808,8 @@ public class TypefaceSystemFallbackTest {
+ "</fonts-modification>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- readFontCustomization(oemXml);
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, oemXml, fontMap, fallbackMap);
final Paint paint = new Paint();
@@ -862,12 +864,10 @@ public class TypefaceSystemFallbackTest {
+ "</familyset>";
final ArrayMap<String, Typeface> fontMap = new ArrayMap<>();
final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
// Install all2em.ttf as a3em.ttf
copyAssetToFile("fonts/all2em.ttf", new File(TEST_UPDATABLE_FONT_DIR, "a3em.ttf"));
- buildSystemFallback(xml, oemCustomization, fontMap, fallbackMap);
+ buildSystemFallback(xml, null, fontMap, fallbackMap);
final Paint paint = new Paint();
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index 392c6b7199a5..d12f495055e1 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -27,7 +27,6 @@ import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
import android.os.SharedMemory;
import android.text.FontConfig;
-import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -41,7 +40,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.ByteOrder;
-import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@@ -197,10 +195,10 @@ public class TypefaceTest {
@SmallTest
@Test
public void testSerialize() throws Exception {
- HashMap<String, Typeface> systemFontMap = new HashMap<>();
- Pair<FontConfig.Alias[], Map<String, FontFamily[]>> res =
- SystemFonts.initializePreinstalledFonts();
- Typeface.initSystemDefaultTypefaces(systemFontMap, res.second, res.first);
+ FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
+ Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
+ Map<String, Typeface> systemFontMap = SystemFonts.buildSystemTypefaces(fontConfig,
+ fallbackMap);
SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
Map<String, Typeface> copiedFontMap =
Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN));
diff --git a/core/tests/coretests/src/android/text/FontFallbackSetup.java b/core/tests/coretests/src/android/text/FontFallbackSetup.java
index 64e6f82d82af..e301037d01f1 100644
--- a/core/tests/coretests/src/android/text/FontFallbackSetup.java
+++ b/core/tests/coretests/src/android/text/FontFallbackSetup.java
@@ -19,14 +19,15 @@ package android.text;
import android.annotation.NonNull;
import android.content.Context;
import android.content.res.AssetManager;
+import android.graphics.FontListParser;
import android.graphics.Typeface;
-import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.SystemFonts;
-import android.util.ArrayMap;
import androidx.test.InstrumentationRegistry;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -34,12 +35,13 @@ import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
+import java.util.Map;
public class FontFallbackSetup implements AutoCloseable {
private final String[] mTestFontFiles;
private final String mXml;
private final String mTestFontsDir;
- final ArrayMap<String, Typeface> mFontMap = new ArrayMap<>();
+ private final Map<String, Typeface> mFontMap;
public FontFallbackSetup(@NonNull String testSubDir, @NonNull String[] testFontFiles,
@NonNull String xml) {
@@ -75,12 +77,15 @@ public class FontFallbackSetup implements AutoCloseable {
throw new RuntimeException(e);
}
- final ArrayMap<String, FontFamily[]> fallbackMap = new ArrayMap<>();
- final FontCustomizationParser.Result oemCustomization =
- new FontCustomizationParser.Result();
- final FontConfig.Alias[] aliases = SystemFonts.buildSystemFallback(testFontsXml,
- mTestFontsDir, oemCustomization, fallbackMap);
- Typeface.initSystemDefaultTypefaces(mFontMap, fallbackMap, aliases);
+ FontConfig fontConfig;
+ try {
+ fontConfig = FontListParser.parse(testFontsXml, mTestFontsDir, null, null, null);
+ } catch (IOException | XmlPullParserException e) {
+ throw new RuntimeException(e);
+ }
+
+ Map<String, FontFamily[]> fallbackMap = SystemFonts.buildSystemFallback(fontConfig);
+ mFontMap = SystemFonts.buildSystemTypefaces(fontConfig, fallbackMap);
}
@NonNull
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index af100c96f6f5..ff381176e38d 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,10 +16,14 @@
package android.graphics;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.fonts.FontCustomizationParser;
+import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
+import android.os.LocaleList;
import android.text.FontConfig;
import android.util.Xml;
@@ -27,6 +31,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -36,7 +41,6 @@ import java.util.regex.Pattern;
/**
* Parser for font config files.
- *
* @hide
*/
public class FontListParser {
@@ -44,49 +48,89 @@ public class FontListParser {
/* Parse fallback list (no names) */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static FontConfig parse(InputStream in) throws XmlPullParserException, IOException {
- return parse(in, "/system/fonts", null);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readFamilies(parser, "/system/fonts/", new FontCustomizationParser.Result(), null);
}
/**
- * Parse the fonts.xml
+ * Parses system font config XMLs
+ *
+ * @param fontsXmlPath location of fonts.xml
+ * @param systemFontDir location of system font directory
+ * @param oemCustomizationXmlPath location of oem_customization.xml
+ * @param productFontDir location of oem customized font directory
+ * @param updatableFontMap map of updated font files.
+ * @return font configuration
+ * @throws IOException
+ * @throws XmlPullParserException
*/
- public static FontConfig parse(InputStream in, String fontDir,
- @Nullable Map<String, File> updatableFontMap)
- throws XmlPullParserException, IOException {
- try {
+ public static FontConfig parse(
+ @NonNull String fontsXmlPath,
+ @NonNull String systemFontDir,
+ @Nullable String oemCustomizationXmlPath,
+ @Nullable String productFontDir,
+ @Nullable Map<String, File> updatableFontMap
+ ) throws IOException, XmlPullParserException {
+ FontCustomizationParser.Result oemCustomization;
+ if (oemCustomizationXmlPath != null) {
+ try (InputStream is = new FileInputStream(oemCustomizationXmlPath)) {
+ oemCustomization = FontCustomizationParser.parse(is, productFontDir,
+ updatableFontMap);
+ } catch (IOException e) {
+ // OEM customization may not exists. Ignoring
+ oemCustomization = new FontCustomizationParser.Result();
+ }
+ } else {
+ oemCustomization = new FontCustomizationParser.Result();
+ }
+
+ try (InputStream is = new FileInputStream(fontsXmlPath)) {
XmlPullParser parser = Xml.newPullParser();
- parser.setInput(in, null);
+ parser.setInput(is, null);
parser.nextTag();
- return readFamilies(parser, fontDir, updatableFontMap);
- } finally {
- in.close();
+ return readFamilies(parser, systemFontDir, oemCustomization, updatableFontMap);
}
}
- private static FontConfig readFamilies(XmlPullParser parser, String fontDir,
+ private static FontConfig readFamilies(
+ @NonNull XmlPullParser parser,
+ @NonNull String fontDir,
+ @NonNull FontCustomizationParser.Result customization,
@Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
List<FontConfig.Family> families = new ArrayList<>();
- List<FontConfig.Alias> aliases = new ArrayList<>();
+ List<FontConfig.Alias> aliases = new ArrayList<>(customization.getAdditionalAliases());
+
+ Map<String, FontConfig.Family> oemNamedFamilies =
+ customization.getAdditionalNamedFamilies();
parser.require(XmlPullParser.START_TAG, null, "familyset");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (tag.equals("family")) {
- families.add(readFamily(parser, fontDir, updatableFontMap));
+ FontConfig.Family family = readFamily(parser, fontDir, updatableFontMap);
+ String name = family.getFallbackName();
+ if (name == null || !oemNamedFamilies.containsKey(name)) {
+ // The OEM customization overrides system named family. Skip if OEM
+ // customization XML defines the same named family.
+ families.add(family);
+ }
} else if (tag.equals("alias")) {
aliases.add(readAlias(parser));
} else {
skip(parser);
}
}
- return new FontConfig(families.toArray(new FontConfig.Family[families.size()]),
- aliases.toArray(new FontConfig.Alias[aliases.size()]));
+
+ families.addAll(oemNamedFamilies.values());
+ return new FontConfig(families, aliases);
}
/**
- * Reads a family element
+ * Read family tag in fonts.xml or oem_customization.xml
*/
public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir,
@Nullable Map<String, File> updatableFontMap)
@@ -94,7 +138,7 @@ public class FontListParser {
final String name = parser.getAttributeValue(null, "name");
final String lang = parser.getAttributeValue("", "lang");
final String variant = parser.getAttributeValue(null, "variant");
- final List<FontConfig.Font> fonts = new ArrayList<FontConfig.Font>();
+ final List<FontConfig.Font> fonts = new ArrayList<>();
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
final String tag = parser.getName();
@@ -112,20 +156,22 @@ public class FontListParser {
intVariant = FontConfig.Family.VARIANT_ELEGANT;
}
}
- return new FontConfig.Family(name, fonts.toArray(new FontConfig.Font[fonts.size()]), lang,
- intVariant);
+ return new FontConfig.Family(fonts, name, LocaleList.forLanguageTags(lang), intVariant);
}
/** Matches leading and trailing XML whitespace. */
private static final Pattern FILENAME_WHITESPACE_PATTERN =
Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$");
- private static FontConfig.Font readFont(XmlPullParser parser, String fontDir,
+ private static FontConfig.Font readFont(
+ @NonNull XmlPullParser parser,
+ @NonNull String fontDir,
@Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
+
String indexStr = parser.getAttributeValue(null, "index");
int index = indexStr == null ? 0 : Integer.parseInt(indexStr);
- List<FontVariationAxis> axes = new ArrayList<FontVariationAxis>();
+ List<FontVariationAxis> axes = new ArrayList<>();
String weightStr = parser.getAttributeValue(null, "weight");
int weight = weightStr == null ? 400 : Integer.parseInt(weightStr);
boolean isItalic = "italic".equals(parser.getAttributeValue(null, "style"));
@@ -144,12 +190,37 @@ public class FontListParser {
}
}
String sanitizedName = FILENAME_WHITESPACE_PATTERN.matcher(filename).replaceAll("");
- String fontName = findFontFile(sanitizedName, fontDir, updatableFontMap);
- return new FontConfig.Font(fontName, index, axes.toArray(
- new FontVariationAxis[axes.size()]), weight, isItalic, fallbackFor);
+ String updatedName = findUpdatedFontFile(sanitizedName, updatableFontMap);
+ String filePath;
+ String originalPath;
+ if (updatedName != null) {
+ filePath = updatedName;
+ originalPath = fontDir + sanitizedName;
+ } else {
+ filePath = fontDir + sanitizedName;
+ originalPath = null;
+ }
+
+ String varSettings;
+ if (axes.isEmpty()) {
+ varSettings = "";
+ } else {
+ varSettings = FontVariationAxis.toFontVariationSettings(
+ axes.toArray(new FontVariationAxis[0]));
+ }
+
+ return new FontConfig.Font(new File(filePath),
+ originalPath == null ? null : new File(originalPath),
+ new FontStyle(
+ weight,
+ isItalic ? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT
+ ),
+ index,
+ varSettings,
+ fallbackFor);
}
- private static String findFontFile(String name, String fontDir,
+ private static String findUpdatedFontFile(String name,
@Nullable Map<String, File> updatableFontMap) {
if (updatableFontMap != null) {
File updatedFile = updatableFontMap.get(name);
@@ -157,7 +228,7 @@ public class FontListParser {
return updatedFile.getAbsolutePath();
}
}
- return fontDir + name;
+ return null;
}
private static FontVariationAxis readAxis(XmlPullParser parser)
@@ -193,12 +264,12 @@ public class FontListParser {
int depth = 1;
while (depth > 0) {
switch (parser.next()) {
- case XmlPullParser.START_TAG:
- depth++;
- break;
- case XmlPullParser.END_TAG:
- depth--;
- break;
+ 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 48b474d6322e..f1866cdceae7 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -45,7 +45,6 @@ import android.text.FontConfig;
import android.util.Base64;
import android.util.LongSparseArray;
import android.util.LruCache;
-import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -197,7 +196,11 @@ public class Typeface {
// Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
/** @hide */
public static final int RESOLVE_BY_FONT_TABLE = -1;
- private static final String DEFAULT_FAMILY = "sans-serif";
+ /**
+ * The key of the default font family.
+ * @hide
+ */
+ public static final String DEFAULT_FAMILY = "sans-serif";
// Style value for building typeface.
private static final int STYLE_NORMAL = 0;
@@ -1139,18 +1142,19 @@ public class Typeface {
/** @hide */
@VisibleForTesting
- public static void initSystemDefaultTypefaces(Map<String, Typeface> systemFontMap,
- Map<String, FontFamily[]> fallbacks,
- FontConfig.Alias[] aliases) {
+ public static void initSystemDefaultTypefaces(Map<String, FontFamily[]> fallbacks,
+ List<FontConfig.Alias> aliases,
+ Map<String, Typeface> outSystemFontMap) {
for (Map.Entry<String, FontFamily[]> entry : fallbacks.entrySet()) {
- systemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue()));
+ outSystemFontMap.put(entry.getKey(), createFromFamilies(entry.getValue()));
}
- for (FontConfig.Alias alias : aliases) {
- if (systemFontMap.containsKey(alias.getName())) {
+ for (int i = 0; i < aliases.size(); ++i) {
+ final FontConfig.Alias alias = aliases.get(i);
+ if (outSystemFontMap.containsKey(alias.getAliasName())) {
continue; // If alias and named family are conflict, use named family.
}
- final Typeface base = systemFontMap.get(alias.getToName());
+ final Typeface base = outSystemFontMap.get(alias.getReferName());
if (base == null) {
// The missing target is a valid thing, some configuration don't have font files,
// e.g. wear devices. Just skip this alias.
@@ -1159,7 +1163,7 @@ public class Typeface {
final int weight = alias.getWeight();
final Typeface newFace = weight == 400 ? base :
new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
- systemFontMap.put(alias.getName(), newFace);
+ outSystemFontMap.put(alias.getAliasName(), newFace);
}
}
@@ -1339,11 +1343,11 @@ public class Typeface {
/** @hide */
public static void loadPreinstalledSystemFontMap() {
- final HashMap<String, Typeface> systemFontMap = new HashMap<>();
- Pair<FontConfig.Alias[], Map<String, FontFamily[]>> pair =
- SystemFonts.initializePreinstalledFonts();
- initSystemDefaultTypefaces(systemFontMap, pair.second, pair.first);
- setSystemFontMap(systemFontMap);
+ final FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
+ final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
+ final Map<String, Typeface> typefaceMap =
+ SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+ setSystemFontMap(typefaceMap);
}
static {
diff --git a/graphics/java/android/graphics/fonts/FontCustomizationParser.java b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
index f95da82ee07c..1ad6fbe264cb 100644
--- a/graphics/java/android/graphics/fonts/FontCustomizationParser.java
+++ b/graphics/java/android/graphics/fonts/FontCustomizationParser.java
@@ -16,18 +16,25 @@
package android.graphics.fonts;
+import static android.text.FontConfig.Alias;
+import static android.text.FontConfig.Family;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.FontListParser;
-import android.text.FontConfig;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* Parser for font customization
@@ -39,8 +46,27 @@ public class FontCustomizationParser {
* Represents a customization XML
*/
public static class Result {
- ArrayList<FontConfig.Family> mAdditionalNamedFamilies = new ArrayList<>();
- ArrayList<FontConfig.Alias> mAdditionalAliases = new ArrayList<>();
+ private final Map<String, Family> mAdditionalNamedFamilies;
+ private final List<Alias> mAdditionalAliases;
+
+ public Result() {
+ mAdditionalNamedFamilies = Collections.emptyMap();
+ mAdditionalAliases = Collections.emptyList();
+ }
+
+ public Result(Map<String, Family> additionalNamedFamilies,
+ List<Alias> additionalAliases) {
+ mAdditionalNamedFamilies = additionalNamedFamilies;
+ mAdditionalAliases = additionalAliases;
+ }
+
+ public Map<String, Family> getAdditionalNamedFamilies() {
+ return mAdditionalNamedFamilies;
+ }
+
+ public List<Alias> getAdditionalAliases() {
+ return mAdditionalAliases;
+ }
}
/**
@@ -48,56 +74,67 @@ public class FontCustomizationParser {
*
* Caller must close the input stream
*/
- public static Result parse(@NonNull InputStream in, @NonNull String fontDir)
- throws XmlPullParserException, IOException {
+ public static Result parse(
+ @NonNull InputStream in,
+ @NonNull String fontDir,
+ @Nullable Map<String, File> updatableFontMap
+ ) throws XmlPullParserException, IOException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, null);
parser.nextTag();
- return readFamilies(parser, fontDir);
+ return readFamilies(parser, fontDir, updatableFontMap);
}
- private static void validate(Result result) {
- HashSet<String> familyNames = new HashSet<>();
- for (int i = 0; i < result.mAdditionalNamedFamilies.size(); ++i) {
- final FontConfig.Family family = result.mAdditionalNamedFamilies.get(i);
- final String name = family.getName();
+ private static Map<String, Family> validateAndTransformToMap(List<Family> families) {
+ HashMap<String, Family> namedFamily = new HashMap<>();
+ for (int i = 0; i < families.size(); ++i) {
+ final Family family = families.get(i);
+ final String name = family.getFallbackName();
if (name == null) {
throw new IllegalArgumentException("new-named-family requires name attribute");
}
- if (!familyNames.add(name)) {
+ if (namedFamily.put(name, family) != null) {
throw new IllegalArgumentException(
"new-named-family requires unique name attribute");
}
}
+ return namedFamily;
}
- private static Result readFamilies(XmlPullParser parser, String fontDir)
- throws XmlPullParserException, IOException {
- Result out = new Result();
+ private static Result readFamilies(
+ @NonNull XmlPullParser parser,
+ @NonNull String fontDir,
+ @Nullable Map<String, File> updatableFontMap
+ ) throws XmlPullParserException, IOException {
+ List<Family> families = new ArrayList<>();
+ List<Alias> aliases = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, null, "fonts-modification");
while (parser.next() != XmlPullParser.END_TAG) {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (tag.equals("family")) {
- readFamily(parser, fontDir, out);
+ readFamily(parser, fontDir, families, updatableFontMap);
} else if (tag.equals("alias")) {
- out.mAdditionalAliases.add(FontListParser.readAlias(parser));
+ aliases.add(FontListParser.readAlias(parser));
} else {
FontListParser.skip(parser);
}
}
- validate(out);
- return out;
+ return new Result(validateAndTransformToMap(families), aliases);
}
- private static void readFamily(XmlPullParser parser, String fontDir, Result out)
+ private static void readFamily(
+ @NonNull XmlPullParser parser,
+ @NonNull String fontDir,
+ @NonNull List<Family> out,
+ @Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
final String customizationType = parser.getAttributeValue(null, "customizationType");
if (customizationType == null) {
throw new IllegalArgumentException("customizationType must be specified");
}
if (customizationType.equals("new-named-family")) {
- out.mAdditionalNamedFamilies.add(FontListParser.readFamily(parser, fontDir, null));
+ out.add(FontListParser.readFamily(parser, fontDir, updatableFontMap));
} else {
throw new IllegalArgumentException("Unknown customizationType=" + customizationType);
}
diff --git a/graphics/java/android/graphics/fonts/FontFamily.java b/graphics/java/android/graphics/fonts/FontFamily.java
index 75ea12062929..2f0c26f06df7 100644
--- a/graphics/java/android/graphics/fonts/FontFamily.java
+++ b/graphics/java/android/graphics/fonts/FontFamily.java
@@ -18,6 +18,7 @@ package android.graphics.fonts;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.text.FontConfig;
import com.android.internal.util.Preconditions;
@@ -119,7 +120,7 @@ public final class FontFamily {
nAddFont(builderPtr, mFonts.get(i).getNativePtr());
}
final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback);
- final FontFamily family = new FontFamily(mFonts, ptr);
+ final FontFamily family = new FontFamily(mFonts, langTags, variant, ptr);
sFamilyRegistory.registerNativeAllocation(family, ptr);
return family;
}
@@ -138,15 +139,36 @@ public final class FontFamily {
}
private final ArrayList<Font> mFonts;
+ private final String mLangTags;
+ private final int mVariant;
private final long mNativePtr;
// Use Builder instead.
- private FontFamily(@NonNull ArrayList<Font> fonts, long ptr) {
+ private FontFamily(@NonNull ArrayList<Font> fonts, String langTags, int variant, long ptr) {
mFonts = fonts;
+ mLangTags = langTags;
+ mVariant = variant;
mNativePtr = ptr;
}
/**
+ * Returns a BCP-47 compliant language tags associated with this font family.
+ * @hide
+ * @return a BCP-47 compliant language tag.
+ */
+ public @Nullable String getLangTags() {
+ return mLangTags;
+ }
+
+ /**
+ * @hide
+ * @return a family variant
+ */
+ public int getVariant() {
+ return mVariant;
+ }
+
+ /**
* Returns a font
*
* @param index an index of the font
diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java
index 93b1fcc3ba1f..54167b4b3042 100644
--- a/graphics/java/android/graphics/fonts/SystemFonts.java
+++ b/graphics/java/android/graphics/fonts/SystemFonts.java
@@ -23,11 +23,9 @@ import android.graphics.Typeface;
import android.text.FontConfig;
import android.util.ArrayMap;
import android.util.Log;
-import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,7 +35,6 @@ 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.HashSet;
@@ -52,6 +49,11 @@ public final class SystemFonts {
private static final String TAG = "SystemFonts";
private static final String DEFAULT_FAMILY = "sans-serif";
+ private static final String FONTS_XML = "/system/etc/fonts.xml";
+ private static final String SYSTEM_FONT_DIR = "/system/fonts/";
+ private static final String OEM_XML = "/product/etc/fonts_customization.xml";
+ private static final String OEM_FONT_DIR = "/product/fonts/";
+
private SystemFonts() {} // Do not instansiate.
private static final Object LOCK = new Object();
@@ -88,12 +90,10 @@ public final class SystemFonts {
}
private static @NonNull Set<Font> collectAllFonts() {
- final FontCustomizationParser.Result oemCustomization =
- readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
- Map<String, FontFamily[]> map = new ArrayMap<>();
// TODO: use updated fonts
- buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/", null /* updatableFontMap */,
- oemCustomization, map);
+ FontConfig fontConfig = getSystemPreinstalledFontConfig();
+ Map<String, FontFamily[]> map = buildSystemFallback(fontConfig);
+
Set<Font> res = new HashSet<>();
for (FontFamily[] families : map.values()) {
for (FontFamily family : families) {
@@ -119,15 +119,16 @@ public final class SystemFonts {
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
@NonNull Map<String, ByteBuffer> cache) {
- final String languageTags = xmlFamily.getLanguages();
- final int variant = xmlFamily.getVariant();
+ final String languageTags = xmlFamily.getLocaleList().toLanguageTags();
+ final int variant = xmlFamily.getTextHeightVariant();
final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>();
- final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts = new ArrayMap<>();
+ 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();
+ final String fallbackName = font.getFallback();
if (fallbackName == null) {
defaultFonts.add(font);
} else {
@@ -141,19 +142,22 @@ public final class SystemFonts {
}
final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
- xmlFamily.getName(), defaultFonts, languageTags, variant, cache);
+ xmlFamily.getFallbackName(), defaultFonts, languageTags, variant, cache);
// Insert family into fallback map.
for (int i = 0; i < fallbackMap.size(); i++) {
- final ArrayList<FontConfig.Font> fallback =
- specificFallbackFonts.get(fallbackMap.keyAt(i));
+ String name = fallbackMap.keyAt(i);
+ final ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(name);
if (fallback == null) {
- if (defaultFamily != null) {
+ String familyName = xmlFamily.getFallbackName();
+ if (defaultFamily != null
+ // do not add myself to the fallback chain.
+ && (familyName == null || !familyName.equals(name))) {
fallbackMap.valueAt(i).add(defaultFamily);
}
} else {
final FontFamily family = createFontFamily(
- xmlFamily.getName(), fallback, languageTags, variant, cache);
+ xmlFamily.getFallbackName(), fallback, languageTags, variant, cache);
if (family != null) {
fallbackMap.valueAt(i).add(family);
} else if (defaultFamily != null) {
@@ -177,7 +181,7 @@ public final class SystemFonts {
FontFamily.Builder b = null;
for (int i = 0; i < fonts.size(); i++) {
final FontConfig.Font fontConfig = fonts.get(i);
- final String fullPath = fontConfig.getFontName();
+ final String fullPath = fontConfig.getFilePath().getAbsolutePath();
ByteBuffer buffer = cache.get(fullPath);
if (buffer == null) {
if (cache.containsKey(fullPath)) {
@@ -193,11 +197,10 @@ public final class SystemFonts {
final Font font;
try {
font = new Font.Builder(buffer, new File(fullPath), languageTags)
- .setWeight(fontConfig.getWeight())
- .setSlant(fontConfig.isItalic() ? FontStyle.FONT_SLANT_ITALIC
- : FontStyle.FONT_SLANT_UPRIGHT)
- .setTtcIndex(fontConfig.getTtcIndex())
- .setFontVariationSettings(fontConfig.getAxes())
+ .setWeight(fontConfig.getStyle().getWeight())
+ .setSlant(fontConfig.getStyle().getSlant())
+ .setTtcIndex(fontConfig.getIndex())
+ .setFontVariationSettings(fontConfig.getFontVariationSettings())
.build();
} catch (IOException e) {
throw new RuntimeException(e); // Never reaches here
@@ -215,10 +218,11 @@ public final class SystemFonts {
private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
@NonNull HashMap<String, ByteBuffer> bufferCache,
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap) {
- final String familyName = xmlFamily.getName();
+ final String familyName = xmlFamily.getFallbackName();
final FontFamily family = createFontFamily(
- familyName, Arrays.asList(xmlFamily.getFonts()),
- xmlFamily.getLanguages(), xmlFamily.getVariant(), bufferCache);
+ familyName, xmlFamily.getFontList(),
+ xmlFamily.getLocaleList().toLanguageTags(), xmlFamily.getTextHeightVariant(),
+ bufferCache);
if (family == null) {
return;
}
@@ -228,115 +232,104 @@ public final class SystemFonts {
}
/**
- * @see #buildSystemFallback(String, String, Map, FontCustomizationParser.Result, Map)
+ * Get the updated FontConfig.
+ *
+ * @param updatableFontMap a font mapping of updated font files.
* @hide
*/
- @VisibleForTesting
- public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
- @NonNull String fontDir,
- @NonNull FontCustomizationParser.Result oemCustomization,
- @NonNull Map<String, FontFamily[]> fallbackMap) {
- return buildSystemFallback(xmlPath, fontDir, null /* updatableFontMap */,
- oemCustomization, fallbackMap);
+ public static @NonNull FontConfig getSystemFontConfig(
+ @Nullable Map<String, File> updatableFontMap
+ ) {
+ return getSystemFontConfigInternal(FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR,
+ updatableFontMap);
}
/**
- * 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 updatableFontMap A map from font file name to updated font file path.
- * @param fallbackMap An output system fallback map. Caller must pass empty map.
- * @return a list of aliases
+ * Get the system preinstalled FontConfig.
* @hide
*/
- @VisibleForTesting
- public static FontConfig.Alias[] buildSystemFallback(@NonNull String xmlPath,
- @NonNull String fontDir,
- @Nullable Map<String, File> updatableFontMap,
- @NonNull FontCustomizationParser.Result oemCustomization,
- @NonNull Map<String, FontFamily[]> fallbackMap) {
- try {
- final FileInputStream fontsIn = new FileInputStream(xmlPath);
- final FontConfig fontConfig = FontListParser.parse(fontsIn, fontDir, updatableFontMap);
-
- 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;
- }
- appendNamedFamily(xmlFamily, bufferCache, fallbackListMap);
- }
+ public static @NonNull FontConfig getSystemPreinstalledFontConfig() {
+ return getSystemFontConfigInternal(FONTS_XML, SYSTEM_FONT_DIR, OEM_XML, OEM_FONT_DIR, null);
+ }
- for (int i = 0; i < oemCustomization.mAdditionalNamedFamilies.size(); ++i) {
- appendNamedFamily(oemCustomization.mAdditionalNamedFamilies.get(i),
- bufferCache, fallbackListMap);
- }
+ /* package */ static @NonNull FontConfig getSystemFontConfigInternal(
+ @NonNull String fontsXml,
+ @NonNull String systemFontDir,
+ @Nullable String oemXml,
+ @Nullable String productFontDir,
+ @Nullable Map<String, File> updatableFontMap
+ ) {
+ try {
+ return FontListParser.parse(fontsXml, systemFontDir, oemXml, productFontDir,
+ updatableFontMap);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to open/read system font configurations.", e);
+ return new FontConfig(Collections.emptyList(), Collections.emptyList());
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "Failed to parse the system font configuration.", e);
+ return new FontConfig(Collections.emptyList(), Collections.emptyList());
+ }
+ }
- // 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);
- }
+ /**
+ * Build the system fallback from FontConfig.
+ * @hide
+ */
+ @VisibleForTesting
+ public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig) {
+ final Map<String, FontFamily[]> fallbackMap = new HashMap<>();
+ final HashMap<String, ByteBuffer> bufferCache = new HashMap<>();
+ final List<FontConfig.Family> xmlFamilies = fontConfig.getFontFamilies();
+
+ 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.getFallbackName();
+ if (familyName == null) {
+ continue;
}
+ appendNamedFamily(xmlFamily, bufferCache, fallbackListMap);
+ }
- // 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);
+ // Then, add fallback fonts to the each fallback map.
+ for (int i = 0; i < xmlFamilies.size(); i++) {
+ final FontConfig.Family xmlFamily = xmlFamilies.get(i);
+ // The first family (usually the sans-serif family) is always placed immediately
+ // after the primary family in the fallback.
+ if (i == 0 || xmlFamily.getFallbackName() == null) {
+ pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache);
}
-
- final ArrayList<FontConfig.Alias> list = new ArrayList<>();
- list.addAll(Arrays.asList(fontConfig.getAliases()));
- list.addAll(oemCustomization.mAdditionalAliases);
- return list.toArray(new FontConfig.Alias[list.size()]);
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Failed initialize system fallbacks.", e);
- return ArrayUtils.emptyArray(FontConfig.Alias.class);
}
- }
- private static FontCustomizationParser.Result readFontCustomization(
- @NonNull String customizeXml, @NonNull String customFontsDir) {
- try (FileInputStream f = new FileInputStream(customizeXml)) {
- return FontCustomizationParser.parse(f, customFontsDir);
- } catch (IOException e) {
- return new FontCustomizationParser.Result();
- } catch (XmlPullParserException e) {
- Log.e(TAG, "Failed to parse font customization XML", e);
- return new FontCustomizationParser.Result();
+ // 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);
+ fallbackMap.put(fallbackName, familyList.toArray(new FontFamily[0]));
}
+
+ return fallbackMap;
}
- /** @hide */
- public static @NonNull Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
- initializePreinstalledFonts() {
- return initializeSystemFonts(null);
+ /**
+ * Build the system Typeface mappings from FontConfig and FallbackMap.
+ * @hide
+ */
+ @VisibleForTesting
+ public static Map<String, Typeface> buildSystemTypefaces(
+ FontConfig fontConfig,
+ Map<String, FontFamily[]> fallbackMap) {
+ final HashMap<String, Typeface> result = new HashMap<>();
+ Typeface.initSystemDefaultTypefaces(fallbackMap, fontConfig.getAliases(), result);
+ return result;
}
- /** @hide */
- public static Pair<FontConfig.Alias[], Map<String, FontFamily[]>>
- initializeSystemFonts(@Nullable Map<String, File> updatableFontMap) {
- final FontCustomizationParser.Result oemCustomization =
- readFontCustomization("/product/etc/fonts_customization.xml", "/product/fonts/");
- Map<String, FontFamily[]> map = new ArrayMap<>();
- FontConfig.Alias[] aliases = buildSystemFallback("/system/etc/fonts.xml", "/system/fonts/",
- updatableFontMap, oemCustomization, map);
+ /**
+ * @hide
+ */
+ public void resetFallbackMapping(Map<String, FontFamily[]> fallbackMap) {
synchronized (LOCK) {
- sFamilyMap = map;
+ sFamilyMap = fallbackMap;
}
- return new Pair(aliases, map);
}
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 633c0c417192..a0d9e8e0a6fb 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -26,7 +26,6 @@ import android.graphics.fonts.SystemFonts;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.text.FontConfig;
-import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -40,7 +39,6 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.NioUtils;
import java.nio.channels.FileChannel;
-import java.util.HashMap;
import java.util.Map;
/** A service for managing system fonts. */
@@ -69,7 +67,10 @@ public final class FontManagerService {
@Override
@Nullable
public SharedMemory getSerializedSystemFontMap() {
- return mService.getSerializedSystemFontMap();
+ if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
+ return null;
+ }
+ return mService.getCurrentFontSettings().getSerializedSystemFontMap();
}
});
}
@@ -98,48 +99,20 @@ public final class FontManagerService {
private final UpdatableFontDir mUpdatableFontDir;
@GuardedBy("FontManagerService.this")
- @Nullable
- private SharedMemory mSerializedSystemFontMap = null;
+ @Nullable SystemFontSettings mCurrentFontSettings = null;
private FontManagerService() {
mUpdatableFontDir = ENABLE_FONT_UPDATES
? new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser()) : null;
}
- @Nullable
- private SharedMemory getSerializedSystemFontMap() {
- if (!Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
- return null;
- }
+ @NonNull private SystemFontSettings getCurrentFontSettings() {
synchronized (FontManagerService.this) {
- if (mSerializedSystemFontMap == null) {
- mSerializedSystemFontMap = createSerializedSystemFontMapLocked();
- }
- return mSerializedSystemFontMap;
- }
- }
-
- @Nullable
- private SharedMemory createSerializedSystemFontMapLocked() {
- if (mUpdatableFontDir != null) {
- HashMap<String, Typeface> systemFontMap = new HashMap<>();
- Map<String, File> fontFileMap = mUpdatableFontDir.getFontFileMap();
- Pair<FontConfig.Alias[], Map<String, FontFamily[]>> pair =
- SystemFonts.initializeSystemFonts(fontFileMap);
- Typeface.initSystemDefaultTypefaces(systemFontMap, pair.second, pair.first);
- try {
- return Typeface.serializeFontMap(systemFontMap);
- } catch (IOException | ErrnoException e) {
- Slog.w(TAG, "Failed to serialize updatable font map. "
- + "Retrying with system image fonts.", e);
+ if (mCurrentFontSettings == null) {
+ mCurrentFontSettings = SystemFontSettings.create(mUpdatableFontDir);
}
+ return mCurrentFontSettings;
}
- try {
- return Typeface.serializeFontMap(Typeface.getSystemFontMap());
- } catch (IOException | ErrnoException e) {
- Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
- }
- return null;
}
private boolean installFontFile(String name, FileDescriptor fd) {
@@ -152,8 +125,74 @@ public final class FontManagerService {
return false;
}
// Create updated font map in the next getSerializedSystemFontMap() call.
- mSerializedSystemFontMap = null;
+ mCurrentFontSettings = null;
return true;
}
}
+
+ private static class SystemFontSettings {
+ private final @NonNull SharedMemory mSerializedSystemFontMap;
+ private final @NonNull FontConfig mSystemFontConfig;
+ private final @NonNull Map<String, FontFamily[]> mSystemFallbackMap;
+ private final @NonNull Map<String, Typeface> mSystemTypefaceMap;
+
+ SystemFontSettings(
+ @NonNull SharedMemory serializedSystemFontMap,
+ @NonNull FontConfig systemFontConfig,
+ @NonNull Map<String, FontFamily[]> systemFallbackMap,
+ @NonNull Map<String, Typeface> systemTypefaceMap) {
+ mSerializedSystemFontMap = serializedSystemFontMap;
+ mSystemFontConfig = systemFontConfig;
+ mSystemFallbackMap = systemFallbackMap;
+ mSystemTypefaceMap = systemTypefaceMap;
+ }
+
+ public @NonNull SharedMemory getSerializedSystemFontMap() {
+ return mSerializedSystemFontMap;
+ }
+
+ public @NonNull FontConfig getSystemFontConfig() {
+ return mSystemFontConfig;
+ }
+
+ public @NonNull Map<String, FontFamily[]> getSystemFallbackMap() {
+ return mSystemFallbackMap;
+ }
+
+ public @NonNull Map<String, Typeface> getSystemTypefaceMap() {
+ return mSystemTypefaceMap;
+ }
+
+ public static @Nullable SystemFontSettings create(
+ @Nullable UpdatableFontDir updatableFontDir) {
+ if (updatableFontDir != null) {
+ final FontConfig fontConfig = SystemFonts.getSystemFontConfig(
+ updatableFontDir.getFontFileMap());
+ final Map<String, FontFamily[]> fallback =
+ SystemFonts.buildSystemFallback(fontConfig);
+ final Map<String, Typeface> typefaceMap =
+ SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+
+ try {
+ final SharedMemory shm = Typeface.serializeFontMap(typefaceMap);
+ return new SystemFontSettings(shm, fontConfig, fallback, typefaceMap);
+ } catch (IOException | ErrnoException e) {
+ Slog.w(TAG, "Failed to serialize updatable font map. "
+ + "Retrying with system image fonts.", e);
+ }
+ }
+
+ final FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig();
+ final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
+ final Map<String, Typeface> typefaceMap =
+ SystemFonts.buildSystemTypefaces(fontConfig, fallback);
+ try {
+ final SharedMemory shm = Typeface.serializeFontMap(typefaceMap);
+ return new SystemFontSettings(shm, fontConfig, fallback, typefaceMap);
+ } catch (IOException | ErrnoException e) {
+ Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
+ }
+ return null;
+ }
+ };
}