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