Add FontManager#updateFontFamily() API.

Bug: 179103383
Test: atest CtsGraphicsTestCases:FontFamilyUpdateRequestTest
Test: atest CtsGraphicsTestCases:FontFileUpdateRequestTest
Test: atest CtsGraphicsTestCases:FontManagerTest
Test: atest FrameworksServicesTests:UpdatableFontDirTest
Test: atest UpdatableSystemFontTest
Change-Id: I0103784c72d60567675daf73e95e4d716f091e4a
This commit is contained in:
Kohsuke Yatoh
2021-02-10 17:05:05 -08:00
parent dc7eaa0bd8
commit c2008e8aac
11 changed files with 509 additions and 31 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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());

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
}