Loading core/java/android/graphics/fonts/FontFamilyUpdateRequest.java +11 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.graphics.fonts; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; Loading Loading @@ -213,6 +214,16 @@ public final class FontFamilyUpdateRequest { public List<FontVariationAxis> getAxes() { return mAxes; } /** * Returns the index of collection * * TODO(183752879): Make font index configurable and make this SystemApi. * @hide */ public @IntRange(from = 0) int getIndex() { return 0; } } /** Loading core/java/android/graphics/fonts/FontUpdateRequest.java +301 −18 Original line number Diff line number Diff line Loading @@ -17,19 +17,24 @@ package android.graphics.fonts; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.LocaleList; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.text.FontConfig; import android.util.TypedXmlSerializer; import java.io.File; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * Represents a font update request. Currently only font install request is supported. Loading @@ -47,6 +52,273 @@ public final class FontUpdateRequest implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface Type {} /** * Font object used for update. * * Here is an example of Family/Font XML. * <family name="my-sans"> * <font name="MySans" weight="400" slant="0" axis="'wght' 400 'ital' 0" index="0" /> * <font name="MySans" weight="400" slant="0" axis="'wght' 400 'ital' 1" index="0" /> * <font name="MySans" weight="400" slant="0" axis="'wght' 700 'ital' 0" index="0" /> * <font name="MySans" weight="400" slant="0" axis="'wght' 700 'ital' 1" index="0" /> * </family> * * @see Font#readFromXml(XmlPullParser) * @see Font#writeToXml(TypedXmlSerializer, Font) * @see Family#readFromXml(XmlPullParser) * @see Family#writeFamilyToXml(TypedXmlSerializer, Family) */ public static final class Font implements Parcelable { private static final String ATTR_INDEX = "index"; private static final String ATTR_WEIGHT = "weight"; private static final String ATTR_SLANT = "slant"; private static final String ATTR_AXIS = "axis"; private static final String ATTR_POSTSCRIPT_NAME = "name"; private final @NonNull String mPostScriptName; private final @NonNull FontStyle mFontStyle; private final @IntRange(from = 0) int mIndex; private final @NonNull String mFontVariationSettings; public Font(@NonNull String postScriptName, @NonNull FontStyle fontStyle, @IntRange(from = 0) int index, @NonNull String fontVariationSettings) { mPostScriptName = postScriptName; mFontStyle = fontStyle; mIndex = index; mFontVariationSettings = fontVariationSettings; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString8(mPostScriptName); dest.writeInt(mFontStyle.getWeight()); dest.writeInt(mFontStyle.getSlant()); dest.writeInt(mIndex); dest.writeString8(mFontVariationSettings); } public static final @NonNull Creator<Font> CREATOR = new Creator<Font>() { @Override public Font createFromParcel(Parcel source) { String fontName = source.readString8(); int weight = source.readInt(); int slant = source.readInt(); int index = source.readInt(); String varSettings = source.readString8(); return new Font(fontName, new FontStyle(weight, slant), index, varSettings); } @Override public Font[] newArray(int size) { return new Font[size]; } }; /** * Write {@link Font} instance to XML file. * * For the XML format, see {@link Font} class comment. * * @param out output XML serializer * @param font a Font instance to be written. */ public static void writeToXml(TypedXmlSerializer out, Font font) throws IOException { out.attribute(null, ATTR_POSTSCRIPT_NAME, font.getPostScriptName()); out.attributeInt(null, ATTR_INDEX, font.getIndex()); out.attributeInt(null, ATTR_WEIGHT, font.getFontStyle().getWeight()); out.attributeInt(null, ATTR_SLANT, font.getFontStyle().getSlant()); out.attribute(null, ATTR_AXIS, font.getFontVariationSettings()); } /** * Read {@link Font} instance from <font> element in XML * * For the XML format, see {@link Font} class comment. * * @param parser a parser that point <font> element. * @return a font instance * @throws IOException if font element is invalid. */ public static Font readFromXml(XmlPullParser parser) throws IOException { String psName = parser.getAttributeValue(null, ATTR_POSTSCRIPT_NAME); if (psName == null) { throw new IOException("name attribute is missing font tag."); } int index = getAttributeValueInt(parser, ATTR_INDEX, 0); int weight = getAttributeValueInt(parser, ATTR_WEIGHT, FontStyle.FONT_WEIGHT_NORMAL); int slant = getAttributeValueInt(parser, ATTR_SLANT, FontStyle.FONT_SLANT_UPRIGHT); String varSettings = parser.getAttributeValue(null, ATTR_AXIS); if (varSettings == null) { varSettings = ""; } return new Font(psName, new FontStyle(weight, slant), index, varSettings); } public @NonNull String getPostScriptName() { return mPostScriptName; } public @NonNull FontStyle getFontStyle() { return mFontStyle; } public @IntRange(from = 0) int getIndex() { return mIndex; } public @NonNull String getFontVariationSettings() { return mFontVariationSettings; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Font font = (Font) o; return mIndex == font.mIndex && mPostScriptName.equals(font.mPostScriptName) && mFontStyle.equals(font.mFontStyle) && mFontVariationSettings.equals(font.mFontVariationSettings); } @Override public int hashCode() { return Objects.hash(mPostScriptName, mFontStyle, mIndex, mFontVariationSettings); } @Override public String toString() { return "Font{" + "mPostScriptName='" + mPostScriptName + '\'' + ", mFontStyle=" + mFontStyle + ", mIndex=" + mIndex + ", mFontVariationSettings='" + mFontVariationSettings + '\'' + '}'; } } /** * Font Family object used for update request. */ public static final class Family implements Parcelable { private static final String TAG_FAMILY = "family"; private static final String ATTR_NAME = "name"; private static final String TAG_FONT = "font"; private final @Nullable String mName; private final @NonNull List<Font> mFonts; public Family(String name, List<Font> fonts) { mName = name; mFonts = fonts; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString8(mName); dest.writeParcelableList(mFonts, flags); } public static final @NonNull Creator<Family> CREATOR = new Creator<Family>() { @Override public Family createFromParcel(Parcel source) { String familyName = source.readString8(); List<Font> fonts = source.readParcelableList( new ArrayList<>(), Font.class.getClassLoader()); return new Family(familyName, fonts); } @Override public Family[] newArray(int size) { return new Family[size]; } }; /** * Write {@link Family} instance to XML. * * For the XML format, see {@link Font} class comment. * * @param out an output XML serializer * @param family a {@link Family} instance to be written */ public static void writeFamilyToXml(@NonNull TypedXmlSerializer out, @NonNull Family family) throws IOException { out.attribute(null, ATTR_NAME, family.getName()); List<Font> fonts = family.getFonts(); for (int i = 0; i < fonts.size(); ++i) { Font font = fonts.get(i); out.startTag(null, TAG_FONT); Font.writeToXml(out, font); out.endTag(null, TAG_FONT); } } /** * Read a {@link Family} instance from <family> element in XML * * For the XML format, see {@link Font} class comment. * * @param parser an XML parser that points <family> element. * @return an {@link Family} instance */ public static @NonNull Family readFromXml(@NonNull XmlPullParser parser) throws XmlPullParserException, IOException { List<Font> fonts = new ArrayList<>(); if (parser.getEventType() != XmlPullParser.START_TAG || !parser.getName().equals(TAG_FAMILY)) { throw new IOException("Unexpected parser state: must be START_TAG with family"); } String name = parser.getAttributeValue(null, ATTR_NAME); int type = 0; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_FONT)) { fonts.add(Font.readFromXml(parser)); } else if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_FAMILY)) { break; } } return new Family(name, fonts); } public @NonNull String getName() { return mName; } public @NonNull List<Font> getFonts() { return mFonts; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Family family = (Family) o; return mName.equals(family.mName) && mFonts.equals(family.mFonts); } @Override public int hashCode() { return Objects.hash(mName, mFonts); } @Override public String toString() { return "Family{mName='" + mName + '\'' + ", mFonts=" + mFonts + '}'; } } public static final Creator<FontUpdateRequest> CREATOR = new Creator<FontUpdateRequest>() { @Override public FontUpdateRequest createFromParcel(Parcel in) { Loading @@ -68,7 +340,7 @@ public final class FontUpdateRequest implements Parcelable { private final byte[] mSignature; // NonNull if mType == TYPE_UPDATE_FONT_FAMILY. @Nullable private final FontConfig.FontFamily mFontFamily; private final Family mFontFamily; public FontUpdateRequest(@NonNull ParcelFileDescriptor fd, @NonNull byte[] signature) { mType = TYPE_UPDATE_FONT_FILE; Loading @@ -77,31 +349,29 @@ public final class FontUpdateRequest implements Parcelable { mFontFamily = null; } public FontUpdateRequest(@NonNull FontConfig.FontFamily fontFamily) { public FontUpdateRequest(@NonNull Family fontFamily) { mType = TYPE_UPDATE_FONT_FAMILY; mFd = null; mSignature = null; mFontFamily = fontFamily; } public FontUpdateRequest(@NonNull String postScriptName, public FontUpdateRequest(@NonNull String familyName, @NonNull List<FontFamilyUpdateRequest.Font> variations) { // TODO: Serialize the request directly instead of reusing FontConfig.FontFamily. this(createFontFamily(postScriptName, variations)); this(createFontFamily(familyName, variations)); } private static FontConfig.FontFamily createFontFamily(@NonNull String postScriptName, private static Family createFontFamily(@NonNull String familyName, @NonNull List<FontFamilyUpdateRequest.Font> fonts) { List<FontConfig.Font> configFonts = new ArrayList<>(fonts.size()); List<Font> updateFonts = new ArrayList<>(fonts.size()); for (FontFamilyUpdateRequest.Font font : fonts) { // TODO: Support .otf. configFonts.add(new FontConfig.Font(new File(font.getPostScriptName() + ".ttf"), null, font.getStyle(), 0 /* index */, FontVariationAxis.toFontVariationSettings(font.getAxes()), null /* fontFamilyName */)); updateFonts.add(new Font( font.getPostScriptName(), font.getStyle(), font.getIndex(), FontVariationAxis.toFontVariationSettings(font.getAxes()))); } return new FontConfig.FontFamily(configFonts, postScriptName, LocaleList.getEmptyLocaleList(), FontConfig.FontFamily.VARIANT_DEFAULT); return new Family(familyName, updateFonts); } protected FontUpdateRequest(Parcel in) { Loading @@ -126,7 +396,7 @@ public final class FontUpdateRequest implements Parcelable { } @Nullable public FontConfig.FontFamily getFontFamily() { public Family getFontFamily() { return mFontFamily; } Loading @@ -142,4 +412,17 @@ public final class FontUpdateRequest implements Parcelable { dest.writeBlob(mSignature); dest.writeParcelable(mFontFamily, flags); } // Utility functions private static int getAttributeValueInt(XmlPullParser parser, String name, int defaultValue) { try { String value = parser.getAttributeValue(null, name); if (value == null) { return defaultValue; } return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } } core/tests/coretests/src/android/graphics/FontListParserTest.java +0 −42 Original line number Diff line number Diff line Loading @@ -24,14 +24,12 @@ import static android.text.FontConfig.FontFamily.VARIANT_DEFAULT; import static android.text.FontConfig.FontFamily.VARIANT_ELEGANT; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static junit.framework.Assert.fail; import android.graphics.fonts.FontStyle; import android.os.LocaleList; import android.text.FontConfig; import android.util.TypedXmlSerializer; import android.util.Xml; import androidx.test.filters.SmallTest; Loading @@ -43,7 +41,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; Loading @@ -69,10 +66,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -94,10 +87,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -115,10 +104,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -136,10 +121,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -164,10 +145,6 @@ public final class FontListParserTest { "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT); FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -194,10 +171,6 @@ public final class FontListParserTest { "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT); FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -218,10 +191,6 @@ public final class FontListParserTest { "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT); FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading Loading @@ -338,15 +307,4 @@ public final class FontListParserTest { parser.nextTag(); return FontListParser.readFamily(parser, "", null); } private String writeFamily(FontConfig.FontFamily family) throws IOException { TypedXmlSerializer out = Xml.newFastSerializer(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); out.setOutput(buffer, "UTF-8"); out.startTag(null, "family"); FontListParser.writeFamily(out, family); out.endTag(null, "family"); out.endDocument(); return buffer.toString("UTF-8"); } } graphics/java/android/graphics/FontListParser.java +0 −62 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import android.graphics.fonts.FontVariationAxis; import android.os.Build; import android.os.LocaleList; import android.text.FontConfig; import android.text.TextUtils; import android.util.TypedXmlSerializer; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; Loading Loading @@ -194,32 +192,6 @@ public class FontListParser { return new FontConfig.FontFamily(fonts, name, LocaleList.forLanguageTags(lang), intVariant); } /** * Write a family tag representing {@code fontFamily}. The tag should be started by the caller. */ public static void writeFamily(TypedXmlSerializer out, FontConfig.FontFamily fontFamily) throws IOException { if (!TextUtils.isEmpty(fontFamily.getName())) { out.attribute(null, ATTR_NAME, fontFamily.getName()); } if (!fontFamily.getLocaleList().isEmpty()) { out.attribute(null, ATTR_LANG, fontFamily.getLocaleList().toLanguageTags()); } switch (fontFamily.getVariant()) { case FontConfig.FontFamily.VARIANT_COMPACT: out.attribute(null, ATTR_VARIANT, VARIANT_COMPACT); break; case FontConfig.FontFamily.VARIANT_ELEGANT: out.attribute(null, ATTR_VARIANT, VARIANT_ELEGANT); break; } for (FontConfig.Font font : fontFamily.getFontList()) { out.startTag(null, TAG_FONT); writeFont(out, font); out.endTag(null, TAG_FONT); } } /** Matches leading and trailing XML whitespace. */ private static final Pattern FILENAME_WHITESPACE_PATTERN = Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$"); Loading Loading @@ -292,34 +264,6 @@ public class FontListParser { return null; } private static void writeFont(TypedXmlSerializer out, FontConfig.Font font) throws IOException { if (font.getTtcIndex() != 0) { out.attributeInt(null, ATTR_INDEX, font.getTtcIndex()); } if (font.getStyle().getWeight() != FontStyle.FONT_WEIGHT_NORMAL) { out.attributeInt(null, ATTR_WEIGHT, font.getStyle().getWeight()); } if (font.getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC) { out.attribute(null, ATTR_STYLE, STYLE_ITALIC); } else { out.attribute(null, ATTR_STYLE, STYLE_NORMAL); } if (!TextUtils.isEmpty(font.getFontFamilyName())) { out.attribute(null, ATTR_FALLBACK_FOR, font.getFontFamilyName()); } out.text(font.getFile().getName()); FontVariationAxis[] axes = FontVariationAxis.fromFontVariationSettings(font.getFontVariationSettings()); if (axes != null) { for (FontVariationAxis axis : axes) { out.startTag(null, TAG_AXIS); writeAxis(out, axis); out.endTag(null, TAG_AXIS); } } } private static FontVariationAxis readAxis(XmlPullParser parser) throws XmlPullParserException, IOException { String tagStr = parser.getAttributeValue(null, ATTR_TAG); Loading @@ -328,12 +272,6 @@ public class FontListParser { return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr)); } private static void writeAxis(TypedXmlSerializer out, FontVariationAxis axis) throws IOException { out.attribute(null, ATTR_TAG, axis.getTag()); out.attributeFloat(null, ATTR_STYLEVALUE, axis.getStyleValue()); } /** * Reads alias elements */ Loading services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java +7 −8 Original line number Diff line number Diff line Loading @@ -17,8 +17,7 @@ package com.android.server.graphics.fonts; import android.annotation.NonNull; import android.graphics.FontListParser; import android.text.FontConfig; import android.graphics.fonts.FontUpdateRequest; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; Loading Loading @@ -48,7 +47,7 @@ import java.util.Set; /* package */ static class Config { public long lastModifiedMillis; public final Set<String> updatedFontDirs = new ArraySet<>(); public final List<FontConfig.FontFamily> fontFamilies = new ArrayList<>(); public final List<FontUpdateRequest.Family> fontFamilies = new ArrayList<>(); } /** Loading Loading @@ -81,8 +80,8 @@ import java.util.Set; case TAG_FAMILY: // updatableFontMap is not ready here. We get the base file names by passing // empty fontDir, and resolve font paths later. out.fontFamilies.add(FontListParser.readFamily( parser, "" /* fontDir */, null /* updatableFontMap */)); out.fontFamilies.add(FontUpdateRequest.Family.readFromXml(parser)); break; default: Slog.w(TAG, "Skipping unknown tag: " + tag); } Loading @@ -108,11 +107,11 @@ import java.util.Set; out.attribute(null, ATTR_VALUE, dir); out.endTag(null, TAG_UPDATED_FONT_DIR); } List<FontConfig.FontFamily> fontFamilies = config.fontFamilies; List<FontUpdateRequest.Family> fontFamilies = config.fontFamilies; for (int i = 0; i < fontFamilies.size(); i++) { FontConfig.FontFamily fontFamily = fontFamilies.get(i); FontUpdateRequest.Family fontFamily = fontFamilies.get(i); out.startTag(null, TAG_FAMILY); FontListParser.writeFamily(out, fontFamily); FontUpdateRequest.Family.writeFamilyToXml(out, fontFamily); out.endTag(null, TAG_FAMILY); } out.endTag(null, TAG_ROOT); Loading Loading
core/java/android/graphics/fonts/FontFamilyUpdateRequest.java +11 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.graphics.fonts; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; Loading Loading @@ -213,6 +214,16 @@ public final class FontFamilyUpdateRequest { public List<FontVariationAxis> getAxes() { return mAxes; } /** * Returns the index of collection * * TODO(183752879): Make font index configurable and make this SystemApi. * @hide */ public @IntRange(from = 0) int getIndex() { return 0; } } /** Loading
core/java/android/graphics/fonts/FontUpdateRequest.java +301 −18 Original line number Diff line number Diff line Loading @@ -17,19 +17,24 @@ package android.graphics.fonts; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.LocaleList; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.text.FontConfig; import android.util.TypedXmlSerializer; import java.io.File; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * Represents a font update request. Currently only font install request is supported. Loading @@ -47,6 +52,273 @@ public final class FontUpdateRequest implements Parcelable { @Retention(RetentionPolicy.SOURCE) public @interface Type {} /** * Font object used for update. * * Here is an example of Family/Font XML. * <family name="my-sans"> * <font name="MySans" weight="400" slant="0" axis="'wght' 400 'ital' 0" index="0" /> * <font name="MySans" weight="400" slant="0" axis="'wght' 400 'ital' 1" index="0" /> * <font name="MySans" weight="400" slant="0" axis="'wght' 700 'ital' 0" index="0" /> * <font name="MySans" weight="400" slant="0" axis="'wght' 700 'ital' 1" index="0" /> * </family> * * @see Font#readFromXml(XmlPullParser) * @see Font#writeToXml(TypedXmlSerializer, Font) * @see Family#readFromXml(XmlPullParser) * @see Family#writeFamilyToXml(TypedXmlSerializer, Family) */ public static final class Font implements Parcelable { private static final String ATTR_INDEX = "index"; private static final String ATTR_WEIGHT = "weight"; private static final String ATTR_SLANT = "slant"; private static final String ATTR_AXIS = "axis"; private static final String ATTR_POSTSCRIPT_NAME = "name"; private final @NonNull String mPostScriptName; private final @NonNull FontStyle mFontStyle; private final @IntRange(from = 0) int mIndex; private final @NonNull String mFontVariationSettings; public Font(@NonNull String postScriptName, @NonNull FontStyle fontStyle, @IntRange(from = 0) int index, @NonNull String fontVariationSettings) { mPostScriptName = postScriptName; mFontStyle = fontStyle; mIndex = index; mFontVariationSettings = fontVariationSettings; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString8(mPostScriptName); dest.writeInt(mFontStyle.getWeight()); dest.writeInt(mFontStyle.getSlant()); dest.writeInt(mIndex); dest.writeString8(mFontVariationSettings); } public static final @NonNull Creator<Font> CREATOR = new Creator<Font>() { @Override public Font createFromParcel(Parcel source) { String fontName = source.readString8(); int weight = source.readInt(); int slant = source.readInt(); int index = source.readInt(); String varSettings = source.readString8(); return new Font(fontName, new FontStyle(weight, slant), index, varSettings); } @Override public Font[] newArray(int size) { return new Font[size]; } }; /** * Write {@link Font} instance to XML file. * * For the XML format, see {@link Font} class comment. * * @param out output XML serializer * @param font a Font instance to be written. */ public static void writeToXml(TypedXmlSerializer out, Font font) throws IOException { out.attribute(null, ATTR_POSTSCRIPT_NAME, font.getPostScriptName()); out.attributeInt(null, ATTR_INDEX, font.getIndex()); out.attributeInt(null, ATTR_WEIGHT, font.getFontStyle().getWeight()); out.attributeInt(null, ATTR_SLANT, font.getFontStyle().getSlant()); out.attribute(null, ATTR_AXIS, font.getFontVariationSettings()); } /** * Read {@link Font} instance from <font> element in XML * * For the XML format, see {@link Font} class comment. * * @param parser a parser that point <font> element. * @return a font instance * @throws IOException if font element is invalid. */ public static Font readFromXml(XmlPullParser parser) throws IOException { String psName = parser.getAttributeValue(null, ATTR_POSTSCRIPT_NAME); if (psName == null) { throw new IOException("name attribute is missing font tag."); } int index = getAttributeValueInt(parser, ATTR_INDEX, 0); int weight = getAttributeValueInt(parser, ATTR_WEIGHT, FontStyle.FONT_WEIGHT_NORMAL); int slant = getAttributeValueInt(parser, ATTR_SLANT, FontStyle.FONT_SLANT_UPRIGHT); String varSettings = parser.getAttributeValue(null, ATTR_AXIS); if (varSettings == null) { varSettings = ""; } return new Font(psName, new FontStyle(weight, slant), index, varSettings); } public @NonNull String getPostScriptName() { return mPostScriptName; } public @NonNull FontStyle getFontStyle() { return mFontStyle; } public @IntRange(from = 0) int getIndex() { return mIndex; } public @NonNull String getFontVariationSettings() { return mFontVariationSettings; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Font font = (Font) o; return mIndex == font.mIndex && mPostScriptName.equals(font.mPostScriptName) && mFontStyle.equals(font.mFontStyle) && mFontVariationSettings.equals(font.mFontVariationSettings); } @Override public int hashCode() { return Objects.hash(mPostScriptName, mFontStyle, mIndex, mFontVariationSettings); } @Override public String toString() { return "Font{" + "mPostScriptName='" + mPostScriptName + '\'' + ", mFontStyle=" + mFontStyle + ", mIndex=" + mIndex + ", mFontVariationSettings='" + mFontVariationSettings + '\'' + '}'; } } /** * Font Family object used for update request. */ public static final class Family implements Parcelable { private static final String TAG_FAMILY = "family"; private static final String ATTR_NAME = "name"; private static final String TAG_FONT = "font"; private final @Nullable String mName; private final @NonNull List<Font> mFonts; public Family(String name, List<Font> fonts) { mName = name; mFonts = fonts; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString8(mName); dest.writeParcelableList(mFonts, flags); } public static final @NonNull Creator<Family> CREATOR = new Creator<Family>() { @Override public Family createFromParcel(Parcel source) { String familyName = source.readString8(); List<Font> fonts = source.readParcelableList( new ArrayList<>(), Font.class.getClassLoader()); return new Family(familyName, fonts); } @Override public Family[] newArray(int size) { return new Family[size]; } }; /** * Write {@link Family} instance to XML. * * For the XML format, see {@link Font} class comment. * * @param out an output XML serializer * @param family a {@link Family} instance to be written */ public static void writeFamilyToXml(@NonNull TypedXmlSerializer out, @NonNull Family family) throws IOException { out.attribute(null, ATTR_NAME, family.getName()); List<Font> fonts = family.getFonts(); for (int i = 0; i < fonts.size(); ++i) { Font font = fonts.get(i); out.startTag(null, TAG_FONT); Font.writeToXml(out, font); out.endTag(null, TAG_FONT); } } /** * Read a {@link Family} instance from <family> element in XML * * For the XML format, see {@link Font} class comment. * * @param parser an XML parser that points <family> element. * @return an {@link Family} instance */ public static @NonNull Family readFromXml(@NonNull XmlPullParser parser) throws XmlPullParserException, IOException { List<Font> fonts = new ArrayList<>(); if (parser.getEventType() != XmlPullParser.START_TAG || !parser.getName().equals(TAG_FAMILY)) { throw new IOException("Unexpected parser state: must be START_TAG with family"); } String name = parser.getAttributeValue(null, ATTR_NAME); int type = 0; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_FONT)) { fonts.add(Font.readFromXml(parser)); } else if (type == XmlPullParser.END_TAG && parser.getName().equals(TAG_FAMILY)) { break; } } return new Family(name, fonts); } public @NonNull String getName() { return mName; } public @NonNull List<Font> getFonts() { return mFonts; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Family family = (Family) o; return mName.equals(family.mName) && mFonts.equals(family.mFonts); } @Override public int hashCode() { return Objects.hash(mName, mFonts); } @Override public String toString() { return "Family{mName='" + mName + '\'' + ", mFonts=" + mFonts + '}'; } } public static final Creator<FontUpdateRequest> CREATOR = new Creator<FontUpdateRequest>() { @Override public FontUpdateRequest createFromParcel(Parcel in) { Loading @@ -68,7 +340,7 @@ public final class FontUpdateRequest implements Parcelable { private final byte[] mSignature; // NonNull if mType == TYPE_UPDATE_FONT_FAMILY. @Nullable private final FontConfig.FontFamily mFontFamily; private final Family mFontFamily; public FontUpdateRequest(@NonNull ParcelFileDescriptor fd, @NonNull byte[] signature) { mType = TYPE_UPDATE_FONT_FILE; Loading @@ -77,31 +349,29 @@ public final class FontUpdateRequest implements Parcelable { mFontFamily = null; } public FontUpdateRequest(@NonNull FontConfig.FontFamily fontFamily) { public FontUpdateRequest(@NonNull Family fontFamily) { mType = TYPE_UPDATE_FONT_FAMILY; mFd = null; mSignature = null; mFontFamily = fontFamily; } public FontUpdateRequest(@NonNull String postScriptName, public FontUpdateRequest(@NonNull String familyName, @NonNull List<FontFamilyUpdateRequest.Font> variations) { // TODO: Serialize the request directly instead of reusing FontConfig.FontFamily. this(createFontFamily(postScriptName, variations)); this(createFontFamily(familyName, variations)); } private static FontConfig.FontFamily createFontFamily(@NonNull String postScriptName, private static Family createFontFamily(@NonNull String familyName, @NonNull List<FontFamilyUpdateRequest.Font> fonts) { List<FontConfig.Font> configFonts = new ArrayList<>(fonts.size()); List<Font> updateFonts = new ArrayList<>(fonts.size()); for (FontFamilyUpdateRequest.Font font : fonts) { // TODO: Support .otf. configFonts.add(new FontConfig.Font(new File(font.getPostScriptName() + ".ttf"), null, font.getStyle(), 0 /* index */, FontVariationAxis.toFontVariationSettings(font.getAxes()), null /* fontFamilyName */)); updateFonts.add(new Font( font.getPostScriptName(), font.getStyle(), font.getIndex(), FontVariationAxis.toFontVariationSettings(font.getAxes()))); } return new FontConfig.FontFamily(configFonts, postScriptName, LocaleList.getEmptyLocaleList(), FontConfig.FontFamily.VARIANT_DEFAULT); return new Family(familyName, updateFonts); } protected FontUpdateRequest(Parcel in) { Loading @@ -126,7 +396,7 @@ public final class FontUpdateRequest implements Parcelable { } @Nullable public FontConfig.FontFamily getFontFamily() { public Family getFontFamily() { return mFontFamily; } Loading @@ -142,4 +412,17 @@ public final class FontUpdateRequest implements Parcelable { dest.writeBlob(mSignature); dest.writeParcelable(mFontFamily, flags); } // Utility functions private static int getAttributeValueInt(XmlPullParser parser, String name, int defaultValue) { try { String value = parser.getAttributeValue(null, name); if (value == null) { return defaultValue; } return Integer.parseInt(value); } catch (NumberFormatException e) { return defaultValue; } } }
core/tests/coretests/src/android/graphics/FontListParserTest.java +0 −42 Original line number Diff line number Diff line Loading @@ -24,14 +24,12 @@ import static android.text.FontConfig.FontFamily.VARIANT_DEFAULT; import static android.text.FontConfig.FontFamily.VARIANT_ELEGANT; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static junit.framework.Assert.fail; import android.graphics.fonts.FontStyle; import android.os.LocaleList; import android.text.FontConfig; import android.util.TypedXmlSerializer; import android.util.Xml; import androidx.test.filters.SmallTest; Loading @@ -43,7 +41,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; Loading @@ -69,10 +66,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -94,10 +87,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -115,10 +104,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -136,10 +121,6 @@ public final class FontListParserTest { FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -164,10 +145,6 @@ public final class FontListParserTest { "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT); FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -194,10 +171,6 @@ public final class FontListParserTest { "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT); FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading @@ -218,10 +191,6 @@ public final class FontListParserTest { "sans-serif", LocaleList.getEmptyLocaleList(), VARIANT_DEFAULT); FontConfig.FontFamily family = readFamily(xml); assertThat(family).isEqualTo(expected); String serialized = writeFamily(family); assertWithMessage("serialized = " + serialized) .that(readFamily(serialized)).isEqualTo(expected); } @Test Loading Loading @@ -338,15 +307,4 @@ public final class FontListParserTest { parser.nextTag(); return FontListParser.readFamily(parser, "", null); } private String writeFamily(FontConfig.FontFamily family) throws IOException { TypedXmlSerializer out = Xml.newFastSerializer(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); out.setOutput(buffer, "UTF-8"); out.startTag(null, "family"); FontListParser.writeFamily(out, family); out.endTag(null, "family"); out.endDocument(); return buffer.toString("UTF-8"); } }
graphics/java/android/graphics/FontListParser.java +0 −62 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import android.graphics.fonts.FontVariationAxis; import android.os.Build; import android.os.LocaleList; import android.text.FontConfig; import android.text.TextUtils; import android.util.TypedXmlSerializer; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; Loading Loading @@ -194,32 +192,6 @@ public class FontListParser { return new FontConfig.FontFamily(fonts, name, LocaleList.forLanguageTags(lang), intVariant); } /** * Write a family tag representing {@code fontFamily}. The tag should be started by the caller. */ public static void writeFamily(TypedXmlSerializer out, FontConfig.FontFamily fontFamily) throws IOException { if (!TextUtils.isEmpty(fontFamily.getName())) { out.attribute(null, ATTR_NAME, fontFamily.getName()); } if (!fontFamily.getLocaleList().isEmpty()) { out.attribute(null, ATTR_LANG, fontFamily.getLocaleList().toLanguageTags()); } switch (fontFamily.getVariant()) { case FontConfig.FontFamily.VARIANT_COMPACT: out.attribute(null, ATTR_VARIANT, VARIANT_COMPACT); break; case FontConfig.FontFamily.VARIANT_ELEGANT: out.attribute(null, ATTR_VARIANT, VARIANT_ELEGANT); break; } for (FontConfig.Font font : fontFamily.getFontList()) { out.startTag(null, TAG_FONT); writeFont(out, font); out.endTag(null, TAG_FONT); } } /** Matches leading and trailing XML whitespace. */ private static final Pattern FILENAME_WHITESPACE_PATTERN = Pattern.compile("^[ \\n\\r\\t]+|[ \\n\\r\\t]+$"); Loading Loading @@ -292,34 +264,6 @@ public class FontListParser { return null; } private static void writeFont(TypedXmlSerializer out, FontConfig.Font font) throws IOException { if (font.getTtcIndex() != 0) { out.attributeInt(null, ATTR_INDEX, font.getTtcIndex()); } if (font.getStyle().getWeight() != FontStyle.FONT_WEIGHT_NORMAL) { out.attributeInt(null, ATTR_WEIGHT, font.getStyle().getWeight()); } if (font.getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC) { out.attribute(null, ATTR_STYLE, STYLE_ITALIC); } else { out.attribute(null, ATTR_STYLE, STYLE_NORMAL); } if (!TextUtils.isEmpty(font.getFontFamilyName())) { out.attribute(null, ATTR_FALLBACK_FOR, font.getFontFamilyName()); } out.text(font.getFile().getName()); FontVariationAxis[] axes = FontVariationAxis.fromFontVariationSettings(font.getFontVariationSettings()); if (axes != null) { for (FontVariationAxis axis : axes) { out.startTag(null, TAG_AXIS); writeAxis(out, axis); out.endTag(null, TAG_AXIS); } } } private static FontVariationAxis readAxis(XmlPullParser parser) throws XmlPullParserException, IOException { String tagStr = parser.getAttributeValue(null, ATTR_TAG); Loading @@ -328,12 +272,6 @@ public class FontListParser { return new FontVariationAxis(tagStr, Float.parseFloat(styleValueStr)); } private static void writeAxis(TypedXmlSerializer out, FontVariationAxis axis) throws IOException { out.attribute(null, ATTR_TAG, axis.getTag()); out.attributeFloat(null, ATTR_STYLEVALUE, axis.getStyleValue()); } /** * Reads alias elements */ Loading
services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java +7 −8 Original line number Diff line number Diff line Loading @@ -17,8 +17,7 @@ package com.android.server.graphics.fonts; import android.annotation.NonNull; import android.graphics.FontListParser; import android.text.FontConfig; import android.graphics.fonts.FontUpdateRequest; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; Loading Loading @@ -48,7 +47,7 @@ import java.util.Set; /* package */ static class Config { public long lastModifiedMillis; public final Set<String> updatedFontDirs = new ArraySet<>(); public final List<FontConfig.FontFamily> fontFamilies = new ArrayList<>(); public final List<FontUpdateRequest.Family> fontFamilies = new ArrayList<>(); } /** Loading Loading @@ -81,8 +80,8 @@ import java.util.Set; case TAG_FAMILY: // updatableFontMap is not ready here. We get the base file names by passing // empty fontDir, and resolve font paths later. out.fontFamilies.add(FontListParser.readFamily( parser, "" /* fontDir */, null /* updatableFontMap */)); out.fontFamilies.add(FontUpdateRequest.Family.readFromXml(parser)); break; default: Slog.w(TAG, "Skipping unknown tag: " + tag); } Loading @@ -108,11 +107,11 @@ import java.util.Set; out.attribute(null, ATTR_VALUE, dir); out.endTag(null, TAG_UPDATED_FONT_DIR); } List<FontConfig.FontFamily> fontFamilies = config.fontFamilies; List<FontUpdateRequest.Family> fontFamilies = config.fontFamilies; for (int i = 0; i < fontFamilies.size(); i++) { FontConfig.FontFamily fontFamily = fontFamilies.get(i); FontUpdateRequest.Family fontFamily = fontFamilies.get(i); out.startTag(null, TAG_FAMILY); FontListParser.writeFamily(out, fontFamily); FontUpdateRequest.Family.writeFamilyToXml(out, fontFamily); out.endTag(null, TAG_FAMILY); } out.endTag(null, TAG_ROOT); Loading