diff options
11 files changed, 509 insertions, 31 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index bfdce373a47e..178efba4fd20 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2810,16 +2810,48 @@ package android.debug { package android.graphics.fonts { + public final class FontFamilyUpdateRequest { + method @NonNull public java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.FontFamily> getFontFamilies(); + method @NonNull public java.util.List<android.graphics.fonts.FontFileUpdateRequest> getFontFileUpdateRequests(); + } + + public static final class FontFamilyUpdateRequest.Builder { + ctor public FontFamilyUpdateRequest.Builder(); + method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.Builder addFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest.FontFamily); + method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest.Builder addFontFileUpdateRequest(@NonNull android.graphics.fonts.FontFileUpdateRequest); + method @NonNull public android.graphics.fonts.FontFamilyUpdateRequest build(); + } + + public static final class FontFamilyUpdateRequest.Font { + ctor public FontFamilyUpdateRequest.Font(@NonNull String, @NonNull android.graphics.fonts.FontStyle, @NonNull java.util.List<android.graphics.fonts.FontVariationAxis>); + method @NonNull public java.util.List<android.graphics.fonts.FontVariationAxis> getAxes(); + method @NonNull public String getPostScriptName(); + method @NonNull public android.graphics.fonts.FontStyle getStyle(); + } + + public static final class FontFamilyUpdateRequest.FontFamily { + ctor public FontFamilyUpdateRequest.FontFamily(@NonNull String, @NonNull java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.Font>); + method @NonNull public java.util.List<android.graphics.fonts.FontFamilyUpdateRequest.Font> getFonts(); + method @NonNull public String getName(); + } + + public final class FontFileUpdateRequest { + ctor public FontFileUpdateRequest(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[]); + method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor(); + method @NonNull public byte[] getSignature(); + } + public class FontManager { method @Nullable public android.text.FontConfig getFontConfig(); + method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int); method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int); field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff field public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; // 0xfffffffa + field public static final int RESULT_ERROR_FONT_NOT_FOUND = -9; // 0xfffffff7 field public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7; // 0xfffffff9 field public static final int RESULT_ERROR_INVALID_FONT_FILE = -3; // 0xfffffffd field public static final int RESULT_ERROR_INVALID_FONT_NAME = -4; // 0xfffffffc - field public static final int RESULT_ERROR_REMOTE_EXCEPTION = -9; // 0xfffffff7 field public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2; // 0xfffffffe field public static final int RESULT_ERROR_VERSION_MISMATCH = -8; // 0xfffffff8 field public static final int RESULT_SUCCESS = 0; // 0x0 diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 06110319cb35..4d2db4d2bbdd 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -836,14 +836,15 @@ package android.graphics.fonts { public class FontManager { method @Nullable public android.text.FontConfig getFontConfig(); + method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFamily(@NonNull android.graphics.fonts.FontFamilyUpdateRequest, @IntRange(from=0) int); method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int); field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff field public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; // 0xfffffffa + field public static final int RESULT_ERROR_FONT_NOT_FOUND = -9; // 0xfffffff7 field public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7; // 0xfffffff9 field public static final int RESULT_ERROR_INVALID_FONT_FILE = -3; // 0xfffffffd field public static final int RESULT_ERROR_INVALID_FONT_NAME = -4; // 0xfffffffc - field public static final int RESULT_ERROR_REMOTE_EXCEPTION = -9; // 0xfffffff7 field public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2; // 0xfffffffe field public static final int RESULT_ERROR_VERSION_MISMATCH = -8; // 0xfffffff8 field public static final int RESULT_SUCCESS = 0; // 0x0 diff --git a/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java new file mode 100644 index 000000000000..25758e9d9a61 --- /dev/null +++ b/core/java/android/graphics/fonts/FontFamilyUpdateRequest.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.fonts; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Request for updating or adding a font family on the system. + * + * <p>You can update or add a font family with custom style parameters. The following example + * defines a font family called "roboto" using "Roboto-Regular" font file that is already available + * on the system by preloading or {@link FontManager#updateFontFile}. + * <pre> + * FontManager fm = getContext().getSystemService(FontManager.class); + * fm.updateFontFamily(new FontFamilyUpdateRequest.Builder() + * .addFontFamily(new FontFamilyUpdateRequest.FontFamily("roboto", Arrays.asList( + * new FontFamilyUpdateRequest.Font( + * "Roboto-Regular", + * new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), + * Collections.emptyList()), + * new FontFamilyUpdateRequest.Font( + * "Roboto-Regular", + * new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC), + * Collections.emptyList())))) + * .build(), fm.getFontConfig().getConfigVersion()); + * </pre> + * + * <p>You can update or add font files in the same request by calling + * {@link FontFamilyUpdateRequest.Builder#addFontFileUpdateRequest(FontFileUpdateRequest)}. + * The following example adds "YourFont" font file and defines "your-font" font family in the same + * request. In this case, the font file represented by {@code yourFontFd} should be an OpenType + * compliant font file and have "YourFont" as PostScript name (ID=6) in 'name' table. + * <pre> + * FontManager fm = getContext().getSystemService(FontManager.class); + * fm.updateFontFamily(new FontFamilyUpdateRequest.Builder() + * .addFontFileUpdateRequest(new FontFileUpdateRequest(yourFontFd, signature)) + * .addFontFamily(new FontFamilyUpdateRequest.FontFamily("your-font", Arrays.asList( + * new FontFamilyUpdateRequest.Font( + * "YourFont", + * new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT), + * Collections.emptyList())))) + * .build(), fm.getFontConfig().getConfigVersion()); + * </pre> + * + * @hide + */ +@SystemApi +public final class FontFamilyUpdateRequest { + + /** + * A font family definition. + */ + public static final class FontFamily { + @NonNull + private final String mName; + @NonNull + private final List<Font> mFonts; + + /** + * Constructs a FontFamily. + * + * <p>A font family has a name to identify the font family. Apps can use + * {@link android.graphics.Typeface#create(String, int)} or XML resources to use a specific + * font family. + * + * <p>A font family consists of multiple fonts with different styles. The style information + * can be specified by {@link Font}. + * + * @see android.graphics.Typeface#create(String, int) + * @see Font + */ + public FontFamily(@NonNull String name, @NonNull List<Font> fonts) { + Objects.requireNonNull(name); + Preconditions.checkStringNotEmpty(name); + Objects.requireNonNull(fonts); + Preconditions.checkCollectionElementsNotNull(fonts, "fonts"); + Preconditions.checkCollectionNotEmpty(fonts, "fonts"); + mName = name; + mFonts = fonts; + } + + /** + * Returns the name of this family. + */ + @NonNull + public String getName() { + return mName; + } + + /** + * Returns the fonts in this family. + */ + @NonNull + public List<Font> getFonts() { + return mFonts; + } + } + + /** + * A single entry in a font family representing a font. + */ + public static final class Font { + + @NonNull + private final String mPostScriptName; + @NonNull + private final FontStyle mStyle; + @NonNull + private final List<FontVariationAxis> mAxes; + + /** + * Constructs a FontStyleVariation. + * + * <p>A font has a PostScript name to identify the font file to use, a {@link FontStyle} + * to specify the style, and a list of {@link FontVariationAxis} to specify axis tags and + * values for variable fonts. If the font file identified by {@code postScriptName} is not a + * variable font, {@code axes} must be empty. + * + * @param postScriptName The PostScript name of the font file to use. PostScript name is in + * Name ID 6 field in 'name' table, as specified by OpenType + * specification. + * @param style The style for this font. + * @param axes A list of {@link FontVariationAxis} to specify axis tags and values + * for variable fonts. + */ + public Font(@NonNull String postScriptName, @NonNull FontStyle style, + @NonNull List<FontVariationAxis> axes) { + Objects.requireNonNull(postScriptName); + Preconditions.checkStringNotEmpty(postScriptName); + Objects.requireNonNull(style); + Objects.requireNonNull(axes); + Preconditions.checkCollectionElementsNotNull(axes, "axes"); + mPostScriptName = postScriptName; + mStyle = style; + mAxes = axes; + } + + /** + * Returns PostScript name of the font file to use. + */ + @NonNull + public String getPostScriptName() { + return mPostScriptName; + } + + /** + * Returns the style. + */ + @NonNull + public FontStyle getStyle() { + return mStyle; + } + + /** + * Returns the list of {@link FontVariationAxis}. + */ + @NonNull + public List<FontVariationAxis> getAxes() { + return mAxes; + } + } + + /** + * Builds a {@link FontFamilyUpdateRequest}. + */ + public static final class Builder { + @NonNull + private final List<FontFileUpdateRequest> mFontFileUpdateRequests = new ArrayList<>(); + @NonNull + private final List<FontFamily> mFontFamilies = new ArrayList<>(); + + /** + * Constructs a FontFamilyUpdateRequest.Builder. + */ + public Builder() { + } + + /** + * Adds a {@link FontFileUpdateRequest} to execute as a part of the constructed + * {@link FontFamilyUpdateRequest}. + * + * @param request A font file update request. + * @return This builder object. + */ + @NonNull + public Builder addFontFileUpdateRequest(@NonNull FontFileUpdateRequest request) { + Objects.requireNonNull(request); + mFontFileUpdateRequests.add(request); + return this; + } + + /** + * Adds a font family to update an existing font family in the system font config or + * add as a new font family to the system font config. + * + * @param fontFamily An font family definition to add or update. + * @return This builder object. + */ + @NonNull + public Builder addFontFamily(@NonNull FontFamily fontFamily) { + Objects.requireNonNull(fontFamily); + mFontFamilies.add(fontFamily); + return this; + } + + /** + * Builds a {@link FontFamilyUpdateRequest}. + */ + @NonNull + public FontFamilyUpdateRequest build() { + return new FontFamilyUpdateRequest(mFontFileUpdateRequests, mFontFamilies); + } + } + + @NonNull + private final List<FontFileUpdateRequest> mFontFiles; + + @NonNull + private final List<FontFamily> mFontFamilies; + + private FontFamilyUpdateRequest(@NonNull List<FontFileUpdateRequest> fontFiles, + @NonNull List<FontFamily> fontFamilies) { + mFontFiles = fontFiles; + mFontFamilies = fontFamilies; + } + + /** + * Returns the list of {@link FontFileUpdateRequest} that will be executed as a part of this + * request. + */ + @NonNull + public List<FontFileUpdateRequest> getFontFileUpdateRequests() { + return mFontFiles; + } + + /** + * Returns the list of {@link FontFamily} that will be updated in this request. + */ + @NonNull + public List<FontFamily> getFontFamilies() { + return mFontFamilies; + } +} diff --git a/core/java/android/graphics/fonts/FontFileUpdateRequest.java b/core/java/android/graphics/fonts/FontFileUpdateRequest.java new file mode 100644 index 000000000000..cf1dca965216 --- /dev/null +++ b/core/java/android/graphics/fonts/FontFileUpdateRequest.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.fonts; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.ParcelFileDescriptor; + +import java.util.Objects; + +/** + * Request for updating a font file on the system. + * + * @hide + */ +@SystemApi +public final class FontFileUpdateRequest { + + private final ParcelFileDescriptor mParcelFileDescriptor; + private final byte[] mSignature; + + /** + * Creates a FontFileUpdateRequest with the given file and signature. + * + * @param parcelFileDescriptor A file descriptor of the font file. + * @param signature A PKCS#7 detached signature for verifying the font file. + */ + public FontFileUpdateRequest(@NonNull ParcelFileDescriptor parcelFileDescriptor, + @NonNull byte[] signature) { + Objects.requireNonNull(parcelFileDescriptor); + Objects.requireNonNull(signature); + mParcelFileDescriptor = parcelFileDescriptor; + mSignature = signature; + } + + /** + * Returns the file descriptor of the font file. + */ + @NonNull + public ParcelFileDescriptor getParcelFileDescriptor() { + return mParcelFileDescriptor; + } + + /** + * Returns the PKCS#7 detached signature for verifying the font file. + */ + @NonNull + public byte[] getSignature() { + return mSignature; + } +} diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java index abb4f9fa7eef..f087dd075816 100644 --- a/core/java/android/graphics/fonts/FontManager.java +++ b/core/java/android/graphics/fonts/FontManager.java @@ -35,6 +35,8 @@ import com.android.internal.graphics.fonts.IFontManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -58,7 +60,7 @@ public class FontManager { RESULT_ERROR_VERIFICATION_FAILURE, RESULT_ERROR_VERSION_MISMATCH, RESULT_ERROR_INVALID_FONT_FILE, RESULT_ERROR_INVALID_FONT_NAME, RESULT_ERROR_DOWNGRADING, RESULT_ERROR_FAILED_UPDATE_CONFIG, - RESULT_ERROR_FONT_UPDATER_DISABLED, RESULT_ERROR_REMOTE_EXCEPTION }) + RESULT_ERROR_FONT_UPDATER_DISABLED, RESULT_ERROR_FONT_NOT_FOUND }) @Retention(RetentionPolicy.SOURCE) public @interface ResultCode {} @@ -131,9 +133,10 @@ public class FontManager { public static final int RESULT_ERROR_VERSION_MISMATCH = -8; /** - * Indicates a failure due to IPC communication. + * Indicates a failure occurred because a font with the specified PostScript name could not be + * found. */ - public static final int RESULT_ERROR_REMOTE_EXCEPTION = -9; + public static final int RESULT_ERROR_FONT_NOT_FOUND = -9; /** * Indicates a failure of opening font file. @@ -253,7 +256,6 @@ public class FontManager { * @see #RESULT_ERROR_DOWNGRADING * @see #RESULT_ERROR_FAILED_UPDATE_CONFIG * @see #RESULT_ERROR_FONT_UPDATER_DISABLED - * @see #RESULT_ERROR_REMOTE_EXCEPTION */ @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @ResultCode int updateFontFile( @NonNull ParcelFileDescriptor pfd, @@ -261,10 +263,69 @@ public class FontManager { @IntRange(from = 0) int baseVersion ) { try { - return mIFontManager.updateFont(baseVersion, new FontUpdateRequest(pfd, signature)); + return mIFontManager.updateFontFile(new FontUpdateRequest(pfd, signature), baseVersion); } catch (RemoteException e) { - Log.e(TAG, "Failed to call updateFont API", e); - return RESULT_ERROR_REMOTE_EXCEPTION; + throw e.rethrowFromSystemServer(); + } + } + + /** + * Update or add system wide font families. + * + * <p>This method will update existing font families or add new font families. The updated + * font family definitions will be used when creating {@link android.graphics.Typeface} objects + * with using {@link android.graphics.Typeface#create(String, int)} specifying the family name, + * or through XML resources. Note that system fallback fonts cannot be modified by this method. + * Apps must use {@link android.graphics.Typeface.CustomFallbackBuilder} to use custom fallback + * fonts. + * + * <p>Font files can be updated by including {@link FontFileUpdateRequest} to {@code request} + * via {@link FontFamilyUpdateRequest.Builder#addFontFileUpdateRequest(FontFileUpdateRequest)}. + * The same constraints as {@link #updateFontFile} will apply when updating font files. + * + * <p>The caller must specify the base config version for keeping the font configuration + * consistent. If the font configuration is updated for some reason between the time you get + * a configuration with {@link #getFontConfig()} and the time when you call this method, + * {@link #RESULT_ERROR_VERSION_MISMATCH} will be returned. Get the latest font configuration by + * calling {@link #getFontConfig()} and call this method again with the latest config version. + * + * @param request A {@link FontFamilyUpdateRequest} to execute. + * @param baseVersion A base config version to be updated. You can get the latest config version + * by {@link FontConfig#getConfigVersion()} via {@link #getFontConfig()}. If + * the system has a newer config version, the update will fail with + * {@link #RESULT_ERROR_VERSION_MISMATCH}. + * @return A result code. + * @see FontConfig#getConfigVersion() + * @see #getFontConfig() + * @see #RESULT_SUCCESS + * @see #RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE + * @see #RESULT_ERROR_VERIFICATION_FAILURE + * @see #RESULT_ERROR_VERSION_MISMATCH + * @see #RESULT_ERROR_INVALID_FONT_FILE + * @see #RESULT_ERROR_INVALID_FONT_NAME + * @see #RESULT_ERROR_DOWNGRADING + * @see #RESULT_ERROR_FAILED_UPDATE_CONFIG + * @see #RESULT_ERROR_FONT_UPDATER_DISABLED + * @see #RESULT_ERROR_FONT_NOT_FOUND + */ + @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @ResultCode int updateFontFamily( + @NonNull FontFamilyUpdateRequest request, @IntRange(from = 0) int baseVersion) { + List<FontUpdateRequest> requests = new ArrayList<>(); + List<FontFileUpdateRequest> fontFileUpdateRequests = request.getFontFileUpdateRequests(); + for (int i = 0; i < fontFileUpdateRequests.size(); i++) { + FontFileUpdateRequest fontFile = fontFileUpdateRequests.get(i); + requests.add(new FontUpdateRequest(fontFile.getParcelFileDescriptor(), + fontFile.getSignature())); + } + List<FontFamilyUpdateRequest.FontFamily> fontFamilies = request.getFontFamilies(); + for (int i = 0; i < fontFamilies.size(); i++) { + FontFamilyUpdateRequest.FontFamily fontFamily = fontFamilies.get(i); + requests.add(new FontUpdateRequest(fontFamily.getName(), fontFamily.getFonts())); + } + try { + return mIFontManager.updateFontFamily(requests, baseVersion); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } diff --git a/core/java/android/graphics/fonts/FontUpdateRequest.java b/core/java/android/graphics/fonts/FontUpdateRequest.java index f551d6a175da..b79c8f62d492 100644 --- a/core/java/android/graphics/fonts/FontUpdateRequest.java +++ b/core/java/android/graphics/fonts/FontUpdateRequest.java @@ -19,13 +19,17 @@ package android.graphics.fonts; import android.annotation.IntDef; 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 java.io.File; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; /** * Represents a font update request. Currently only font install request is supported. @@ -80,6 +84,26 @@ public final class FontUpdateRequest implements Parcelable { mFontFamily = fontFamily; } + public FontUpdateRequest(@NonNull String postScriptName, + @NonNull List<FontFamilyUpdateRequest.Font> variations) { + // TODO: Serialize the request directly instead of reusing FontConfig.FontFamily. + this(createFontFamily(postScriptName, variations)); + } + + private static FontConfig.FontFamily createFontFamily(@NonNull String postScriptName, + @NonNull List<FontFamilyUpdateRequest.Font> fonts) { + List<FontConfig.Font> configFonts = 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); + } + protected FontUpdateRequest(Parcel in) { mType = in.readInt(); mFd = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); diff --git a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl index dfcc91421b9e..1c7eca8b6c8e 100644 --- a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl +++ b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl @@ -20,6 +20,8 @@ import android.os.ParcelFileDescriptor; import android.graphics.fonts.FontUpdateRequest; import android.text.FontConfig; +import java.util.List; + /** * System private interface for talking with * {@link com.android.server.graphics.fonts.FontManagerService}. @@ -28,5 +30,7 @@ import android.text.FontConfig; interface IFontManager { FontConfig getFontConfig(); - int updateFont(int baseVersion, in FontUpdateRequest request); + int updateFontFile(in FontUpdateRequest request, int baseVersion); + + int updateFontFamily(in List<FontUpdateRequest> request, int baseVersion); } diff --git a/graphics/java/android/graphics/fonts/FontVariationAxis.java b/graphics/java/android/graphics/fonts/FontVariationAxis.java index 7bd581723d18..d1fe2cdbcd77 100644 --- a/graphics/java/android/graphics/fonts/FontVariationAxis.java +++ b/graphics/java/android/graphics/fonts/FontVariationAxis.java @@ -23,6 +23,7 @@ import android.os.Build; import android.text.TextUtils; import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.regex.Pattern; @@ -189,6 +190,17 @@ public final class FontVariationAxis { return TextUtils.join(",", axes); } + /** + * Stringify the array of FontVariationAxis. + * @hide + */ + public static @NonNull String toFontVariationSettings(@Nullable List<FontVariationAxis> axes) { + if (axes == null) { + return ""; + } + return TextUtils.join(",", axes); + } + @Override public boolean equals(@Nullable Object o) { if (o == this) { 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 1b27572ad8de..09c0937802a5 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -72,11 +72,11 @@ public final class FontManagerService extends IFontManager.Stub { } @Override - public int updateFont(int baseVersion, @NonNull FontUpdateRequest request) { + public int updateFontFile(@NonNull FontUpdateRequest request, int baseVersion) { + Preconditions.checkArgumentNonnegative(baseVersion); Objects.requireNonNull(request); Objects.requireNonNull(request.getFd()); Objects.requireNonNull(request.getSignature()); - Preconditions.checkArgumentNonnegative(baseVersion); getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS, "UPDATE_FONTS permission required."); try { @@ -88,6 +88,21 @@ public final class FontManagerService extends IFontManager.Stub { } } + @Override + public int updateFontFamily(@NonNull List<FontUpdateRequest> requests, int baseVersion) { + Preconditions.checkArgumentNonnegative(baseVersion); + Objects.requireNonNull(requests); + getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS, + "UPDATE_FONTS permission required."); + try { + update(baseVersion, requests); + return FontManager.RESULT_SUCCESS; + } catch (SystemFontException e) { + Slog.e(TAG, "Failed to update font family", e); + return e.getErrorCode(); + } + } + /* package */ static class SystemFontException extends AndroidException { private final int mErrorCode; diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java index 45f2a38b6773..08ddc6ddf4ae 100644 --- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java @@ -45,6 +45,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; /** * Manages set of updatable font files. @@ -182,8 +183,12 @@ final class UpdatableFontDir { 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); + try { + addFontFamily(fontFamily); + } catch (SystemFontException e) { + // Ignore failures as updated fonts may be obsoleted by system OTA update. + Slog.i(TAG, "Obsolete font family: " + fontFamily.getName()); + } } success = true; } catch (Throwable t) { @@ -236,10 +241,7 @@ final class UpdatableFontDir { 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"); - } + addFontFamily(request.getFontFamily()); break; } } @@ -495,18 +497,15 @@ final class UpdatableFontDir { * 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; - } + private void addFontFamily(FontConfig.FontFamily fontFamily) throws SystemFontException { + Objects.requireNonNull(fontFamily.getName()); FontConfig.FontFamily resolvedFontFamily = resolveFontFiles(fontFamily); if (resolvedFontFamily == null) { - Slog.e(TAG, "Required fonts are not available"); - return false; + throw new SystemFontException( + FontManager.RESULT_ERROR_FONT_NOT_FOUND, + "Required fonts are not available"); } mFontFamilyMap.put(resolvedFontFamily.getName(), resolvedFontFamily); - return true; } @Nullable diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java index 4bbf96fcb7ef..7771afc8c7f1 100644 --- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java @@ -684,8 +684,8 @@ public final class UpdatableFontDirTest { newAddFontFamilyRequest("<family lang='en'>" + " <font>test.ttf</font>" + "</family>"))); - fail("Expect IllegalArgumentException"); - } catch (IllegalArgumentException e) { + fail("Expect NullPointerException"); + } catch (NullPointerException e) { // Expect } } @@ -703,9 +703,10 @@ public final class UpdatableFontDirTest { dir.update(Arrays.asList(newAddFontFamilyRequest("<family name='test'>" + " <font>test.ttf</font>" + "</family>"))); - fail("Expect IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // Expect + fail("Expect SystemFontException"); + } catch (FontManagerService.SystemFontException e) { + assertThat(e.getErrorCode()) + .isEqualTo(FontManager.RESULT_ERROR_FONT_NOT_FOUND); } } |