Loading core/java/android/graphics/fonts/FontUpdateRequest.java +50 −7 Original line number Diff line number Diff line Loading @@ -16,18 +16,33 @@ package android.graphics.fonts; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.text.FontConfig; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Represents a font update request. Currently only font install request is supported. * @hide */ // TODO: Support font config update. public final class FontUpdateRequest implements Parcelable { public static final int TYPE_UPDATE_FONT_FILE = 0; public static final int TYPE_UPDATE_FONT_FAMILY = 1; @IntDef(prefix = "TYPE_", value = { TYPE_UPDATE_FONT_FILE, TYPE_UPDATE_FONT_FAMILY, }) @Retention(RetentionPolicy.SOURCE) public @interface Type {} public static final Creator<FontUpdateRequest> CREATOR = new Creator<FontUpdateRequest>() { @Override public FontUpdateRequest createFromParcel(Parcel in) { Loading @@ -40,39 +55,67 @@ public final class FontUpdateRequest implements Parcelable { } }; @NonNull private final @Type int mType; // NonNull if mType == TYPE_UPDATE_FONT_FILE. @Nullable private final ParcelFileDescriptor mFd; @NonNull // NonNull if mType == TYPE_UPDATE_FONT_FILE. @Nullable private final byte[] mSignature; // NonNull if mType == TYPE_UPDATE_FONT_FAMILY. @Nullable private final FontConfig.FontFamily mFontFamily; public FontUpdateRequest(@NonNull ParcelFileDescriptor fd, @NonNull byte[] signature) { mType = TYPE_UPDATE_FONT_FILE; mFd = fd; mSignature = signature; mFontFamily = null; } public FontUpdateRequest(@NonNull FontConfig.FontFamily fontFamily) { mType = TYPE_UPDATE_FONT_FAMILY; mFd = null; mSignature = null; mFontFamily = fontFamily; } private FontUpdateRequest(Parcel in) { protected FontUpdateRequest(Parcel in) { mType = in.readInt(); mFd = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); mSignature = in.readBlob(); mFontFamily = in.readParcelable(FontConfig.FontFamily.class.getClassLoader()); } @NonNull public @Type int getType() { return mType; } @Nullable public ParcelFileDescriptor getFd() { return mFd; } @NonNull @Nullable public byte[] getSignature() { return mSignature; } @Nullable public FontConfig.FontFamily getFontFamily() { return mFontFamily; } @Override public int describeContents() { return Parcelable.CONTENTS_FILE_DESCRIPTOR; return mFd != null ? mFd.describeContents() : 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); dest.writeParcelable(mFd, flags); dest.writeBlob(mSignature); dest.writeParcelable(mFontFamily, flags); } } services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java +18 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.graphics.fonts; import android.annotation.NonNull; import android.graphics.FontListParser; import android.text.FontConfig; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; Loading @@ -30,6 +32,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; /* package */ class PersistentSystemFontConfig { Loading @@ -38,11 +42,13 @@ import java.util.Set; private static final String TAG_ROOT = "fontConfig"; private static final String TAG_LAST_MODIFIED_DATE = "lastModifiedDate"; private static final String TAG_UPDATED_FONT_DIR = "updatedFontDir"; private static final String TAG_FAMILY = "family"; private static final String ATTR_VALUE = "value"; /* package */ static class Config { public long lastModifiedDate; public final Set<String> updatedFontDirs = new ArraySet<>(); public final List<FontConfig.FontFamily> fontFamilies = new ArrayList<>(); } /** Loading Loading @@ -72,6 +78,11 @@ import java.util.Set; case TAG_UPDATED_FONT_DIR: out.updatedFontDirs.add(getAttribute(parser, ATTR_VALUE)); break; 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 */)); default: Slog.w(TAG, "Skipping unknown tag: " + tag); } Loading @@ -97,6 +108,13 @@ import java.util.Set; out.attribute(null, ATTR_VALUE, dir); out.endTag(null, TAG_UPDATED_FONT_DIR); } List<FontConfig.FontFamily> fontFamilies = config.fontFamilies; for (int i = 0; i < fontFamilies.size(); i++) { FontConfig.FontFamily fontFamily = fontFamilies.get(i); out.startTag(null, TAG_FAMILY); FontListParser.writeFamily(out, fontFamily); out.endTag(null, TAG_FAMILY); } out.endTag(null, TAG_ROOT); out.endDocument(); Loading services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +94 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ import android.util.ArrayMap; import android.util.Base64; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParserException; import java.io.File; Loading @@ -40,6 +42,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.security.SecureRandom; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Map; Loading Loading @@ -118,6 +121,12 @@ final class UpdatableFontDir { */ private final ArrayMap<String, FontFileInfo> mFontFileInfoMap = new ArrayMap<>(); /** * A mutable map containing mapping from font family name to {@link FontConfig.FontFamily}. * The FontFamily entries only reference font files in {@link #mFontFileInfoMap}. */ private final ArrayMap<String, FontConfig.FontFamily> mFontFamilyMap = new ArrayMap<>(); UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser, FsverityUtil fsverityUtil) { this(filesDir, preinstalledFontDirs, parser, fsverityUtil, new File(CONFIG_XML_FILE)); Loading @@ -136,6 +145,7 @@ final class UpdatableFontDir { /* package */ void loadFontFileMap() { mFontFileInfoMap.clear(); mFontFamilyMap.clear(); mLastModifiedDate = 0; boolean success = false; try { Loading Loading @@ -168,6 +178,13 @@ final class UpdatableFontDir { FontFileInfo fontFileInfo = validateFontFile(files[0]); addFileToMapIfNewer(fontFileInfo, true /* deleteOldFile */); } // Resolve font file paths. List<FontConfig.FontFamily> fontFamilies = config.fontFamilies; for (int i = 0; i < fontFamilies.size(); i++) { FontConfig.FontFamily fontFamily = fontFamilies.get(i); // Ignore failures as updated fonts may be obsoleted by system OTA update. addFontFamily(fontFamily); } success = true; } catch (Throwable t) { // If something happened during loading system fonts, clear all contents in finally Loading @@ -177,6 +194,7 @@ final class UpdatableFontDir { // Delete all files just in case if we find a problematic file. if (!success) { mFontFileInfoMap.clear(); mFontFamilyMap.clear(); mLastModifiedDate = 0; FileUtils.deleteContents(mFilesDir); } Loading @@ -186,10 +204,11 @@ final class UpdatableFontDir { /* package */ void clearUpdates() throws SystemFontException { mFontFileInfoMap.clear(); FileUtils.deleteContents(mFilesDir); mFontFamilyMap.clear(); mLastModifiedDate = Instant.now().getEpochSecond(); try (FileOutputStream fos = new FileOutputStream(mConfigFile)) { PersistentSystemFontConfig.writeToXml(fos, getPersistentConfig()); PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig()); } catch (Exception e) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, Loading @@ -206,17 +225,29 @@ final class UpdatableFontDir { public void update(List<FontUpdateRequest> requests) throws SystemFontException { // Backup the mapping for rollback. ArrayMap<String, FontFileInfo> backupMap = new ArrayMap<>(mFontFileInfoMap); ArrayMap<String, FontConfig.FontFamily> backupFamilies = new ArrayMap<>(mFontFamilyMap); long backupLastModifiedDate = mLastModifiedDate; boolean success = false; try { for (FontUpdateRequest request : requests) { installFontFile(request.getFd().getFileDescriptor(), request.getSignature()); switch (request.getType()) { case FontUpdateRequest.TYPE_UPDATE_FONT_FILE: installFontFile( request.getFd().getFileDescriptor(), request.getSignature()); break; case FontUpdateRequest.TYPE_UPDATE_FONT_FAMILY: // TODO: define error code. if (!addFontFamily(request.getFontFamily())) { throw new IllegalArgumentException("Invalid font family"); } break; } } // Write config file. mLastModifiedDate = Instant.now().getEpochSecond(); try (FileOutputStream fos = new FileOutputStream(mTmpConfigFile)) { PersistentSystemFontConfig.writeToXml(fos, getPersistentConfig()); PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig()); } catch (Exception e) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, Loading @@ -234,6 +265,8 @@ final class UpdatableFontDir { if (!success) { mFontFileInfoMap.clear(); mFontFileInfoMap.putAll(backupMap); mFontFamilyMap.clear(); mFontFamilyMap.putAll(backupFamilies); mLastModifiedDate = backupLastModifiedDate; } } Loading Loading @@ -454,12 +487,52 @@ final class UpdatableFontDir { } } private PersistentSystemFontConfig.Config getPersistentConfig() { /** * Adds a font family to {@link #mFontFamilyMap} and returns true on success. * * <p>This method only accepts adding or updating a font family with a name. * This is to prevent bad font family update from removing glyphs from font fallback chains. * Unnamed font families are used as other named font family's fallback fonts to guarantee a * complete glyph coverage. */ private boolean addFontFamily(FontConfig.FontFamily fontFamily) { if (fontFamily.getName() == null) { Slog.e(TAG, "Name is null."); return false; } FontConfig.FontFamily resolvedFontFamily = resolveFontFiles(fontFamily); if (resolvedFontFamily == null) { Slog.e(TAG, "Required fonts are not available"); return false; } mFontFamilyMap.put(resolvedFontFamily.getName(), resolvedFontFamily); return true; } @Nullable private FontConfig.FontFamily resolveFontFiles(FontConfig.FontFamily fontFamily) { List<FontConfig.Font> resolvedFonts = new ArrayList<>(fontFamily.getFontList().size()); List<FontConfig.Font> fontList = fontFamily.getFontList(); for (int i = 0; i < fontList.size(); i++) { FontConfig.Font font = fontList.get(i); FontFileInfo info = mFontFileInfoMap.get(font.getFile().getName()); if (info == null) { return null; } resolvedFonts.add(new FontConfig.Font(info.mFile, null, font.getStyle(), font.getTtcIndex(), font.getFontVariationSettings(), font.getFontFamilyName())); } return new FontConfig.FontFamily(resolvedFonts, fontFamily.getName(), fontFamily.getLocaleList(), fontFamily.getVariant()); } private PersistentSystemFontConfig.Config createPersistentConfig() { PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config(); config.lastModifiedDate = mLastModifiedDate; for (FontFileInfo info : mFontFileInfoMap.values()) { config.updatedFontDirs.add(info.getRandomizedFontDir().getName()); } config.fontFamilies.addAll(mFontFamilyMap.values()); return config; } Loading @@ -471,8 +544,24 @@ final class UpdatableFontDir { return map; } @VisibleForTesting Map<String, FontConfig.FontFamily> getFontFamilyMap() { return mFontFamilyMap; } /* package */ FontConfig getSystemFontConfig() { return SystemFonts.getSystemFontConfig(getFontFileMap(), mLastModifiedDate, mConfigVersion); FontConfig config = SystemFonts.getSystemFontConfig(getFontFileMap(), 0, 0); List<FontConfig.FontFamily> mergedFamilies = new ArrayList<>(config.getFontFamilies().size() + mFontFamilyMap.size()); // We should keep the first font family (config.getFontFamilies().get(0)) because it's used // as a fallback font. See SystemFonts.java. mergedFamilies.addAll(config.getFontFamilies()); // When building Typeface, a latter font family definition will override the previous font // family definition with the same name. An exception is config.getFontFamilies.get(0), // which will be used as a fallback font without being overridden. mergedFamilies.addAll(mFontFamilyMap.values()); return new FontConfig( mergedFamilies, config.getAliases(), mLastModifiedDate, mConfigVersion); } /* package */ int getConfigVersion() { Loading services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java +19 −1 Original line number Diff line number Diff line Loading @@ -18,13 +18,17 @@ package com.android.server.graphics.fonts; import static com.google.common.truth.Truth.assertThat; import android.graphics.FontListParser; import android.platform.test.annotations.Presubmit; import android.text.FontConfig; import android.util.Xml; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; Loading @@ -38,13 +42,19 @@ import java.nio.charset.StandardCharsets; public final class PersistentSystemFontConfigTest { @Test public void testWriteRead() throws IOException, XmlPullParserException { public void testWriteRead() throws Exception { long expectedModifiedDate = 1234567890; PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config(); config.lastModifiedDate = expectedModifiedDate; config.updatedFontDirs.add("~~abc"); config.updatedFontDirs.add("~~def"); FontConfig.FontFamily fontFamily = parseFontFamily( "<family name='test'>" + " <font>test.ttf</font>" + "</family>"); config.fontFamilies.add(fontFamily); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PersistentSystemFontConfig.writeToXml(baos, config); Loading @@ -57,6 +67,7 @@ public final class PersistentSystemFontConfigTest { assertThat(another.lastModifiedDate).isEqualTo(expectedModifiedDate); assertThat(another.updatedFontDirs).containsExactly("~~abc", "~~def"); assertThat(another.fontFamilies).containsExactly(fontFamily); } } } Loading @@ -75,4 +86,11 @@ public final class PersistentSystemFontConfigTest { } } private static FontConfig.FontFamily parseFontFamily(String xml) throws Exception { XmlPullParser parser = Xml.newPullParser(); ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); parser.setInput(is, "UTF-8"); parser.nextTag(); return FontListParser.readFamily(parser, "", null); } } services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +204 −9 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/graphics/fonts/FontUpdateRequest.java +50 −7 Original line number Diff line number Diff line Loading @@ -16,18 +16,33 @@ package android.graphics.fonts; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.text.FontConfig; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * Represents a font update request. Currently only font install request is supported. * @hide */ // TODO: Support font config update. public final class FontUpdateRequest implements Parcelable { public static final int TYPE_UPDATE_FONT_FILE = 0; public static final int TYPE_UPDATE_FONT_FAMILY = 1; @IntDef(prefix = "TYPE_", value = { TYPE_UPDATE_FONT_FILE, TYPE_UPDATE_FONT_FAMILY, }) @Retention(RetentionPolicy.SOURCE) public @interface Type {} public static final Creator<FontUpdateRequest> CREATOR = new Creator<FontUpdateRequest>() { @Override public FontUpdateRequest createFromParcel(Parcel in) { Loading @@ -40,39 +55,67 @@ public final class FontUpdateRequest implements Parcelable { } }; @NonNull private final @Type int mType; // NonNull if mType == TYPE_UPDATE_FONT_FILE. @Nullable private final ParcelFileDescriptor mFd; @NonNull // NonNull if mType == TYPE_UPDATE_FONT_FILE. @Nullable private final byte[] mSignature; // NonNull if mType == TYPE_UPDATE_FONT_FAMILY. @Nullable private final FontConfig.FontFamily mFontFamily; public FontUpdateRequest(@NonNull ParcelFileDescriptor fd, @NonNull byte[] signature) { mType = TYPE_UPDATE_FONT_FILE; mFd = fd; mSignature = signature; mFontFamily = null; } public FontUpdateRequest(@NonNull FontConfig.FontFamily fontFamily) { mType = TYPE_UPDATE_FONT_FAMILY; mFd = null; mSignature = null; mFontFamily = fontFamily; } private FontUpdateRequest(Parcel in) { protected FontUpdateRequest(Parcel in) { mType = in.readInt(); mFd = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); mSignature = in.readBlob(); mFontFamily = in.readParcelable(FontConfig.FontFamily.class.getClassLoader()); } @NonNull public @Type int getType() { return mType; } @Nullable public ParcelFileDescriptor getFd() { return mFd; } @NonNull @Nullable public byte[] getSignature() { return mSignature; } @Nullable public FontConfig.FontFamily getFontFamily() { return mFontFamily; } @Override public int describeContents() { return Parcelable.CONTENTS_FILE_DESCRIPTOR; return mFd != null ? mFd.describeContents() : 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); dest.writeParcelable(mFd, flags); dest.writeBlob(mSignature); dest.writeParcelable(mFontFamily, flags); } }
services/core/java/com/android/server/graphics/fonts/PersistentSystemFontConfig.java +18 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,8 @@ package com.android.server.graphics.fonts; import android.annotation.NonNull; import android.graphics.FontListParser; import android.text.FontConfig; import android.text.TextUtils; import android.util.ArraySet; import android.util.Slog; Loading @@ -30,6 +32,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Set; /* package */ class PersistentSystemFontConfig { Loading @@ -38,11 +42,13 @@ import java.util.Set; private static final String TAG_ROOT = "fontConfig"; private static final String TAG_LAST_MODIFIED_DATE = "lastModifiedDate"; private static final String TAG_UPDATED_FONT_DIR = "updatedFontDir"; private static final String TAG_FAMILY = "family"; private static final String ATTR_VALUE = "value"; /* package */ static class Config { public long lastModifiedDate; public final Set<String> updatedFontDirs = new ArraySet<>(); public final List<FontConfig.FontFamily> fontFamilies = new ArrayList<>(); } /** Loading Loading @@ -72,6 +78,11 @@ import java.util.Set; case TAG_UPDATED_FONT_DIR: out.updatedFontDirs.add(getAttribute(parser, ATTR_VALUE)); break; 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 */)); default: Slog.w(TAG, "Skipping unknown tag: " + tag); } Loading @@ -97,6 +108,13 @@ import java.util.Set; out.attribute(null, ATTR_VALUE, dir); out.endTag(null, TAG_UPDATED_FONT_DIR); } List<FontConfig.FontFamily> fontFamilies = config.fontFamilies; for (int i = 0; i < fontFamilies.size(); i++) { FontConfig.FontFamily fontFamily = fontFamilies.get(i); out.startTag(null, TAG_FAMILY); FontListParser.writeFamily(out, fontFamily); out.endTag(null, TAG_FAMILY); } out.endTag(null, TAG_ROOT); out.endDocument(); Loading
services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +94 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,8 @@ import android.util.ArrayMap; import android.util.Base64; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParserException; import java.io.File; Loading @@ -40,6 +42,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.security.SecureRandom; import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Map; Loading Loading @@ -118,6 +121,12 @@ final class UpdatableFontDir { */ private final ArrayMap<String, FontFileInfo> mFontFileInfoMap = new ArrayMap<>(); /** * A mutable map containing mapping from font family name to {@link FontConfig.FontFamily}. * The FontFamily entries only reference font files in {@link #mFontFileInfoMap}. */ private final ArrayMap<String, FontConfig.FontFamily> mFontFamilyMap = new ArrayMap<>(); UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser, FsverityUtil fsverityUtil) { this(filesDir, preinstalledFontDirs, parser, fsverityUtil, new File(CONFIG_XML_FILE)); Loading @@ -136,6 +145,7 @@ final class UpdatableFontDir { /* package */ void loadFontFileMap() { mFontFileInfoMap.clear(); mFontFamilyMap.clear(); mLastModifiedDate = 0; boolean success = false; try { Loading Loading @@ -168,6 +178,13 @@ final class UpdatableFontDir { FontFileInfo fontFileInfo = validateFontFile(files[0]); addFileToMapIfNewer(fontFileInfo, true /* deleteOldFile */); } // Resolve font file paths. List<FontConfig.FontFamily> fontFamilies = config.fontFamilies; for (int i = 0; i < fontFamilies.size(); i++) { FontConfig.FontFamily fontFamily = fontFamilies.get(i); // Ignore failures as updated fonts may be obsoleted by system OTA update. addFontFamily(fontFamily); } success = true; } catch (Throwable t) { // If something happened during loading system fonts, clear all contents in finally Loading @@ -177,6 +194,7 @@ final class UpdatableFontDir { // Delete all files just in case if we find a problematic file. if (!success) { mFontFileInfoMap.clear(); mFontFamilyMap.clear(); mLastModifiedDate = 0; FileUtils.deleteContents(mFilesDir); } Loading @@ -186,10 +204,11 @@ final class UpdatableFontDir { /* package */ void clearUpdates() throws SystemFontException { mFontFileInfoMap.clear(); FileUtils.deleteContents(mFilesDir); mFontFamilyMap.clear(); mLastModifiedDate = Instant.now().getEpochSecond(); try (FileOutputStream fos = new FileOutputStream(mConfigFile)) { PersistentSystemFontConfig.writeToXml(fos, getPersistentConfig()); PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig()); } catch (Exception e) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, Loading @@ -206,17 +225,29 @@ final class UpdatableFontDir { public void update(List<FontUpdateRequest> requests) throws SystemFontException { // Backup the mapping for rollback. ArrayMap<String, FontFileInfo> backupMap = new ArrayMap<>(mFontFileInfoMap); ArrayMap<String, FontConfig.FontFamily> backupFamilies = new ArrayMap<>(mFontFamilyMap); long backupLastModifiedDate = mLastModifiedDate; boolean success = false; try { for (FontUpdateRequest request : requests) { installFontFile(request.getFd().getFileDescriptor(), request.getSignature()); switch (request.getType()) { case FontUpdateRequest.TYPE_UPDATE_FONT_FILE: installFontFile( request.getFd().getFileDescriptor(), request.getSignature()); break; case FontUpdateRequest.TYPE_UPDATE_FONT_FAMILY: // TODO: define error code. if (!addFontFamily(request.getFontFamily())) { throw new IllegalArgumentException("Invalid font family"); } break; } } // Write config file. mLastModifiedDate = Instant.now().getEpochSecond(); try (FileOutputStream fos = new FileOutputStream(mTmpConfigFile)) { PersistentSystemFontConfig.writeToXml(fos, getPersistentConfig()); PersistentSystemFontConfig.writeToXml(fos, createPersistentConfig()); } catch (Exception e) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, Loading @@ -234,6 +265,8 @@ final class UpdatableFontDir { if (!success) { mFontFileInfoMap.clear(); mFontFileInfoMap.putAll(backupMap); mFontFamilyMap.clear(); mFontFamilyMap.putAll(backupFamilies); mLastModifiedDate = backupLastModifiedDate; } } Loading Loading @@ -454,12 +487,52 @@ final class UpdatableFontDir { } } private PersistentSystemFontConfig.Config getPersistentConfig() { /** * Adds a font family to {@link #mFontFamilyMap} and returns true on success. * * <p>This method only accepts adding or updating a font family with a name. * This is to prevent bad font family update from removing glyphs from font fallback chains. * Unnamed font families are used as other named font family's fallback fonts to guarantee a * complete glyph coverage. */ private boolean addFontFamily(FontConfig.FontFamily fontFamily) { if (fontFamily.getName() == null) { Slog.e(TAG, "Name is null."); return false; } FontConfig.FontFamily resolvedFontFamily = resolveFontFiles(fontFamily); if (resolvedFontFamily == null) { Slog.e(TAG, "Required fonts are not available"); return false; } mFontFamilyMap.put(resolvedFontFamily.getName(), resolvedFontFamily); return true; } @Nullable private FontConfig.FontFamily resolveFontFiles(FontConfig.FontFamily fontFamily) { List<FontConfig.Font> resolvedFonts = new ArrayList<>(fontFamily.getFontList().size()); List<FontConfig.Font> fontList = fontFamily.getFontList(); for (int i = 0; i < fontList.size(); i++) { FontConfig.Font font = fontList.get(i); FontFileInfo info = mFontFileInfoMap.get(font.getFile().getName()); if (info == null) { return null; } resolvedFonts.add(new FontConfig.Font(info.mFile, null, font.getStyle(), font.getTtcIndex(), font.getFontVariationSettings(), font.getFontFamilyName())); } return new FontConfig.FontFamily(resolvedFonts, fontFamily.getName(), fontFamily.getLocaleList(), fontFamily.getVariant()); } private PersistentSystemFontConfig.Config createPersistentConfig() { PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config(); config.lastModifiedDate = mLastModifiedDate; for (FontFileInfo info : mFontFileInfoMap.values()) { config.updatedFontDirs.add(info.getRandomizedFontDir().getName()); } config.fontFamilies.addAll(mFontFamilyMap.values()); return config; } Loading @@ -471,8 +544,24 @@ final class UpdatableFontDir { return map; } @VisibleForTesting Map<String, FontConfig.FontFamily> getFontFamilyMap() { return mFontFamilyMap; } /* package */ FontConfig getSystemFontConfig() { return SystemFonts.getSystemFontConfig(getFontFileMap(), mLastModifiedDate, mConfigVersion); FontConfig config = SystemFonts.getSystemFontConfig(getFontFileMap(), 0, 0); List<FontConfig.FontFamily> mergedFamilies = new ArrayList<>(config.getFontFamilies().size() + mFontFamilyMap.size()); // We should keep the first font family (config.getFontFamilies().get(0)) because it's used // as a fallback font. See SystemFonts.java. mergedFamilies.addAll(config.getFontFamilies()); // When building Typeface, a latter font family definition will override the previous font // family definition with the same name. An exception is config.getFontFamilies.get(0), // which will be used as a fallback font without being overridden. mergedFamilies.addAll(mFontFamilyMap.values()); return new FontConfig( mergedFamilies, config.getAliases(), mLastModifiedDate, mConfigVersion); } /* package */ int getConfigVersion() { Loading
services/tests/servicestests/src/com/android/server/graphics/fonts/PersistentSystemFontConfigTest.java +19 −1 Original line number Diff line number Diff line Loading @@ -18,13 +18,17 @@ package com.android.server.graphics.fonts; import static com.google.common.truth.Truth.assertThat; import android.graphics.FontListParser; import android.platform.test.annotations.Presubmit; import android.text.FontConfig; import android.util.Xml; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.ByteArrayInputStream; Loading @@ -38,13 +42,19 @@ import java.nio.charset.StandardCharsets; public final class PersistentSystemFontConfigTest { @Test public void testWriteRead() throws IOException, XmlPullParserException { public void testWriteRead() throws Exception { long expectedModifiedDate = 1234567890; PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config(); config.lastModifiedDate = expectedModifiedDate; config.updatedFontDirs.add("~~abc"); config.updatedFontDirs.add("~~def"); FontConfig.FontFamily fontFamily = parseFontFamily( "<family name='test'>" + " <font>test.ttf</font>" + "</family>"); config.fontFamilies.add(fontFamily); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { PersistentSystemFontConfig.writeToXml(baos, config); Loading @@ -57,6 +67,7 @@ public final class PersistentSystemFontConfigTest { assertThat(another.lastModifiedDate).isEqualTo(expectedModifiedDate); assertThat(another.updatedFontDirs).containsExactly("~~abc", "~~def"); assertThat(another.fontFamilies).containsExactly(fontFamily); } } } Loading @@ -75,4 +86,11 @@ public final class PersistentSystemFontConfigTest { } } private static FontConfig.FontFamily parseFontFamily(String xml) throws Exception { XmlPullParser parser = Xml.newPullParser(); ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); parser.setInput(is, "UTF-8"); parser.nextTag(); return FontListParser.readFamily(parser, "", null); } }
services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +204 −9 File changed.Preview size limit exceeded, changes collapsed. Show changes