diff options
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/graphics/fonts/FontFamilyUpdateRequest.java | 11 | ||||
| -rw-r--r-- | core/java/android/graphics/fonts/FontUpdateRequest.java | 319 |
2 files changed, 312 insertions, 18 deletions
diff --git a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java index 8c7695ad5a5a..fbc951e2f6e6 100644 --- a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java +++ b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java @@ -16,6 +16,7 @@ package android.graphics.fonts; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; @@ -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; + } } /** diff --git a/core/java/android/graphics/fonts/FontUpdateRequest.java b/core/java/android/graphics/fonts/FontUpdateRequest.java index b79c8f62d492..4dd5a72d446e 100644 --- a/core/java/android/graphics/fonts/FontUpdateRequest.java +++ b/core/java/android/graphics/fonts/FontUpdateRequest.java @@ -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. @@ -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) { @@ -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; @@ -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 */)); - } - return new FontConfig.FontFamily(configFonts, postScriptName, - LocaleList.getEmptyLocaleList(), FontConfig.FontFamily.VARIANT_DEFAULT); + updateFonts.add(new Font( + font.getPostScriptName(), + font.getStyle(), + font.getIndex(), + FontVariationAxis.toFontVariationSettings(font.getAxes()))); + } + return new Family(familyName, updateFonts); } protected FontUpdateRequest(Parcel in) { @@ -126,7 +396,7 @@ public final class FontUpdateRequest implements Parcelable { } @Nullable - public FontConfig.FontFamily getFontFamily() { + public Family getFontFamily() { return mFontFamily; } @@ -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; + } + } } |
