1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.graphics.fonts; 18 19 import android.Manifest; 20 import android.annotation.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SystemApi; 25 import android.annotation.SystemService; 26 import android.annotation.TestApi; 27 import android.content.Context; 28 import android.os.RemoteException; 29 import android.text.FontConfig; 30 31 import com.android.internal.graphics.fonts.IFontManager; 32 33 import java.lang.annotation.Retention; 34 import java.lang.annotation.RetentionPolicy; 35 import java.util.ArrayList; 36 import java.util.List; 37 import java.util.Objects; 38 39 /** 40 * This class gives you control of system installed font files. 41 * 42 * <p> 43 * This class gives you the information of system font configuration and ability of changing them. 44 * 45 * @hide 46 */ 47 @SystemApi 48 @TestApi 49 @SystemService(Context.FONT_SERVICE) 50 public class FontManager { 51 private static final String TAG = "FontManager"; 52 private final @NonNull IFontManager mIFontManager; 53 54 /** @hide */ 55 @IntDef(prefix = "RESULT_", 56 value = { RESULT_SUCCESS, RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, 57 RESULT_ERROR_VERIFICATION_FAILURE, RESULT_ERROR_VERSION_MISMATCH, 58 RESULT_ERROR_INVALID_FONT_FILE, RESULT_ERROR_INVALID_FONT_NAME, 59 RESULT_ERROR_DOWNGRADING, RESULT_ERROR_FAILED_UPDATE_CONFIG, 60 RESULT_ERROR_FONT_UPDATER_DISABLED, RESULT_ERROR_FONT_NOT_FOUND }) 61 @Retention(RetentionPolicy.SOURCE) 62 public @interface ResultCode {} 63 64 /** 65 * Indicates that the request has been processed successfully. 66 */ 67 public static final int RESULT_SUCCESS = 0; 68 69 /** 70 * Indicates that a failure occurred while writing the font file to disk. 71 * 72 * This is an internal error that the system cannot place the font file for being used by 73 * application. 74 */ 75 public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; 76 77 /** 78 * Indicates that a failure occurred during the verification of the font file. 79 * 80 * The system failed to verify given font file contents and signature with system installed 81 * certificate. 82 */ 83 public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2; 84 85 /** 86 * Indicates that a failure occurred as a result of invalid font format or content. 87 * 88 * Android only accepts OpenType compliant font files. 89 */ 90 public static final int RESULT_ERROR_INVALID_FONT_FILE = -3; 91 92 /** 93 * Indicates a failure due to missing PostScript name in font's name table. 94 * 95 * Indicates that a failure occurred since PostScript name in the name table(ID=6) was missing. 96 * The font is expected to have a PostScript name. 97 */ 98 public static final int RESULT_ERROR_INVALID_FONT_NAME = -4; 99 100 /** 101 * Indicates that a failure occurred due to downgrading the font version. 102 * 103 * The font must have equal or newer revision in its head table. 104 */ 105 public static final int RESULT_ERROR_DOWNGRADING = -5; 106 107 /** 108 * Indicates that a failure occurred while updating system font configuration. 109 * 110 * This is an internal error that the system couldn't update the {@link FontConfig}. 111 */ 112 public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; 113 114 /** 115 * Indicates a failure due to disabled font updater. 116 * 117 * This is typically returned due to missing Linux kernel feature. 118 * The font updater only works with the Linux kernel that has fs-verity feature. The fs-verity 119 * is required after the device shipped with Android 11. Thus the updated device may not have 120 * fs-verity feature and font updater is disabled. 121 */ 122 public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7; 123 124 /** 125 * Indicates that a failure occurred because provided {@code baseVersion} did not match. 126 * 127 * The {@code baseVersion} provided does not match to the current {@link FontConfig} version. 128 * Please get the latest configuration and update {@code baseVersion} accordingly. 129 */ 130 public static final int RESULT_ERROR_VERSION_MISMATCH = -8; 131 132 /** 133 * Indicates a failure occurred because a font with the specified PostScript name could not be 134 * found. 135 */ 136 public static final int RESULT_ERROR_FONT_NOT_FOUND = -9; 137 138 /** 139 * Indicates a failure of opening font file. 140 * 141 * This error code is only used with the shell command interaction. 142 * 143 * @hide 144 */ 145 public static final int RESULT_ERROR_FAILED_TO_OPEN_FONT_FILE = -10001; 146 147 /** 148 * Indicates a failure of opening signature file. 149 * 150 * This error code is only used with the shell command interaction. 151 * 152 * @hide 153 */ 154 public static final int RESULT_ERROR_FAILED_TO_OPEN_SIGNATURE_FILE = -10002; 155 156 /** 157 * Indicates a failure of invalid shell command arguments. 158 * 159 * This error code is only used with the shell command interaction. 160 * 161 * @hide 162 */ 163 public static final int RESULT_ERROR_INVALID_SHELL_ARGUMENT = -10003; 164 165 /** 166 * Indicates a failure of reading signature file. 167 * 168 * This error code is only used with the shell command interaction. 169 * 170 * @hide 171 */ 172 public static final int RESULT_ERROR_INVALID_SIGNATURE_FILE = -10004; 173 174 /** 175 * Indicates a failure due to exceeding allowed signature file size (8kb). 176 * 177 * This error code is only used with the shell command interaction. 178 * 179 * @hide 180 */ 181 public static final int RESULT_ERROR_SIGNATURE_TOO_LARGE = -10005; 182 183 /** 184 * Indicates a failure of opening XML file. 185 * 186 * This error code is only used with the shell command interaction. 187 * 188 * @hide 189 */ 190 public static final int RESULT_ERROR_FAILED_TO_OPEN_XML_FILE = -10006; 191 192 /** 193 * Indicates a failure due to invalid XML file. 194 * 195 * This error code is only used with the shell command interaction. 196 * 197 * @hide 198 */ 199 public static final int RESULT_ERROR_INVALID_XML = -10007; 200 FontManager(@onNull IFontManager iFontManager)201 private FontManager(@NonNull IFontManager iFontManager) { 202 mIFontManager = iFontManager; 203 } 204 205 /** 206 * Returns the system font configuration. 207 * 208 * This information is expected to be used by system font updater. If you are looking for APIs 209 * about drawing text and/or high-level system font information, use 210 * {@link android.graphics.Typeface} or {@link SystemFonts} instead. 211 * 212 * @return The current font configuration. null if failed to fetch information from the system 213 * service. 214 */ 215 @RequiresPermission(Manifest.permission.UPDATE_FONTS) getFontConfig()216 public @NonNull FontConfig getFontConfig() { 217 try { 218 return mIFontManager.getFontConfig(); 219 } catch (RemoteException e) { 220 throw e.rethrowAsRuntimeException(); 221 } 222 } 223 224 /** 225 * Update or add system font families. 226 * 227 * <p>This method will update existing font families or add new font families. The updated 228 * font family definitions will be used when creating {@link android.graphics.Typeface} objects 229 * with using {@link android.graphics.Typeface#create(String, int)} specifying the family name, 230 * or through XML resources. 231 * 232 * To protect devices, system font updater relies on a Linux Kernel feature called fs-verity. 233 * If the device does not support fs-verity, {@link #RESULT_ERROR_FONT_UPDATER_DISABLED} will be 234 * returned. 235 * 236 * <p>Android only accepts OpenType compliant font files. If other font files are provided, 237 * {@link #RESULT_ERROR_INVALID_FONT_FILE} will be returned. 238 * 239 * <p>The font file to be updated is identified by PostScript name stored in the name table. If 240 * the font file doesn't have PostScript name entry, {@link #RESULT_ERROR_INVALID_FONT_NAME} 241 * will be returned. 242 * 243 * <p>The entire font file is verified with the given signature using system installed 244 * certificates. If the system cannot verify the font file contents, 245 * {@link #RESULT_ERROR_VERIFICATION_FAILURE} will be returned. 246 * 247 * <p>The font file must have a newer revision number in the head table. In other words, it is 248 * not allowed to downgrade a font file. If an older font file is provided, 249 * {@link #RESULT_ERROR_DOWNGRADING} will be returned. 250 * 251 * <p>The caller must specify the base config version for keeping the font configuration 252 * consistent. If the font configuration is updated for some reason between the time you get 253 * a configuration with {@link #getFontConfig()} and the time when you call this method, 254 * {@link #RESULT_ERROR_VERSION_MISMATCH} will be returned. Get the latest font configuration by 255 * calling {@link #getFontConfig()} and call this method again with the latest config version. 256 * 257 * @param request A {@link FontFamilyUpdateRequest} to execute. 258 * @param baseVersion A base config version to be updated. You can get the latest config version 259 * by {@link FontConfig#getConfigVersion()} via {@link #getFontConfig()}. If 260 * the system has a newer config version, the update will fail with 261 * {@link #RESULT_ERROR_VERSION_MISMATCH}. 262 * @return A result code. 263 * @see FontConfig#getConfigVersion() 264 * @see #getFontConfig() 265 * @see #RESULT_SUCCESS 266 * @see #RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE 267 * @see #RESULT_ERROR_VERIFICATION_FAILURE 268 * @see #RESULT_ERROR_VERSION_MISMATCH 269 * @see #RESULT_ERROR_INVALID_FONT_FILE 270 * @see #RESULT_ERROR_INVALID_FONT_NAME 271 * @see #RESULT_ERROR_DOWNGRADING 272 * @see #RESULT_ERROR_FAILED_UPDATE_CONFIG 273 * @see #RESULT_ERROR_FONT_UPDATER_DISABLED 274 * @see #RESULT_ERROR_FONT_NOT_FOUND 275 */ updateFontFamily( @onNull FontFamilyUpdateRequest request, @IntRange(from = 0) int baseVersion)276 @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @ResultCode int updateFontFamily( 277 @NonNull FontFamilyUpdateRequest request, @IntRange(from = 0) int baseVersion) { 278 List<FontUpdateRequest> requests = new ArrayList<>(); 279 List<FontFileUpdateRequest> fontFileUpdateRequests = request.getFontFileUpdateRequests(); 280 for (int i = 0; i < fontFileUpdateRequests.size(); i++) { 281 FontFileUpdateRequest fontFile = fontFileUpdateRequests.get(i); 282 requests.add(new FontUpdateRequest(fontFile.getParcelFileDescriptor(), 283 fontFile.getSignature())); 284 } 285 List<FontFamilyUpdateRequest.FontFamily> fontFamilies = request.getFontFamilies(); 286 for (int i = 0; i < fontFamilies.size(); i++) { 287 FontFamilyUpdateRequest.FontFamily fontFamily = fontFamilies.get(i); 288 requests.add(new FontUpdateRequest(fontFamily.getName(), fontFamily.getFonts())); 289 } 290 try { 291 return mIFontManager.updateFontFamily(requests, baseVersion); 292 } catch (RemoteException e) { 293 throw e.rethrowFromSystemServer(); 294 } 295 } 296 297 /** 298 * Factory method of the FontManager. 299 * 300 * Do not use this method directly. Use getSystemService(Context.FONT_SERVICE) instead. 301 * 302 * @return A new instance of FontManager 303 * @hide 304 */ create(@onNull IFontManager iFontManager)305 public static FontManager create(@NonNull IFontManager iFontManager) { 306 Objects.requireNonNull(iFontManager); 307 return new FontManager(iFontManager); 308 } 309 } 310