1 /* 2 * Copyright (C) 2017 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.text; 18 19 import static java.lang.annotation.RetentionPolicy.SOURCE; 20 21 import android.annotation.CurrentTimeMillisLong; 22 import android.annotation.IntDef; 23 import android.annotation.IntRange; 24 import android.annotation.NonNull; 25 import android.annotation.Nullable; 26 import android.annotation.SystemApi; 27 import android.annotation.TestApi; 28 import android.compat.annotation.UnsupportedAppUsage; 29 import android.graphics.fonts.FontStyle; 30 import android.graphics.fonts.FontVariationAxis; 31 import android.os.Build; 32 import android.os.LocaleList; 33 import android.os.Parcel; 34 import android.os.Parcelable; 35 36 import java.io.File; 37 import java.lang.annotation.Retention; 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Objects; 41 42 43 /** 44 * Font configuration descriptions for System fonts. 45 * 46 * FontConfig represents the configuration for the fonts installed on the system. It is made of list 47 * of font families and aliases. 48 * 49 * @see FontFamily 50 * @see Alias 51 * @hide 52 */ 53 @SystemApi 54 @TestApi 55 public final class FontConfig implements Parcelable { 56 private final @NonNull List<FontFamily> mFamilies; 57 private final @NonNull List<Alias> mAliases; 58 private final long mLastModifiedTimeMillis; 59 private final int mConfigVersion; 60 61 /** 62 * Construct a FontConfig instance. 63 * 64 * @param families a list of font families. 65 * @param aliases a list of aliases. 66 * 67 * @hide Only system server can create this instance and passed via IPC. 68 */ FontConfig(@onNull List<FontFamily> families, @NonNull List<Alias> aliases, long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion)69 public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases, 70 long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) { 71 mFamilies = families; 72 mAliases = aliases; 73 mLastModifiedTimeMillis = lastModifiedTimeMillis; 74 mConfigVersion = configVersion; 75 } 76 77 /** 78 * Returns the ordered list of font families available in the system. 79 * 80 * @return a list of font families. 81 * @see FontFamily 82 */ getFontFamilies()83 public @NonNull List<FontFamily> getFontFamilies() { 84 return mFamilies; 85 } 86 87 /** 88 * Returns the list of aliases for mapping font families with other names. 89 * 90 * @return a list of font families. 91 * @see Alias 92 */ getAliases()93 public @NonNull List<Alias> getAliases() { 94 return mAliases; 95 } 96 97 /** 98 * Returns the last modified time in milliseconds. 99 * 100 * This is a value of {@link System#currentTimeMillis()} when the system font configuration was 101 * modified last time. 102 * 103 * If there is no update, this return 0. 104 */ getLastModifiedTimeMillis()105 public @CurrentTimeMillisLong long getLastModifiedTimeMillis() { 106 return mLastModifiedTimeMillis; 107 } 108 109 /** 110 * Returns the monotonically increasing config version value. 111 * 112 * The config version is reset to 0 when the system is restarted. 113 */ getConfigVersion()114 public @IntRange(from = 0) int getConfigVersion() { 115 return mConfigVersion; 116 } 117 118 /** 119 * Returns the ordered list of families included in the system fonts. 120 * @deprecated Use getFontFamilies instead. 121 * @hide 122 */ 123 @Deprecated 124 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getFamilies()125 public @NonNull FontFamily[] getFamilies() { 126 return mFamilies.toArray(new FontFamily[0]); 127 } 128 129 @Override describeContents()130 public int describeContents() { 131 return 0; 132 } 133 134 @Override writeToParcel(@onNull Parcel dest, int flags)135 public void writeToParcel(@NonNull Parcel dest, int flags) { 136 dest.writeParcelableList(mFamilies, flags); 137 dest.writeParcelableList(mAliases, flags); 138 dest.writeLong(mLastModifiedTimeMillis); 139 dest.writeInt(mConfigVersion); 140 } 141 142 public static final @NonNull Creator<FontConfig> CREATOR = new Creator<FontConfig>() { 143 @Override 144 public FontConfig createFromParcel(Parcel source) { 145 List<FontFamily> families = source.readParcelableList(new ArrayList<>(), 146 FontFamily.class.getClassLoader()); 147 List<Alias> aliases = source.readParcelableList(new ArrayList<>(), 148 Alias.class.getClassLoader()); 149 long lastModifiedDate = source.readLong(); 150 int configVersion = source.readInt(); 151 return new FontConfig(families, aliases, lastModifiedDate, configVersion); 152 } 153 154 @Override 155 public FontConfig[] newArray(int size) { 156 return new FontConfig[size]; 157 } 158 }; 159 160 @Override equals(Object o)161 public boolean equals(Object o) { 162 if (this == o) return true; 163 if (o == null || getClass() != o.getClass()) return false; 164 FontConfig that = (FontConfig) o; 165 return mLastModifiedTimeMillis == that.mLastModifiedTimeMillis 166 && mConfigVersion == that.mConfigVersion 167 && Objects.equals(mFamilies, that.mFamilies) 168 && Objects.equals(mAliases, that.mAliases); 169 } 170 171 @Override hashCode()172 public int hashCode() { 173 return Objects.hash(mFamilies, mAliases, mLastModifiedTimeMillis, mConfigVersion); 174 } 175 176 @Override toString()177 public String toString() { 178 return "FontConfig{" 179 + "mFamilies=" + mFamilies 180 + ", mAliases=" + mAliases 181 + ", mLastModifiedTimeMillis=" + mLastModifiedTimeMillis 182 + ", mConfigVersion=" + mConfigVersion 183 + '}'; 184 } 185 186 /** 187 * Represents single font entry in system font configuration. 188 * 189 * A font is the most primitive unit of drawing character shapes. A font in system configuration 190 * is always referring a single OpenType compliant regular file in the file system. 191 * 192 * @see android.graphics.fonts.Font 193 */ 194 public static final class Font implements Parcelable { 195 private final @NonNull File mFile; 196 private final @Nullable File mOriginalFile; 197 private final @NonNull String mPostScriptName; 198 private final @NonNull FontStyle mStyle; 199 private final @IntRange(from = 0) int mIndex; 200 private final @NonNull String mFontVariationSettings; 201 private final @Nullable String mFontFamilyName; 202 203 /** 204 * Construct a Font instance. 205 * 206 * @hide Only system server can create this instance and passed via IPC. 207 */ Font(@onNull File file, @Nullable File originalFile, @NonNull String postScriptName, @NonNull FontStyle style, @IntRange(from = 0) int index, @NonNull String fontVariationSettings, @Nullable String fontFamilyName)208 public Font(@NonNull File file, @Nullable File originalFile, @NonNull String postScriptName, 209 @NonNull FontStyle style, @IntRange(from = 0) int index, 210 @NonNull String fontVariationSettings, @Nullable String fontFamilyName) { 211 mFile = file; 212 mOriginalFile = originalFile; 213 mPostScriptName = postScriptName; 214 mStyle = style; 215 mIndex = index; 216 mFontVariationSettings = fontVariationSettings; 217 mFontFamilyName = fontFamilyName; 218 } 219 220 @Override describeContents()221 public int describeContents() { 222 return 0; 223 } 224 225 @Override writeToParcel(@onNull Parcel dest, int flags)226 public void writeToParcel(@NonNull Parcel dest, int flags) { 227 dest.writeString8(mFile.getAbsolutePath()); 228 dest.writeString8(mOriginalFile == null ? null : mOriginalFile.getAbsolutePath()); 229 dest.writeString8(mPostScriptName); 230 dest.writeInt(mStyle.getWeight()); 231 dest.writeInt(mStyle.getSlant()); 232 dest.writeInt(mIndex); 233 dest.writeString8(mFontVariationSettings); 234 dest.writeString8(mFontFamilyName); 235 } 236 237 public static final @NonNull Creator<Font> CREATOR = new Creator<Font>() { 238 239 @Override 240 public Font createFromParcel(Parcel source) { 241 File path = new File(source.readString8()); 242 String originalPathStr = source.readString8(); 243 File originalPath = originalPathStr == null ? null : new File(originalPathStr); 244 String postScriptName = source.readString8(); 245 int weight = source.readInt(); 246 int slant = source.readInt(); 247 int index = source.readInt(); 248 String varSettings = source.readString8(); 249 String fallback = source.readString8(); 250 251 return new Font(path, originalPath, postScriptName, new FontStyle(weight, slant), 252 index, varSettings, fallback); 253 } 254 255 @Override 256 public Font[] newArray(int size) { 257 return new Font[size]; 258 } 259 }; 260 261 /** 262 * Returns the font file. 263 */ getFile()264 public @NonNull File getFile() { 265 return mFile; 266 } 267 268 /** 269 * Returns the original font file in the system directory. 270 * 271 * If the font file is not updated, returns null. 272 * 273 * @return returns the original font file in the system if the font file is updated. Returns 274 * null if the font file is not updated. 275 * @hide 276 */ getOriginalFile()277 public @Nullable File getOriginalFile() { 278 return mOriginalFile; 279 } 280 281 /** 282 * Returns the font style. 283 */ getStyle()284 public @NonNull FontStyle getStyle() { 285 return mStyle; 286 } 287 288 289 /** 290 * Return a font variation settings. 291 */ getFontVariationSettings()292 public @NonNull String getFontVariationSettings() { 293 return mFontVariationSettings; 294 } 295 296 /** 297 * A {@link Font} can be configured to be in the {@code Fallback List} for a 298 * {@link FontFamily}. 299 * 300 * For example a serif Hebrew [Font] can be defined in the {@code Fallback List} for 301 * {@code "serif"} {@link FontFamily}. 302 * 303 * If the return value is not {@code null}, then the font will be used in the 304 * {@code Fallback List} of that {@link FontFamily}. 305 * 306 * If the return value is {@code null}, then the font will be used in {@code Fallback List} 307 * of all {@link FontFamily}s. 308 */ getFontFamilyName()309 public @Nullable String getFontFamilyName() { 310 return mFontFamilyName; 311 } 312 313 /** 314 * Returns the index to be used to access this font when accessing a TTC file. 315 */ getTtcIndex()316 public int getTtcIndex() { 317 return mIndex; 318 } 319 320 /** 321 * Returns the PostScript name of this font. 322 */ getPostScriptName()323 public @NonNull String getPostScriptName() { 324 return mPostScriptName; 325 } 326 327 /** 328 * Returns the list of axes associated to this font. 329 * @deprecated Use getFontVariationSettings 330 * @hide 331 */ 332 @Deprecated 333 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getAxes()334 public @NonNull FontVariationAxis[] getAxes() { 335 return FontVariationAxis.fromFontVariationSettings(mFontVariationSettings); 336 } 337 338 /** 339 * Returns the weight value for this font. 340 * @deprecated Use getStyle instead. 341 * @hide 342 */ 343 @Deprecated 344 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getWeight()345 public int getWeight() { 346 return getStyle().getWeight(); 347 } 348 349 /** 350 * Returns whether this font is italic. 351 * @deprecated Use getStyle instead. 352 * @hide 353 */ 354 @Deprecated 355 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isItalic()356 public boolean isItalic() { 357 return getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC; 358 } 359 360 @Override equals(Object o)361 public boolean equals(Object o) { 362 if (this == o) return true; 363 if (o == null || getClass() != o.getClass()) return false; 364 Font font = (Font) o; 365 return mIndex == font.mIndex 366 && Objects.equals(mFile, font.mFile) 367 && Objects.equals(mOriginalFile, font.mOriginalFile) 368 && Objects.equals(mStyle, font.mStyle) 369 && Objects.equals(mFontVariationSettings, font.mFontVariationSettings) 370 && Objects.equals(mFontFamilyName, font.mFontFamilyName); 371 } 372 373 @Override hashCode()374 public int hashCode() { 375 return Objects.hash(mFile, mOriginalFile, mStyle, mIndex, mFontVariationSettings, 376 mFontFamilyName); 377 } 378 379 @Override toString()380 public String toString() { 381 return "Font{" 382 + "mFile=" + mFile 383 + ", mOriginalFile=" + mOriginalFile 384 + ", mStyle=" + mStyle 385 + ", mIndex=" + mIndex 386 + ", mFontVariationSettings='" + mFontVariationSettings + '\'' 387 + ", mFontFamilyName='" + mFontFamilyName + '\'' 388 + '}'; 389 } 390 } 391 392 /** 393 * Alias provides an alternative name for an existing font family. 394 * 395 * In the system font configuration, a font family can be an alias of another font family with 396 * different font weight. For example, "sans-serif-medium" can be a medium weight of 397 * "sans-serif" font family. In this example, {@link #getName()} returns "sans-serif-medium" and 398 * {@link #getOriginal()} return "sans-serif". The font family that doesn't have name can not be 399 * an original of the alias. 400 */ 401 public static final class Alias implements Parcelable { 402 private final @NonNull String mName; 403 private final @NonNull String mOriginal; 404 private final @IntRange(from = 0, to = 1000) int mWeight; 405 406 /** 407 * Construct an alias instance. 408 * 409 * @param name alias for the font family. 410 * @param original original font family name. 411 * @param weight font weight of the original font family. 412 * @hide Only system server can create this instance and passed via IPC. 413 */ Alias(@onNull String name, @NonNull String original, @IntRange(from = 0, to = 1000) int weight)414 public Alias(@NonNull String name, @NonNull String original, 415 @IntRange(from = 0, to = 1000) int weight) { 416 mName = name; 417 mOriginal = original; 418 mWeight = weight; 419 } 420 421 /** 422 * Alias for the font family 423 */ getName()424 public @NonNull String getName() { 425 return mName; 426 } 427 428 /** 429 * The name of the original font family. 430 */ getOriginal()431 public @NonNull String getOriginal() { 432 return mOriginal; 433 } 434 435 /** 436 * A font weight of the referring font family. 437 * 438 * @return a font weight of the referring font family. 439 */ getWeight()440 public @IntRange(from = 0, to = 1000) int getWeight() { 441 return mWeight; 442 } 443 444 @Override describeContents()445 public int describeContents() { 446 return 0; 447 } 448 449 @Override writeToParcel(@onNull Parcel dest, int flags)450 public void writeToParcel(@NonNull Parcel dest, int flags) { 451 dest.writeString8(mName); 452 dest.writeString8(mOriginal); 453 dest.writeInt(mWeight); 454 } 455 456 public static final @NonNull Creator<Alias> CREATOR = new Creator<Alias>() { 457 458 @Override 459 public Alias createFromParcel(Parcel source) { 460 String alias = source.readString8(); 461 String referName = source.readString8(); 462 int weight = source.readInt(); 463 return new Alias(alias, referName, weight); 464 } 465 466 @Override 467 public Alias[] newArray(int size) { 468 return new Alias[size]; 469 } 470 }; 471 472 @Override equals(Object o)473 public boolean equals(Object o) { 474 if (this == o) return true; 475 if (o == null || getClass() != o.getClass()) return false; 476 Alias alias = (Alias) o; 477 return mWeight == alias.mWeight 478 && Objects.equals(mName, alias.mName) 479 && Objects.equals(mOriginal, alias.mOriginal); 480 } 481 482 @Override hashCode()483 public int hashCode() { 484 return Objects.hash(mName, mOriginal, mWeight); 485 } 486 487 @Override toString()488 public String toString() { 489 return "Alias{" 490 + "mName='" + mName + '\'' 491 + ", mOriginal='" + mOriginal + '\'' 492 + ", mWeight=" + mWeight 493 + '}'; 494 } 495 } 496 497 /** 498 * Represents a font family in the system font configuration. 499 * 500 * A {@link FontFamily} is a list of {@link Font}s for drawing text in various styles such as 501 * weight, slant. 502 * 503 * For example, a {@link FontFamily} can include the regular and bold styles of a {@link Font}. 504 * 505 * @see android.graphics.fonts.FontFamily 506 */ 507 public static final class FontFamily implements Parcelable { 508 private final @NonNull List<Font> mFonts; 509 private final @Nullable String mName; 510 private final @NonNull LocaleList mLocaleList; 511 private final @Variant int mVariant; 512 513 /** @hide */ 514 @Retention(SOURCE) 515 @IntDef(prefix = { "VARIANT_" }, value = { 516 VARIANT_DEFAULT, 517 VARIANT_COMPACT, 518 VARIANT_ELEGANT 519 }) 520 public @interface Variant {} 521 522 /** 523 * Value for font variant. 524 * 525 * Indicates the font has no variant attribute. 526 */ 527 public static final int VARIANT_DEFAULT = 0; 528 529 /** 530 * Value for font variant. 531 * 532 * Indicates the font is for compact variant. 533 * @see android.graphics.Paint#setElegantTextHeight 534 */ 535 public static final int VARIANT_COMPACT = 1; 536 537 /** 538 * Value for font variant. 539 * 540 * Indicates the font is for elegant variant. 541 * @see android.graphics.Paint#setElegantTextHeight 542 */ 543 public static final int VARIANT_ELEGANT = 2; 544 545 /** 546 * Construct a family instance. 547 * 548 * @hide Only system server can create this instance and passed via IPC. 549 */ FontFamily(@onNull List<Font> fonts, @Nullable String name, @NonNull LocaleList localeList, @Variant int variant)550 public FontFamily(@NonNull List<Font> fonts, @Nullable String name, 551 @NonNull LocaleList localeList, @Variant int variant) { 552 mFonts = fonts; 553 mName = name; 554 mLocaleList = localeList; 555 mVariant = variant; 556 } 557 558 /** 559 * Returns the list of {@link Font}s in this {@link FontFamily}. 560 * 561 * @return a list of font files. 562 */ getFontList()563 public @NonNull List<Font> getFontList() { 564 return mFonts; 565 } 566 567 /** 568 * Returns the name of the {@link FontFamily}. 569 * 570 * When the name of a {@link FontFamily} is not null, this name is used to create a new 571 * {@code Fallback List}, and that {@code Fallback List}. Fallback List is the 572 * main building block for a {@link android.graphics.Typeface}. 573 * 574 * For example, if the {@link FontFamily} has the name "serif", then the system will create 575 * a “serif” {@code Fallback List} and it can be used by creating a Typeface via 576 * {@code Typeface.create("serif", Typeface.NORMAL);} 577 * 578 * When the name of a {@link FontFamily} is null, it will be appended to all of the 579 * {@code Fallback List}s. 580 */ getName()581 public @Nullable String getName() { 582 return mName; 583 } 584 585 /** 586 * Returns the locale list if available. 587 * 588 * The locale list will be used for deciding which font family should be used in fallback 589 * list. 590 */ getLocaleList()591 public @NonNull LocaleList getLocaleList() { 592 return mLocaleList; 593 } 594 595 /** 596 * Returns the text height variant. 597 */ getVariant()598 public @Variant int getVariant() { 599 return mVariant; 600 } 601 602 @Override describeContents()603 public int describeContents() { 604 return 0; 605 } 606 607 @Override writeToParcel(@onNull Parcel dest, int flags)608 public void writeToParcel(@NonNull Parcel dest, int flags) { 609 dest.writeParcelableList(mFonts, flags); 610 dest.writeString8(mName); 611 dest.writeString8(mLocaleList.toLanguageTags()); 612 dest.writeInt(mVariant); 613 } 614 615 public static final @NonNull Creator<FontFamily> CREATOR = new Creator<FontFamily>() { 616 617 @Override 618 public FontFamily createFromParcel(Parcel source) { 619 List<Font> fonts = source.readParcelableList( 620 new ArrayList<>(), Font.class.getClassLoader()); 621 String name = source.readString8(); 622 String langTags = source.readString8(); 623 int variant = source.readInt(); 624 625 return new FontFamily(fonts, name, LocaleList.forLanguageTags(langTags), variant); 626 } 627 628 @Override 629 public FontFamily[] newArray(int size) { 630 return new FontFamily[size]; 631 } 632 }; 633 634 /** 635 * Returns the list of fonts included in this family. 636 * @deprecated Use getFontList instead 637 * @hide 638 */ 639 @Deprecated 640 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getFonts()641 public @Nullable Font[] getFonts() { 642 return mFonts.toArray(new Font[0]); 643 } 644 645 /** 646 * Returns the comma separated BCP47 compliant languages for this family. May be null. 647 * @deprecated Use getLocaleList instead 648 * @hide 649 */ 650 @Deprecated getLanguages()651 public @NonNull String getLanguages() { 652 return mLocaleList.toLanguageTags(); 653 } 654 655 @Override equals(Object o)656 public boolean equals(Object o) { 657 if (this == o) return true; 658 if (o == null || getClass() != o.getClass()) return false; 659 FontFamily that = (FontFamily) o; 660 return mVariant == that.mVariant 661 && Objects.equals(mFonts, that.mFonts) 662 && Objects.equals(mName, that.mName) 663 && Objects.equals(mLocaleList, that.mLocaleList); 664 } 665 666 @Override hashCode()667 public int hashCode() { 668 return Objects.hash(mFonts, mName, mLocaleList, mVariant); 669 } 670 671 @Override toString()672 public String toString() { 673 return "FontFamily{" 674 + "mFonts=" + mFonts 675 + ", mName='" + mName + '\'' 676 + ", mLocaleList=" + mLocaleList 677 + ", mVariant=" + mVariant 678 + '}'; 679 } 680 } 681 } 682