Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2008e8a authored by Kohsuke Yatoh's avatar Kohsuke Yatoh
Browse files

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
parent dc7eaa0b
Loading
Loading
Loading
Loading
+33 −1
Original line number Diff line number Diff line
@@ -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
+2 −1
Original line number Diff line number Diff line
@@ -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
+264 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
+65 −0
Original line number Diff line number Diff line
/*
 * 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;
    }
}
+68 −7
Original line number Diff line number Diff line
@@ -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();
        }
    }

Loading