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.icu.util.ULocale;
32 import android.os.Build;
33 import android.os.LocaleList;
34 import android.os.Parcel;
35 import android.os.Parcelable;
36 
37 import java.io.File;
38 import java.lang.annotation.Retention;
39 import java.util.ArrayList;
40 import java.util.Collections;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Objects;
44 
45 
46 /**
47  * Font configuration descriptions for System fonts.
48  *
49  * FontConfig represents the configuration for the fonts installed on the system. It is made of list
50  * of font families and aliases.
51  *
52  * @see FontFamily
53  * @see Alias
54  * @hide
55  */
56 @SystemApi
57 @TestApi
58 public final class FontConfig implements Parcelable {
59     private final @NonNull List<FontFamily> mFamilies;
60     private final @NonNull List<Alias> mAliases;
61     private final @NonNull List<NamedFamilyList> mNamedFamilyLists;
62     private final @NonNull List<Customization.LocaleFallback> mLocaleFallbackCustomizations;
63     private final long mLastModifiedTimeMillis;
64     private final int mConfigVersion;
65 
66     /**
67      * Construct a FontConfig instance.
68      *
69      * @param families a list of font families.
70      * @param aliases a list of aliases.
71      *
72      * @hide Only system server can create this instance and passed via IPC.
73      */
FontConfig(@onNull List<FontFamily> families, @NonNull List<Alias> aliases, @NonNull List<NamedFamilyList> namedFamilyLists, @NonNull List<Customization.LocaleFallback> localeFallbackCustomizations, long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion)74     public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases,
75             @NonNull List<NamedFamilyList> namedFamilyLists,
76             @NonNull List<Customization.LocaleFallback> localeFallbackCustomizations,
77             long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) {
78         mFamilies = families;
79         mAliases = aliases;
80         mNamedFamilyLists = namedFamilyLists;
81         mLocaleFallbackCustomizations = localeFallbackCustomizations;
82         mLastModifiedTimeMillis = lastModifiedTimeMillis;
83         mConfigVersion = configVersion;
84     }
85 
86     /**
87      * @hide Keep this constructor for reoborectric.
88      */
FontConfig(@onNull List<FontFamily> families, @NonNull List<Alias> aliases, long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion)89     public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases,
90             long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) {
91         this(families, aliases, Collections.emptyList(), Collections.emptyList(),
92                 lastModifiedTimeMillis, configVersion);
93     }
94 
95 
96     /**
97      * Returns the ordered list of font families available in the system.
98      *
99      * @return a list of font families.
100      * @see FontFamily
101      */
getFontFamilies()102     public @NonNull List<FontFamily> getFontFamilies() {
103         return mFamilies;
104     }
105 
106     /**
107      * Returns the list of aliases for mapping font families with other names.
108      *
109      * @return a list of font families.
110      * @see Alias
111      */
getAliases()112     public @NonNull List<Alias> getAliases() {
113         return mAliases;
114     }
115 
getNamedFamilyLists()116     public @NonNull List<NamedFamilyList> getNamedFamilyLists() {
117         return mNamedFamilyLists;
118     }
119 
120     /**
121      * Returns a locale fallback customizations.
122      *
123      * This field is used for creating the system fallback in the system server. This field is
124      * always empty in the application process.
125      *
126      * @hide
127      */
getLocaleFallbackCustomizations()128     public @NonNull List<Customization.LocaleFallback> getLocaleFallbackCustomizations() {
129         return mLocaleFallbackCustomizations;
130     }
131 
132     /**
133      * Returns the last modified time in milliseconds.
134      *
135      * This is a value of {@link System#currentTimeMillis()} when the system font configuration was
136      * modified last time.
137      *
138      * If there is no update, this return 0.
139      */
getLastModifiedTimeMillis()140     public @CurrentTimeMillisLong long getLastModifiedTimeMillis() {
141         return mLastModifiedTimeMillis;
142     }
143 
144     /**
145      * Returns the monotonically increasing config version value.
146      *
147      * The config version is reset to 0 when the system is restarted.
148      */
getConfigVersion()149     public @IntRange(from = 0) int getConfigVersion() {
150         return mConfigVersion;
151     }
152 
153     /**
154      * Returns the ordered list of families included in the system fonts.
155      * @deprecated Use getFontFamilies instead.
156      * @hide
157      */
158     @Deprecated
159     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getFamilies()160     public @NonNull FontFamily[] getFamilies() {
161         return mFamilies.toArray(new FontFamily[0]);
162     }
163 
164     @Override
describeContents()165     public int describeContents() {
166         return 0;
167     }
168 
169     @Override
writeToParcel(@onNull Parcel dest, int flags)170     public void writeToParcel(@NonNull Parcel dest, int flags) {
171         dest.writeTypedList(mFamilies, flags);
172         dest.writeTypedList(mAliases, flags);
173         dest.writeTypedList(mNamedFamilyLists, flags);
174         dest.writeLong(mLastModifiedTimeMillis);
175         dest.writeInt(mConfigVersion);
176     }
177 
178     public static final @NonNull Creator<FontConfig> CREATOR = new Creator<FontConfig>() {
179         @Override
180         public FontConfig createFromParcel(Parcel source) {
181             final List<FontFamily> families = new ArrayList<>();
182             source.readTypedList(families, FontFamily.CREATOR);
183             final List<Alias> aliases = new ArrayList<>();
184             source.readTypedList(aliases, Alias.CREATOR);
185             final List<NamedFamilyList> familyLists = new ArrayList<>();
186             source.readTypedList(familyLists, NamedFamilyList.CREATOR);
187             long lastModifiedDate = source.readLong();
188             int configVersion = source.readInt();
189             return new FontConfig(families, aliases, familyLists,
190                     Collections.emptyList(),  // Don't need to pass customization to API caller.
191                     lastModifiedDate, configVersion);
192         }
193 
194         @Override
195         public FontConfig[] newArray(int size) {
196             return new FontConfig[size];
197         }
198     };
199 
200     @Override
equals(Object o)201     public boolean equals(Object o) {
202         if (this == o) return true;
203         if (o == null || getClass() != o.getClass()) return false;
204         FontConfig that = (FontConfig) o;
205         return mLastModifiedTimeMillis == that.mLastModifiedTimeMillis
206                 && mConfigVersion == that.mConfigVersion
207                 && Objects.equals(mFamilies, that.mFamilies)
208                 && Objects.equals(mAliases, that.mAliases);
209     }
210 
211     @Override
hashCode()212     public int hashCode() {
213         return Objects.hash(mFamilies, mAliases, mLastModifiedTimeMillis, mConfigVersion);
214     }
215 
216     @Override
toString()217     public String toString() {
218         return "FontConfig{"
219                 + "mFamilies=" + mFamilies
220                 + ", mAliases=" + mAliases
221                 + ", mLastModifiedTimeMillis=" + mLastModifiedTimeMillis
222                 + ", mConfigVersion=" + mConfigVersion
223                 + '}';
224     }
225 
226     /**
227      * Represents single font entry in system font configuration.
228      *
229      * A font is the most primitive unit of drawing character shapes. A font in system configuration
230      * is always referring a single OpenType compliant regular file in the file system.
231      *
232      * @see android.graphics.fonts.Font
233      */
234     public static final class Font implements Parcelable {
235         private final @NonNull File mFile;
236         private final @Nullable File mOriginalFile;
237         private final @NonNull String mPostScriptName;
238         private final @NonNull FontStyle mStyle;
239         private final @IntRange(from = 0) int mIndex;
240         private final @NonNull String mFontVariationSettings;
241         private final @Nullable String mFontFamilyName;
242         private final @VarTypeAxes int mVarTypeAxes;
243 
244         /** @hide */
245         @Retention(SOURCE)
246         @IntDef(prefix = { "VAR_TYPE_AXES_" }, value = {
247                 VAR_TYPE_AXES_NONE,
248                 VAR_TYPE_AXES_WGHT,
249                 VAR_TYPE_AXES_ITAL,
250         })
251         public @interface VarTypeAxes {}
252 
253         /** @hide */
254         public static final int VAR_TYPE_AXES_NONE = 0;
255         /** @hide */
256         public static final int VAR_TYPE_AXES_WGHT = 1;
257         /** @hide */
258         public static final int VAR_TYPE_AXES_ITAL = 2;
259 
260         /**
261          * Construct a Font instance.
262          *
263          * @hide Only system server can create this instance and passed via IPC.
264          */
Font(@onNull File file, @Nullable File originalFile, @NonNull String postScriptName, @NonNull FontStyle style, @IntRange(from = 0) int index, @NonNull String fontVariationSettings, @Nullable String fontFamilyName, @VarTypeAxes int varTypeAxes)265         public Font(@NonNull File file, @Nullable File originalFile, @NonNull String postScriptName,
266                 @NonNull FontStyle style, @IntRange(from = 0) int index,
267                 @NonNull String fontVariationSettings, @Nullable String fontFamilyName,
268                 @VarTypeAxes int varTypeAxes) {
269             mFile = file;
270             mOriginalFile = originalFile;
271             mPostScriptName = postScriptName;
272             mStyle = style;
273             mIndex = index;
274             mFontVariationSettings = fontVariationSettings;
275             mFontFamilyName = fontFamilyName;
276             mVarTypeAxes = varTypeAxes;
277         }
278 
279         @Override
describeContents()280         public int describeContents() {
281             return 0;
282         }
283 
284         @Override
writeToParcel(@onNull Parcel dest, int flags)285         public void writeToParcel(@NonNull Parcel dest, int flags) {
286             dest.writeString8(mFile.getAbsolutePath());
287             dest.writeString8(mOriginalFile == null ? null : mOriginalFile.getAbsolutePath());
288             dest.writeString8(mPostScriptName);
289             dest.writeInt(mStyle.getWeight());
290             dest.writeInt(mStyle.getSlant());
291             dest.writeInt(mIndex);
292             dest.writeString8(mFontVariationSettings);
293             dest.writeString8(mFontFamilyName);
294             dest.writeInt(mVarTypeAxes);
295         }
296 
297         public static final @NonNull Creator<Font> CREATOR = new Creator<Font>() {
298 
299             @Override
300             public Font createFromParcel(Parcel source) {
301                 File path = new File(source.readString8());
302                 String originalPathStr = source.readString8();
303                 File originalPath = originalPathStr == null ? null : new File(originalPathStr);
304                 String postScriptName = source.readString8();
305                 int weight = source.readInt();
306                 int slant = source.readInt();
307                 int index = source.readInt();
308                 String varSettings = source.readString8();
309                 String fallback = source.readString8();
310                 int varTypeAxes = source.readInt();
311 
312                 return new Font(path, originalPath, postScriptName, new FontStyle(weight, slant),
313                         index, varSettings, fallback, varTypeAxes);
314             }
315 
316             @Override
317             public Font[] newArray(int size) {
318                 return new Font[size];
319             }
320         };
321 
322         /**
323          * Returns the font file.
324          */
getFile()325         public @NonNull File getFile() {
326             return mFile;
327         }
328 
329         /**
330          * Returns the original font file in the system directory.
331          *
332          * If the font file is not updated, returns null.
333          *
334          * @return returns the original font file in the system if the font file is updated. Returns
335          *         null if the font file is not updated.
336          * @hide
337          */
getOriginalFile()338         public @Nullable File getOriginalFile() {
339             return mOriginalFile;
340         }
341 
342         /**
343          * Returns the font style.
344          */
getStyle()345         public @NonNull FontStyle getStyle() {
346             return mStyle;
347         }
348 
349 
350         /**
351          * Return a font variation settings.
352          */
getFontVariationSettings()353         public @NonNull String getFontVariationSettings() {
354             return mFontVariationSettings;
355         }
356 
357         /**
358          * A {@link Font} can be configured to be in the {@code Fallback List} for a
359          * {@link FontFamily}.
360          *
361          * For example a serif Hebrew [Font] can be defined in the {@code Fallback List} for
362          * {@code "serif"} {@link FontFamily}.
363          *
364          * If the return value is not {@code null}, then the font will be used in the
365          * {@code Fallback List} of that {@link FontFamily}.
366          *
367          * If the return value is {@code null}, then the font will be used in {@code Fallback List}
368          * of all {@link FontFamily}s.
369          */
getFontFamilyName()370         public @Nullable String getFontFamilyName() {
371             return mFontFamilyName;
372         }
373 
374         /**
375          * Returns the index to be used to access this font when accessing a TTC file.
376          */
getTtcIndex()377         public int getTtcIndex() {
378             return mIndex;
379         }
380 
381         /**
382          * Returns the PostScript name of this font.
383          */
getPostScriptName()384         public @NonNull String getPostScriptName() {
385             return mPostScriptName;
386         }
387 
388         /**
389          * Returns the list of supported axes tags for variable family type resolution.
390          *
391          * @hide
392          */
getVarTypeAxes()393         public @VarTypeAxes int getVarTypeAxes() {
394             return mVarTypeAxes;
395         }
396 
397         /**
398          * Returns the list of axes associated to this font.
399          * @deprecated Use getFontVariationSettings
400          * @hide
401          */
402         @Deprecated
403         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getAxes()404         public @NonNull FontVariationAxis[] getAxes() {
405             return FontVariationAxis.fromFontVariationSettings(mFontVariationSettings);
406         }
407 
408         /**
409          * Returns the weight value for this font.
410          * @deprecated Use getStyle instead.
411          * @hide
412          */
413         @Deprecated
414         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getWeight()415         public int getWeight() {
416             return getStyle().getWeight();
417         }
418 
419         /**
420          * Returns whether this font is italic.
421          * @deprecated Use getStyle instead.
422          * @hide
423          */
424         @Deprecated
425         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isItalic()426         public boolean isItalic() {
427             return getStyle().getSlant() == FontStyle.FONT_SLANT_ITALIC;
428         }
429 
430         @Override
equals(Object o)431         public boolean equals(Object o) {
432             if (this == o) return true;
433             if (o == null || getClass() != o.getClass()) return false;
434             Font font = (Font) o;
435             return mIndex == font.mIndex
436                     && Objects.equals(mFile, font.mFile)
437                     && Objects.equals(mOriginalFile, font.mOriginalFile)
438                     && Objects.equals(mStyle, font.mStyle)
439                     && Objects.equals(mFontVariationSettings, font.mFontVariationSettings)
440                     && Objects.equals(mFontFamilyName, font.mFontFamilyName)
441                     && mVarTypeAxes == font.mVarTypeAxes;
442         }
443 
444         @Override
hashCode()445         public int hashCode() {
446             return Objects.hash(mFile, mOriginalFile, mStyle, mIndex, mFontVariationSettings,
447                     mFontFamilyName, mVarTypeAxes);
448         }
449 
450         @Override
toString()451         public String toString() {
452             return "Font{"
453                     + "mFile=" + mFile
454                     + ", mOriginalFile=" + mOriginalFile
455                     + ", mStyle=" + mStyle
456                     + ", mIndex=" + mIndex
457                     + ", mFontVariationSettings='" + mFontVariationSettings + '\''
458                     + ", mFontFamilyName='" + mFontFamilyName + '\''
459                     + ", mVarTypeAxes='" + mVarTypeAxes + '\''
460                     + '}';
461         }
462     }
463 
464     /**
465      * Alias provides an alternative name for an existing font family.
466      *
467      * In the system font configuration, a font family can be an alias of another font family with
468      * different font weight. For example, "sans-serif-medium" can be a medium weight of
469      * "sans-serif" font family. In this example, {@link #getName()} returns "sans-serif-medium" and
470      * {@link #getOriginal()} return "sans-serif". The font family that doesn't have name can not be
471      * an original of the alias.
472      */
473     public static final class Alias implements Parcelable {
474         private final @NonNull String mName;
475         private final @NonNull String mOriginal;
476         private final @IntRange(from = 0, to = 1000) int mWeight;
477 
478         /**
479          * Construct an alias instance.
480          *
481          * @param name alias for the font family.
482          * @param original original font family name.
483          * @param weight font weight of the original font family.
484          * @hide Only system server can create this instance and passed via IPC.
485          */
Alias(@onNull String name, @NonNull String original, @IntRange(from = 0, to = 1000) int weight)486         public Alias(@NonNull String name, @NonNull String original,
487                 @IntRange(from = 0, to = 1000) int weight) {
488             mName = name;
489             mOriginal = original;
490             mWeight = weight;
491         }
492 
493         /**
494          * Alias for the font family
495          */
getName()496         public @NonNull String getName() {
497             return mName;
498         }
499 
500         /**
501          * The name of the original font family.
502          */
getOriginal()503         public @NonNull String getOriginal() {
504             return mOriginal;
505         }
506 
507         /**
508          * A font weight of the referring font family.
509          *
510          * @return a font weight of the referring font family.
511          */
getWeight()512         public @IntRange(from = 0, to = 1000) int getWeight() {
513             return mWeight;
514         }
515 
516         @Override
describeContents()517         public int describeContents() {
518             return 0;
519         }
520 
521         @Override
writeToParcel(@onNull Parcel dest, int flags)522         public void writeToParcel(@NonNull Parcel dest, int flags) {
523             dest.writeString8(mName);
524             dest.writeString8(mOriginal);
525             dest.writeInt(mWeight);
526         }
527 
528         public static final @NonNull Creator<Alias> CREATOR = new Creator<Alias>() {
529 
530             @Override
531             public Alias createFromParcel(Parcel source) {
532                 String alias = source.readString8();
533                 String referName = source.readString8();
534                 int weight = source.readInt();
535                 return new Alias(alias, referName, weight);
536             }
537 
538             @Override
539             public Alias[] newArray(int size) {
540                 return new Alias[size];
541             }
542         };
543 
544         @Override
equals(Object o)545         public boolean equals(Object o) {
546             if (this == o) return true;
547             if (o == null || getClass() != o.getClass()) return false;
548             Alias alias = (Alias) o;
549             return mWeight == alias.mWeight
550                     && Objects.equals(mName, alias.mName)
551                     && Objects.equals(mOriginal, alias.mOriginal);
552         }
553 
554         @Override
hashCode()555         public int hashCode() {
556             return Objects.hash(mName, mOriginal, mWeight);
557         }
558 
559         @Override
toString()560         public String toString() {
561             return "Alias{"
562                     + "mName='" + mName + '\''
563                     + ", mOriginal='" + mOriginal + '\''
564                     + ", mWeight=" + mWeight
565                     + '}';
566         }
567     }
568 
569     /**
570      * Represents a font family in the system font configuration.
571      *
572      * A {@link FontFamily} is a list of {@link Font}s for drawing text in various styles such as
573      * weight, slant.
574      *
575      * For example, a {@link FontFamily} can include the regular and bold styles of a {@link Font}.
576      *
577      * @see android.graphics.fonts.FontFamily
578      */
579     public static final class FontFamily implements Parcelable {
580         private final @NonNull List<Font> mFonts;
581         private final @NonNull LocaleList mLocaleList;
582         private final @Variant int mVariant;
583 
584         /** @hide */
585         @Retention(SOURCE)
586         @IntDef(prefix = { "VARIANT_" }, value = {
587                 VARIANT_DEFAULT,
588                 VARIANT_COMPACT,
589                 VARIANT_ELEGANT
590         })
591         public @interface Variant {}
592 
593         /**
594          * Value for font variant.
595          *
596          * Indicates the font has no variant attribute.
597          */
598         public static final int VARIANT_DEFAULT = 0;
599 
600         /**
601          * Value for font variant.
602          *
603          * Indicates the font is for compact variant.
604          * @see android.graphics.Paint#setElegantTextHeight
605          */
606         public static final int VARIANT_COMPACT = 1;
607 
608         /**
609          * Value for font variant.
610          *
611          * Indicates the font is for elegant variant.
612          * @see android.graphics.Paint#setElegantTextHeight
613          */
614         public static final int VARIANT_ELEGANT = 2;
615 
616         /**
617          * Construct a family instance.
618          *
619          * @hide Only system server can create this instance and passed via IPC.
620          */
FontFamily(@onNull List<Font> fonts, @NonNull LocaleList localeList, @Variant int variant)621         public FontFamily(@NonNull List<Font> fonts, @NonNull LocaleList localeList,
622                 @Variant int variant) {
623             mFonts = fonts;
624             mLocaleList = localeList;
625             mVariant = variant;
626         }
627 
628         /**
629          * Returns the list of {@link Font}s in this {@link FontFamily}.
630          *
631          * @return a list of font files.
632          */
getFontList()633         public @NonNull List<Font> getFontList() {
634             return mFonts;
635         }
636 
637         /**
638          * Returns the name of the {@link FontFamily}.
639          *
640          * When the name of a {@link FontFamily} is not null, this name is used to create a new
641          * {@code Fallback List}, and that {@code Fallback List}. Fallback List is the
642          * main building block for a {@link android.graphics.Typeface}.
643          *
644          * For example, if the {@link FontFamily} has the name "serif", then the system will create
645          * a “serif” {@code Fallback List} and it can be used by creating a Typeface via
646          * {@code Typeface.create("serif", Typeface.NORMAL);}
647          *
648          * When the name of a {@link FontFamily} is null, it will be appended to all of the
649          * {@code Fallback List}s.
650          *
651          * @deprecated From API 34, this function always returns null. All font families which have
652          *             name attribute will be reported as a {@link NamedFamilyList}.
653          */
654         @Deprecated
getName()655         public @Nullable String getName() {
656             return null;
657         }
658 
659         /**
660          * Returns the locale list if available.
661          *
662          * The locale list will be used for deciding which font family should be used in fallback
663          * list.
664          */
getLocaleList()665         public @NonNull LocaleList getLocaleList() {
666             return mLocaleList;
667         }
668 
669         /**
670          * Returns the text height variant.
671          */
getVariant()672         public @Variant int getVariant() {
673             return mVariant;
674         }
675 
676         @Override
describeContents()677         public int describeContents() {
678             return 0;
679         }
680 
681         @Override
writeToParcel(@onNull Parcel dest, int flags)682         public void writeToParcel(@NonNull Parcel dest, int flags) {
683             dest.writeTypedList(mFonts, flags);
684             dest.writeString8(mLocaleList.toLanguageTags());
685             dest.writeInt(mVariant);
686         }
687 
688         public static final @NonNull Creator<FontFamily> CREATOR = new Creator<FontFamily>() {
689 
690             @Override
691             public FontFamily createFromParcel(Parcel source) {
692                 List<Font> fonts = new ArrayList<>();
693                 source.readTypedList(fonts, Font.CREATOR);
694                 String langTags = source.readString8();
695                 int variant = source.readInt();
696 
697                 return new FontFamily(fonts, LocaleList.forLanguageTags(langTags), variant);
698             }
699 
700             @Override
701             public FontFamily[] newArray(int size) {
702                 return new FontFamily[size];
703             }
704         };
705 
706         /**
707          * Returns the list of fonts included in this family.
708          * @deprecated Use getFontList instead
709          * @hide
710          */
711         @Deprecated
712         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getFonts()713         public @Nullable Font[] getFonts() {
714             return mFonts.toArray(new Font[0]);
715         }
716 
717         /**
718          * Returns the comma separated BCP47 compliant languages for this family. May be null.
719          * @deprecated Use getLocaleList instead
720          * @hide
721          */
722         @Deprecated
getLanguages()723         public @NonNull String getLanguages() {
724             return mLocaleList.toLanguageTags();
725         }
726 
727         @Override
equals(Object o)728         public boolean equals(Object o) {
729             if (this == o) return true;
730             if (o == null || getClass() != o.getClass()) return false;
731             FontFamily that = (FontFamily) o;
732             return mVariant == that.mVariant
733                     && Objects.equals(mFonts, that.mFonts)
734                     && Objects.equals(mLocaleList, that.mLocaleList);
735         }
736 
737         @Override
hashCode()738         public int hashCode() {
739             return Objects.hash(mFonts, mLocaleList, mVariant);
740         }
741 
742         @Override
toString()743         public String toString() {
744             return "FontFamily{"
745                     + "mFonts=" + mFonts
746                     + ", mLocaleList=" + mLocaleList
747                     + ", mVariant=" + mVariant
748                     + '}';
749         }
750     }
751 
752     /**
753      * Represents list of font family in the system font configuration.
754      *
755      * In the fonts_customization.xml, it can define the list of FontFamily as a named family. The
756      * list of FontFamily is treated as a fallback list when drawing.
757      *
758      * @see android.graphics.fonts.FontFamily
759      */
760     public static final class NamedFamilyList implements Parcelable {
761         private final List<FontFamily> mFamilies;
762         private final String mName;
763 
764         /** @hide */
NamedFamilyList(@onNull List<FontFamily> families, @NonNull String name)765         public NamedFamilyList(@NonNull List<FontFamily> families, @NonNull String name) {
766             mFamilies = families;
767             mName = name;
768         }
769 
770         /** @hide */
NamedFamilyList(@onNull FontFamily family)771         public NamedFamilyList(@NonNull FontFamily family) {
772             mFamilies = new ArrayList<>();
773             mFamilies.add(family);
774             mName = family.getName();
775         }
776 
777         /**
778          * A list of font families.
779          *
780          * @return a list of font families.
781          */
getFamilies()782         public @NonNull List<FontFamily> getFamilies() {
783             return mFamilies;
784         }
785 
786         /**
787          * Returns the name of the {@link FontFamily}.
788          *
789          * This name is used to create a new {@code Fallback List}.
790          *
791          * For example, if the {@link FontFamily} has the name "serif", then the system will create
792          * a “serif” {@code Fallback List} and it can be used by creating a Typeface via
793          * {@code Typeface.create("serif", Typeface.NORMAL);}
794          */
getName()795         public @NonNull String getName() {
796             return mName;
797         }
798 
799         @Override
describeContents()800         public int describeContents() {
801             return 0;
802         }
803 
804         @Override
writeToParcel(@ndroidx.annotation.NonNull Parcel dest, int flags)805         public void writeToParcel(@androidx.annotation.NonNull Parcel dest, int flags) {
806             dest.writeTypedList(mFamilies, flags);
807             dest.writeString8(mName);
808         }
809 
810         public static final @NonNull Creator<NamedFamilyList> CREATOR = new Creator<>() {
811 
812             @Override
813             public NamedFamilyList createFromParcel(Parcel source) {
814                 final List<FontFamily> families = new ArrayList<>();
815                 source.readTypedList(families, FontFamily.CREATOR);
816                 String name = source.readString8();
817                 return new NamedFamilyList(families, name);
818             }
819 
820             @Override
821             public NamedFamilyList[] newArray(int size) {
822                 return new NamedFamilyList[size];
823             }
824         };
825 
826         @Override
equals(Object o)827         public boolean equals(Object o) {
828             if (this == o) return true;
829             if (o == null || getClass() != o.getClass()) return false;
830             NamedFamilyList that = (NamedFamilyList) o;
831             return Objects.equals(mFamilies, that.mFamilies) && Objects.equals(mName,
832                     that.mName);
833         }
834 
835         @Override
hashCode()836         public int hashCode() {
837             return Objects.hash(mFamilies, mName);
838         }
839 
840         @Override
toString()841         public String toString() {
842             return "NamedFamilyList{"
843                     + "mFamilies=" + mFamilies
844                     + ", mName='" + mName + '\''
845                     + '}';
846         }
847     }
848 
849     /** @hide */
850     public static class Customization {
Customization()851         private Customization() {}  // Singleton
852 
853         /**
854          * A class that represents customization of locale fallback
855          *
856          * This class represents a vendor customization of new-locale-family.
857          *
858          * <pre>
859          * <family customizationType="new-locale-family" operation="prepend" lang="ja-JP">
860          *     <font weight="400" style="normal">MyAlternativeFont.ttf
861          *         <axis tag="wght" stylevalue="400"/>
862          *     </font>
863          * </family>
864          * </pre>
865          *
866          * The operation can be one of prepend, replace or append. The operation prepend means that
867          * the new font family is inserted just before the original font family. The original font
868          * family is still in the fallback. The operation replace means that the original font
869          * family is replaced with new font family. The original font family is removed from the
870          * fallback. The operation append means that the new font family is inserted just after the
871          * original font family. The original font family is still in the fallback.
872          *
873          * The lang attribute is a BCP47 compliant language tag. The font fallback mainly uses ISO
874          * 15924 script code for matching. If the script code is missing, most likely script code
875          * will be used.
876          */
877         public static class LocaleFallback {
878             private final Locale mLocale;
879             private final int mOperation;
880             private final FontFamily mFamily;
881             private final String mScript;
882 
883             public static final int OPERATION_PREPEND = 0;
884             public static final int OPERATION_APPEND = 1;
885             public static final int OPERATION_REPLACE = 2;
886 
887             /** @hide */
888             @Retention(SOURCE)
889             @IntDef(prefix = { "OPERATION_" }, value = {
890                     OPERATION_PREPEND,
891                     OPERATION_APPEND,
892                     OPERATION_REPLACE
893             })
894             public @interface Operation {}
895 
896 
LocaleFallback(@onNull Locale locale, @Operation int operation, @NonNull FontFamily family)897             public LocaleFallback(@NonNull Locale locale, @Operation int operation,
898                     @NonNull FontFamily family) {
899                 mLocale = locale;
900                 mOperation = operation;
901                 mFamily = family;
902                 mScript = resolveScript(locale);
903             }
904 
905             /**
906              * A customization target locale.
907              * @return a locale
908              */
getLocale()909             public @NonNull Locale getLocale() {
910                 return mLocale;
911             }
912 
913             /**
914              * An operation to be applied to the original font family.
915              *
916              * The operation can be one of {@link #OPERATION_PREPEND}, {@link #OPERATION_REPLACE} or
917              * {@link #OPERATION_APPEND}.
918              *
919              * The operation prepend ({@link #OPERATION_PREPEND}) means that the new font family is
920              * inserted just before the original font family. The original font family is still in
921              * the fallback.
922              *
923              * The operation replace ({@link #OPERATION_REPLACE}) means that the original font
924              * family is replaced with new font family. The original font family is removed from the
925              * fallback.
926              *
927              * The operation append ({@link #OPERATION_APPEND}) means that the new font family is
928              * inserted just after the original font family. The original font family is still in
929              * the fallback.
930              *
931              * @return an operation.
932              */
getOperation()933             public @Operation int getOperation() {
934                 return mOperation;
935             }
936 
937             /**
938              * Returns a family to be inserted or replaced to the fallback.
939              *
940              * @return a family
941              */
getFamily()942             public @NonNull FontFamily getFamily() {
943                 return mFamily;
944             }
945 
946             /**
947              * Returns a script of the locale. If the script is missing in the given locale, the
948              * most likely locale is returned.
949              */
getScript()950             public @NonNull String getScript() {
951                 return mScript;
952             }
953 
954             @Override
toString()955             public String toString() {
956                 return "LocaleFallback{"
957                         + "mLocale=" + mLocale
958                         + ", mOperation=" + mOperation
959                         + ", mFamily=" + mFamily
960                         + '}';
961             }
962         }
963     }
964 
965     /** @hide */
resolveScript(Locale locale)966     public static String resolveScript(Locale locale) {
967         String script = locale.getScript();
968         if (script != null && !script.isEmpty()) {
969             return script;
970         }
971         return ULocale.addLikelySubtags(ULocale.forLocale(locale)).getScript();
972     }
973 }
974