• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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