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.annotation.IntRange;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 
23 import com.android.internal.util.Preconditions;
24 
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.Objects;
29 
30 /**
31  * Request for updating or adding a font family on the system.
32  *
33  * <p>You can update or add a font family with custom style parameters. The following example
34  * defines a font family called "roboto" using "Roboto-Regular" font file that is already available
35  * on the system by preloading or {@link FontManager#updateFontFile}.
36  * <pre>
37  * FontManager fm = getContext().getSystemService(FontManager.class);
38  * fm.updateFontFamily(new FontFamilyUpdateRequest.Builder()
39  *     .addFontFamily(new FontFamilyUpdateRequest.FontFamily("roboto", Arrays.asList(
40  *         new FontFamilyUpdateRequest.Font(
41  *             "Roboto-Regular",
42  *             new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
43  *             Collections.emptyList()),
44  *         new FontFamilyUpdateRequest.Font(
45  *             "Roboto-Regular",
46  *             new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_ITALIC),
47  *             Collections.emptyList()))))
48  *     .build(), fm.getFontConfig().getConfigVersion());
49  * </pre>
50  *
51  * <p>You can update or add font files in the same request by calling
52  * {@link FontFamilyUpdateRequest.Builder#addFontFileUpdateRequest(FontFileUpdateRequest)}.
53  * The following example adds "YourFont" font file and defines "your-font" font family in the same
54  * request. In this case, the font file represented by {@code yourFontFd} should be an OpenType
55  * compliant font file and have "YourFont" as PostScript name (ID=6) in 'name' table.
56  * <pre>
57  * FontManager fm = getContext().getSystemService(FontManager.class);
58  * fm.updateFontFamily(new FontFamilyUpdateRequest.Builder()
59  *     .addFontFileUpdateRequest(new FontFileUpdateRequest(yourFontFd, signature))
60  *     .addFontFamily(new FontFamilyUpdateRequest.FontFamily("your-font", Arrays.asList(
61  *         new FontFamilyUpdateRequest.Font(
62  *             "YourFont",
63  *             new FontStyle(FONT_WEIGHT_NORMAL, FONT_SLANT_UPRIGHT),
64  *             Collections.emptyList()))))
65  *     .build(), fm.getFontConfig().getConfigVersion());
66  * </pre>
67  *
68  * @hide
69  */
70 @SystemApi
71 public final class FontFamilyUpdateRequest {
72 
73     /**
74      * A font family definition.
75      */
76     public static final class FontFamily {
77 
78         /**
79          * Builds a {@link FontFamily}.
80          */
81         public static final class Builder {
82             @NonNull private final String mName;
83             @NonNull private final List<Font> mFonts;
84 
85             /**
86              * Constructs a {@link FontFamily.Builder}.
87              */
Builder(@onNull String name, @NonNull List<Font> fonts)88             public Builder(@NonNull String name, @NonNull List<Font> fonts) {
89                 Objects.requireNonNull(name);
90                 Preconditions.checkStringNotEmpty(name);
91                 Objects.requireNonNull(fonts);
92                 Preconditions.checkCollectionElementsNotNull(fonts, "fonts");
93                 Preconditions.checkCollectionNotEmpty(fonts, "fonts");
94                 mName = name;
95                 mFonts = new ArrayList<>(fonts);
96             }
97 
98             /**
99              * Adds a {@link Font} to the builder.
100              *
101              * @return This builder object.
102              */
addFont(@onNull Font font)103             public @NonNull Builder addFont(@NonNull Font font) {
104                 mFonts.add(font);
105                 return this;
106             }
107 
108             /**
109              * Builds a {@link FontFamily}.
110              */
build()111             public @NonNull FontFamily build() {
112                 return new FontFamily(mName, mFonts);
113             }
114         }
115 
116         @NonNull
117         private final String mName;
118         @NonNull
119         private final List<Font> mFonts;
120 
121         /**
122          * Constructs a FontFamily.
123          *
124          * <p>A font family has a name to identify the font family. Apps can use
125          * {@link android.graphics.Typeface#create(String, int)} or XML resources to use a specific
126          * font family.
127          *
128          * <p>A font family consists of multiple fonts with different styles. The style information
129          * can be specified by {@link Font}.
130          *
131          * @see android.graphics.Typeface#create(String, int)
132          * @see Font
133          */
FontFamily(@onNull String name, @NonNull List<Font> fonts)134         private FontFamily(@NonNull String name, @NonNull List<Font> fonts) {
135             mName = name;
136             mFonts = fonts;
137         }
138 
139         /**
140          * Returns the name of this family.
141          */
142         @NonNull
getName()143         public String getName() {
144             return mName;
145         }
146 
147         /**
148          * Returns the fonts in this family.
149          */
150         @NonNull
getFonts()151         public List<Font> getFonts() {
152             return mFonts;
153         }
154     }
155 
156     /**
157      * A single entry in a font family representing a font.
158      */
159     public static final class Font {
160 
161         /**
162          * Builds a {@link Font}.
163          */
164         public static final class Builder {
165             private final@NonNull  String mPostScriptName;
166             private final @NonNull FontStyle mStyle;
167             private @NonNull List<FontVariationAxis> mAxes = Collections.emptyList();
168             private @IntRange(from = 0) int mIndex = 0;
169 
170             /**
171              * Construct a {@link Font.Builder}
172              *
173              * @param postScriptName The PostScript name of the font file to use. PostScript name is
174              *                       in Name ID 6 field in 'name' table, as specified by OpenType
175              *                       specification.
176              * @param style          The style for this font.
177              */
Builder(@onNull String postScriptName, @NonNull FontStyle style)178             public Builder(@NonNull String postScriptName, @NonNull FontStyle style) {
179                 Objects.requireNonNull(postScriptName);
180                 Preconditions.checkStringNotEmpty(postScriptName);
181                 Objects.requireNonNull(style);
182                 mPostScriptName = postScriptName;
183                 mStyle = style;
184             }
185 
186             /**
187              * A list of {@link FontVariationAxis} to specify axis tags and values for variable
188              * fonts.
189              */
setAxes(@onNull List<FontVariationAxis> axes)190             public @NonNull Builder setAxes(@NonNull List<FontVariationAxis> axes) {
191                 Objects.requireNonNull(axes);
192                 Preconditions.checkCollectionElementsNotNull(axes, "axes");
193                 mAxes = axes;
194                 return this;
195             }
196 
197             /**
198              * Sets font collection index for the Font.
199              *
200              * @see {@link android.R.attr#ttcIndex}.
201              */
setIndex(@ntRangefrom = 0) int index)202             public @NonNull Builder setIndex(@IntRange(from = 0) int index) {
203                 Preconditions.checkArgumentNonnegative(index);
204                 mIndex = index;
205                 return this;
206             }
207 
208             /**
209              * Build a {@link Font} instance.
210              */
build()211             public @NonNull Font build() {
212                 return new Font(mPostScriptName, mStyle, mIndex, mAxes);
213             }
214         }
215 
216         @NonNull
217         private final String mPostScriptName;
218         @NonNull
219         private final FontStyle mStyle;
220         @NonNull
221         private final List<FontVariationAxis> mAxes;
222 
223         private final @IntRange(from = 0) int mIndex;
224 
225         /**
226          * Constructs a FontStyleVariation.
227          *
228          * <p>A font has a PostScript name to identify the font file to use, a {@link FontStyle}
229          * to specify the style, and a list of {@link FontVariationAxis} to specify axis tags and
230          * values for variable fonts. If the font file identified by {@code postScriptName} is not a
231          * variable font, {@code axes} must be empty.
232          *
233          * @param postScriptName The PostScript name of the font file to use. PostScript name is in
234          *                       Name ID 6 field in 'name' table, as specified by OpenType
235          *                       specification.
236          * @param style          The style for this font.
237          * @param index          The index of the font in the collection.
238          * @param axes           A list of {@link FontVariationAxis} to specify axis tags and values
239          *                       for variable fonts.
240          */
Font(@onNull String postScriptName, @NonNull FontStyle style, @IntRange(from = 0) int index, @NonNull List<FontVariationAxis> axes)241         private Font(@NonNull String postScriptName, @NonNull FontStyle style,
242                 @IntRange(from = 0) int index, @NonNull List<FontVariationAxis> axes) {
243             mPostScriptName = postScriptName;
244             mStyle = style;
245             mIndex = index;
246             mAxes = axes;
247         }
248 
249         /**
250          * Returns PostScript name of the font file to use.
251          */
252         @NonNull
getPostScriptName()253         public String getPostScriptName() {
254             return mPostScriptName;
255         }
256 
257         /**
258          * Returns the style.
259          */
260         @NonNull
getStyle()261         public FontStyle getStyle() {
262             return mStyle;
263         }
264 
265 
266         /**
267          * Returns the list of {@link FontVariationAxis}.
268          */
269         @NonNull
getAxes()270         public List<FontVariationAxis> getAxes() {
271             return mAxes;
272         }
273 
274         /**
275          * Returns the index of collection
276          */
getIndex()277         public @IntRange(from = 0) int getIndex() {
278             return mIndex;
279         }
280     }
281 
282     /**
283      * Builds a {@link FontFamilyUpdateRequest}.
284      */
285     public static final class Builder {
286         @NonNull
287         private final List<FontFileUpdateRequest> mFontFileUpdateRequests = new ArrayList<>();
288         @NonNull
289         private final List<FontFamily> mFontFamilies = new ArrayList<>();
290 
291         /**
292          * Constructs a FontFamilyUpdateRequest.Builder.
293          */
Builder()294         public Builder() {
295         }
296 
297         /**
298          * Adds a {@link FontFileUpdateRequest} to execute as a part of the constructed
299          * {@link FontFamilyUpdateRequest}.
300          *
301          * @param request A font file update request.
302          * @return This builder object.
303          */
304         @NonNull
addFontFileUpdateRequest(@onNull FontFileUpdateRequest request)305         public Builder addFontFileUpdateRequest(@NonNull FontFileUpdateRequest request) {
306             Objects.requireNonNull(request);
307             mFontFileUpdateRequests.add(request);
308             return this;
309         }
310 
311         /**
312          * Adds a font family to update an existing font family in the system font config or
313          * add as a new font family to the system font config.
314          *
315          * @param fontFamily An font family definition to add or update.
316          * @return This builder object.
317          */
318         @NonNull
addFontFamily(@onNull FontFamily fontFamily)319         public Builder addFontFamily(@NonNull FontFamily fontFamily) {
320             Objects.requireNonNull(fontFamily);
321             mFontFamilies.add(fontFamily);
322             return this;
323         }
324 
325         /**
326          * Builds a {@link FontFamilyUpdateRequest}.
327          */
328         @NonNull
build()329         public FontFamilyUpdateRequest build() {
330             return new FontFamilyUpdateRequest(mFontFileUpdateRequests, mFontFamilies);
331         }
332     }
333 
334     @NonNull
335     private final List<FontFileUpdateRequest> mFontFiles;
336 
337     @NonNull
338     private final List<FontFamily> mFontFamilies;
339 
FontFamilyUpdateRequest(@onNull List<FontFileUpdateRequest> fontFiles, @NonNull List<FontFamily> fontFamilies)340     private FontFamilyUpdateRequest(@NonNull List<FontFileUpdateRequest> fontFiles,
341             @NonNull List<FontFamily> fontFamilies) {
342         mFontFiles = fontFiles;
343         mFontFamilies = fontFamilies;
344     }
345 
346     /**
347      * Returns the list of {@link FontFileUpdateRequest} that will be executed as a part of this
348      * request.
349      */
350     @NonNull
getFontFileUpdateRequests()351     public List<FontFileUpdateRequest> getFontFileUpdateRequests() {
352         return mFontFiles;
353     }
354 
355     /**
356      * Returns the list of {@link FontFamily} that will be updated in this request.
357      */
358     @NonNull
getFontFamilies()359     public List<FontFamily> getFontFamilies() {
360         return mFontFamilies;
361     }
362 }
363