blob: 24480e954a6453fc31889b249d24d207d4d3b83c [file] [log] [blame]
/*
* 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.Manifest;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
import android.text.FontConfig;
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;
/**
* This class gives you control of system installed font files.
*
* <p>
* This class gives you the information of system font configuration and ability of changing them.
*
* @hide
*/
@SystemApi
@TestApi
@SystemService(Context.FONT_SERVICE)
public class FontManager {
private static final String TAG = "FontManager";
private final @NonNull IFontManager mIFontManager;
/** @hide */
@IntDef(prefix = "RESULT_",
value = { RESULT_SUCCESS, RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE,
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_FONT_NOT_FOUND })
@Retention(RetentionPolicy.SOURCE)
public @interface ResultCode {}
/**
* Indicates that the request has been processed successfully.
*/
public static final int RESULT_SUCCESS = 0;
/**
* Indicates that a failure occurred while writing the font file to disk.
*
* This is an internal error that the system cannot place the font file for being used by
* application.
*/
public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1;
/**
* Indicates that a failure occurred during the verification of the font file.
*
* The system failed to verify given font file contents and signature with system installed
* certificate.
*/
public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2;
/**
* Indicates that a failure occurred as a result of invalid font format or content.
*
* Android only accepts OpenType compliant font files.
*/
public static final int RESULT_ERROR_INVALID_FONT_FILE = -3;
/**
* Indicates a failure due to missing PostScript name in font's name table.
*
* Indicates that a failure occurred since PostScript name in the name table(ID=6) was missing.
* The font is expected to have a PostScript name.
*/
public static final int RESULT_ERROR_INVALID_FONT_NAME = -4;
/**
* Indicates that a failure occurred due to downgrading the font version.
*
* The font must have equal or newer revision in its head table.
*/
public static final int RESULT_ERROR_DOWNGRADING = -5;
/**
* Indicates that a failure occurred while updating system font configuration.
*
* This is an internal error that the system couldn't update the {@link FontConfig}.
*/
public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6;
/**
* Indicates a failure due to disabled font updater.
*
* This is typically returned due to missing Linux kernel feature.
* The font updater only works with the Linux kernel that has fs-verity feature. The fs-verity
* is required after the device shipped with Android 11. Thus the updated device may not have
* fs-verity feature and font updater is disabled.
*/
public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7;
/**
* Indicates that a failure occurred because provided {@code baseVersion} did not match.
*
* The {@code baseVersion} provided does not match to the current {@link FontConfig} version.
* Please get the latest configuration and update {@code baseVersion} accordingly.
*/
public static final int RESULT_ERROR_VERSION_MISMATCH = -8;
/**
* Indicates a failure occurred because a font with the specified PostScript name could not be
* found.
*/
public static final int RESULT_ERROR_FONT_NOT_FOUND = -9;
/**
* Indicates a failure of opening font file.
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_FAILED_TO_OPEN_FONT_FILE = -10001;
/**
* Indicates a failure of opening signature file.
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_FAILED_TO_OPEN_SIGNATURE_FILE = -10002;
/**
* Indicates a failure of invalid shell command arguments.
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_INVALID_SHELL_ARGUMENT = -10003;
/**
* Indicates a failure of reading signature file.
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_INVALID_SIGNATURE_FILE = -10004;
/**
* Indicates a failure due to exceeding allowed signature file size (8kb).
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_SIGNATURE_TOO_LARGE = -10005;
/**
* Indicates a failure of opening XML file.
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_FAILED_TO_OPEN_XML_FILE = -10006;
/**
* Indicates a failure due to invalid XML file.
*
* This error code is only used with the shell command interaction.
*
* @hide
*/
public static final int RESULT_ERROR_INVALID_XML = -10007;
private FontManager(@NonNull IFontManager iFontManager) {
mIFontManager = iFontManager;
}
/**
* Returns the system font configuration.
*
* This information is expected to be used by system font updater. If you are looking for APIs
* about drawing text and/or high-level system font information, use
* {@link android.graphics.Typeface} or {@link SystemFonts} instead.
*
* @return The current font configuration. null if failed to fetch information from the system
* service.
*/
@RequiresPermission(Manifest.permission.UPDATE_FONTS)
public @NonNull FontConfig getFontConfig() {
try {
return mIFontManager.getFontConfig();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
* Update or add system 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.
*
* To protect devices, system font updater relies on a Linux Kernel feature called fs-verity.
* If the device does not support fs-verity, {@link #RESULT_ERROR_FONT_UPDATER_DISABLED} will be
* returned.
*
* <p>Android only accepts OpenType compliant font files. If other font files are provided,
* {@link #RESULT_ERROR_INVALID_FONT_FILE} will be returned.
*
* <p>The font file to be updated is identified by PostScript name stored in the name table. If
* the font file doesn't have PostScript name entry, {@link #RESULT_ERROR_INVALID_FONT_NAME}
* will be returned.
*
* <p>The entire font file is verified with the given signature using system installed
* certificates. If the system cannot verify the font file contents,
* {@link #RESULT_ERROR_VERIFICATION_FAILURE} will be returned.
*
* <p>The font file must have a newer revision number in the head table. In other words, it is
* not allowed to downgrade a font file. If an older font file is provided,
* {@link #RESULT_ERROR_DOWNGRADING} will be returned.
*
* <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();
}
}
/**
* Factory method of the FontManager.
*
* Do not use this method directly. Use getSystemService(Context.FONT_SERVICE) instead.
*
* @return A new instance of FontManager
* @hide
*/
public static FontManager create(@NonNull IFontManager iFontManager) {
Objects.requireNonNull(iFontManager);
return new FontManager(iFontManager);
}
}