Add FontManager API and font manager shell commands

FontManager is an interface of communicating with FontManaserService.
With this CL, system apps can know the primitive information about
what font files are installed and how it is configured.

This CL also adds shell command of dumping font configuration.
Example usages are:

  # dump primitive font configuration.
  adb shell dumpsys font

  # dump fallback font list
  adb shell cmd font dump serif

Bug: 173619554
Test: atest FontManagerTest
Test: Manually confirmed above commands works.
Change-Id: I5cb855308e199ac38bd7b56b60821346247bdce3
This commit is contained in:
Seigo Nonaka
2021-01-18 20:25:16 -08:00
parent 9e5ec68e4d
commit 46d6a3f9ce
15 changed files with 838 additions and 160 deletions

View File

@@ -1927,6 +1927,7 @@ package android.content {
field public static final String CONTEXTHUB_SERVICE = "contexthub";
field public static final String ETHERNET_SERVICE = "ethernet";
field public static final String EUICC_CARD_SERVICE = "euicc_card";
field public static final String FONT_SERVICE = "font";
field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final String MEDIA_TRANSCODING_SERVICE = "media_transcoding";
field public static final String MUSIC_RECOGNITION_SERVICE = "music_recognition";
@@ -2588,6 +2589,14 @@ package android.graphics.drawable {
}
package android.graphics.fonts {
public class FontManager {
method @Nullable public android.text.FontConfig getFontConfig();
}
}
package android.hardware {
public final class Sensor {
@@ -13451,6 +13460,51 @@ package android.telephony.mbms.vendor {
}
package android.text {
public final class FontConfig implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.text.FontConfig.Alias> getAliases();
method @NonNull public java.util.List<android.text.FontConfig.FontFamily> getFontFamilies();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
}
public static final class FontConfig.Alias implements android.os.Parcelable {
method public int describeContents();
method @NonNull public String getName();
method @NonNull public String getOriginal();
method @IntRange(from=0, to=1000) public int getWeight();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
}
public static final class FontConfig.Font implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.io.File getFile();
method @Nullable public String getFontFamilyName();
method @NonNull public String getFontVariationSettings();
method @NonNull public android.graphics.fonts.FontStyle getStyle();
method public int getTtcIndex();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
}
public static final class FontConfig.FontFamily implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.text.FontConfig.Font> getFontList();
method @NonNull public android.os.LocaleList getLocaleList();
method @Nullable public String getName();
method public int getVariant();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.FontFamily> CREATOR;
field public static final int VARIANT_COMPACT = 1; // 0x1
field public static final int VARIANT_DEFAULT = 0; // 0x0
field public static final int VARIANT_ELEGANT = 2; // 0x2
}
}
package android.util {
public class EventLog {

View File

@@ -627,6 +627,7 @@ package android.content {
field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture";
field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle";
field public static final String DREAM_SERVICE = "dream";
field public static final String FONT_SERVICE = "font";
field public static final String POWER_WHITELIST_MANAGER = "power_whitelist";
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
@@ -819,6 +820,14 @@ package android.graphics.drawable {
}
package android.graphics.fonts {
public class FontManager {
method @Nullable public android.text.FontConfig getFontConfig();
}
}
package android.hardware {
public final class SensorPrivacyManager {
@@ -2014,6 +2023,47 @@ package android.telephony.ims.feature {
package android.text {
public final class FontConfig implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.text.FontConfig.Alias> getAliases();
method @NonNull public java.util.List<android.text.FontConfig.FontFamily> getFontFamilies();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
}
public static final class FontConfig.Alias implements android.os.Parcelable {
method public int describeContents();
method @NonNull public String getName();
method @NonNull public String getOriginal();
method @IntRange(from=0, to=1000) public int getWeight();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.Alias> CREATOR;
}
public static final class FontConfig.Font implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.io.File getFile();
method @Nullable public String getFontFamilyName();
method @NonNull public String getFontVariationSettings();
method @NonNull public android.graphics.fonts.FontStyle getStyle();
method public int getTtcIndex();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.Font> CREATOR;
}
public static final class FontConfig.FontFamily implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.text.FontConfig.Font> getFontList();
method @NonNull public android.os.LocaleList getLocaleList();
method @Nullable public String getName();
method public int getVariant();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig.FontFamily> CREATOR;
field public static final int VARIANT_COMPACT = 1; // 0x1
field public static final int VARIANT_DEFAULT = 0; // 0x0
field public static final int VARIANT_ELEGANT = 2; // 0x2
}
public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher {
ctor public Selection.MemoryTextWatcher();
method public void afterTextChanged(android.text.Editable);

View File

@@ -72,6 +72,7 @@ import android.content.res.Resources;
import android.content.rollback.RollbackManagerFrameworkInitializer;
import android.debug.AdbManager;
import android.debug.IAdbManager;
import android.graphics.fonts.FontManager;
import android.hardware.ConsumerIrManager;
import android.hardware.ISerialManager;
import android.hardware.SensorManager;
@@ -216,6 +217,7 @@ import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.ISoundTriggerService;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.graphics.fonts.IFontManager;
import com.android.internal.net.INetworkWatchlistManager;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
@@ -344,6 +346,14 @@ public final class SystemServiceRegistry {
return new TextClassificationManager(ctx);
}});
registerService(Context.FONT_SERVICE, FontManager.class,
new CachedServiceFetcher<FontManager>() {
@Override
public FontManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.FONT_SERVICE);
return FontManager.create(IFontManager.Stub.asInterface(b));
}});
registerService(Context.CLIPBOARD_SERVICE, ClipboardManager.class,
new CachedServiceFetcher<ClipboardManager>() {
@Override

View File

@@ -4476,6 +4476,18 @@ public abstract class Context {
*/
public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification";
/**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.graphics.fonts.FontManager} for font services.
*
* @see #getSystemService(String)
* @see android.graphics.fonts.FontManager
* @hide
*/
@SystemApi
@TestApi
public static final String FONT_SERVICE = "font";
/**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link com.android.server.attention.AttentionManagerService} for attention services.

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics.fonts;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
import android.text.FontConfig;
import android.util.Log;
import com.android.internal.graphics.fonts.IFontManager;
import java.util.Objects;
/**
* This class gives you control of system installed font files.
* @hide
*/
@SystemApi
@TestApi
@SystemService(Context.FONT_SERVICE)
public class FontManager {
private static final String TAG = "FontManager";
private final @NonNull IFontManager mIFontManager;
private FontManager(@NonNull IFontManager iFontManager) {
mIFontManager = iFontManager;
}
/**
* Returns the system font configuration.
*
* This information is expected to be used by system font updater. If you are looking for APIs
* about drawing text and/or high-level system font information, use
* {@link android.graphics.Typeface} or {@link SystemFonts} instead.
*
* @return The current font configuration. null if failed to fetch information from the system
* service.
*/
public @Nullable FontConfig getFontConfig() {
try {
return mIFontManager.getFontConfig();
} catch (RemoteException e) {
Log.e(TAG, "Failed to call getFontConfig", e);
return null;
}
}
/**
* Factory method of the FontManager.
*
* Do not use this method directly. Use getSystemService(Context.FONT_SERVICE) instead.
*
* @return A new instance of FontManager
* @hide
*/
public static FontManager create(@NonNull IFontManager iFontManager) {
Objects.requireNonNull(iFontManager);
return new FontManager(iFontManager);
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.graphics.fonts;
/** @hide */
parcelable SystemFontState;

View File

@@ -22,51 +22,66 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
import android.os.Build;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.File;
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.List;
/**
* Font configuration descriptions for System fonts.
* @hide // TODO Make this SystemApi.
*
* FontConfig represents the configuration for the fonts installed on the system. It is made of list
* of font families and aliases.
*
* @see FontFamily
* @see Alias
* @hide
*/
public final class FontConfig {
private final @NonNull List<Family> mFamilies;
@SystemApi
@TestApi
public final class FontConfig implements Parcelable {
private final @NonNull List<FontFamily> mFamilies;
private final @NonNull List<Alias> mAliases;
/**
* Construct a SystemFontConfig instance.
* Construct a FontConfig instance.
*
* @param families a list of font families.
* @param aliases a list of aliases.
*
* @hide Only system server can create this instance and passed via IPC.
*/
public FontConfig(@NonNull List<Family> families, @NonNull List<Alias> aliases) {
public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> aliases) {
mFamilies = families;
mAliases = aliases;
}
/**
* Returns the ordered list of families included in the system fonts.
* Returns the ordered list of font families available in the system.
*
* @return a list of font families.
* @see FontFamily
*/
public @NonNull List<Family> getFontFamilies() {
public @NonNull List<FontFamily> getFontFamilies() {
return mFamilies;
}
/**
* Returns the list of aliases defined for the font families in the system fonts.
* Returns the list of aliases for mapping font families with other names.
*
* @return a list of font families.
* @see Alias
*/
public @NonNull List<Alias> getAliases() {
return mAliases;
@@ -75,106 +90,167 @@ public final class FontConfig {
/**
* Returns the ordered list of families included in the system fonts.
* @deprecated Use getFontFamilies instead.
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public @NonNull Family[] getFamilies() {
return mFamilies.toArray(new Family[0]);
public @NonNull FontFamily[] getFamilies() {
return mFamilies.toArray(new FontFamily[0]);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelableList(mFamilies, flags);
dest.writeParcelableList(mAliases, flags);
}
public static final @NonNull Creator<FontConfig> CREATOR = new Creator<FontConfig>() {
@Override
public FontConfig createFromParcel(Parcel source) {
List<FontFamily> families = source.readParcelableList(new ArrayList<>(),
FontFamily.class.getClassLoader());
List<Alias> aliases = source.readParcelableList(new ArrayList<>(),
Alias.class.getClassLoader());
return new FontConfig(families, aliases);
}
@Override
public FontConfig[] newArray(int size) {
return new FontConfig[size];
}
};
/**
* A class represents single font entry in system font configuration.
* Represents single font entry in system font configuration.
*
* A font is the most primitive unit of drawing character shapes. A font in system configuration
* is always referring a single OpenType compliant regular file in the file system.
*
* @see android.graphics.fonts.Font
*/
public static final class Font {
private final @NonNull File mFilePath;
private final @Nullable File mOriginalPath;
public static final class Font implements Parcelable {
private final @NonNull File mFile;
private final @Nullable File mOriginalFile;
private final @NonNull FontStyle mStyle;
private final @IntRange(from = 0) int mIndex;
private final @NonNull String mFontVariationSettings;
private final @Nullable String mFallback;
private final @Nullable String mFontFamilyName;
/**
* Construct a Font instance.
*
* @hide Only system server can create this instance and passed via IPC.
*/
public Font(@NonNull File filePath, @Nullable File originalPath, @NonNull FontStyle style,
public Font(@NonNull File file, @Nullable File originalFile, @NonNull FontStyle style,
@IntRange(from = 0) int index, @NonNull String fontVariationSettings,
@Nullable String fallback) {
mFilePath = filePath;
mOriginalPath = originalPath;
@Nullable String fontFamilyName) {
mFile = file;
mOriginalFile = originalFile;
mStyle = style;
mIndex = index;
mFontVariationSettings = fontVariationSettings;
mFallback = fallback;
mFontFamilyName = fontFamilyName;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mFile.getAbsolutePath());
dest.writeString8(mOriginalFile == null ? null : mOriginalFile.getAbsolutePath());
dest.writeInt(mStyle.getWeight());
dest.writeInt(mStyle.getSlant());
dest.writeInt(mIndex);
dest.writeString8(mFontVariationSettings);
dest.writeString8(mFontFamilyName);
}
public static final @NonNull Creator<Font> CREATOR = new Creator<Font>() {
@Override
public Font createFromParcel(Parcel source) {
File path = new File(source.readString8());
String originalPathStr = source.readString8();
File originalPath = originalPathStr == null ? null : new File(originalPathStr);
int weight = source.readInt();
int slant = source.readInt();
int index = source.readInt();
String varSettings = source.readString8();
String fallback = source.readString8();
return new Font(path, originalPath, new FontStyle(weight, slant), index,
varSettings, fallback);
}
@Override
public Font[] newArray(int size) {
return new Font[size];
}
};
/**
* Returns a file to the font file.
*
* @return a font file.
* Returns the font file.
*/
public @NonNull File getFilePath() {
return mFilePath;
public @NonNull File getFile() {
return mFile;
}
/**
* Returns an original font file in the system directory.
* Returns the original font file in the system directory.
*
* If the font file is not updated, returns null.
*
* @return returns the original font file in the system if the font file is updated. Returns
* null if the font file is not updated.
* @hide
*/
public @Nullable File getOriginalPath() {
return mOriginalPath;
public @Nullable File getOriginalFile() {
return mOriginalFile;
}
/**
* Returns a font style.
*
* @return a font style.
* Returns the font style.
*/
public @NonNull FontStyle getStyle() {
return mStyle;
}
/**
* Returns a font index.
*
* @return a font index.
*/
public @IntRange(from = 0) int getIndex() {
return mIndex;
}
/**
* Return a font variation settings.
*
* @return a font variation settings.
*/
public @NonNull String getFontVariationSettings() {
return mFontVariationSettings;
}
/**
* Returns font family name that uses this font as a fallback.
* A {@link Font} can be configured to be in the {@code Fallback List} for a
* {@link FontFamily}.
*
* If this font is a fallback for the default font family, this is null.
* For example a serif Hebrew [Font] can be defined in the {@code Fallback List} for
* {@code "serif"} {@link FontFamily}.
*
* @return a font family name.
* If the return value is not {@code null}, then the font will be used in the
* {@code Fallback List} of that {@link FontFamily}.
*
* If the return value is {@code null}, then the font will be used in {@code Fallback List}
* of all {@link FontFamily}s.
*/
public @Nullable String getFallback() {
return mFallback;
public @Nullable String getFontFamilyName() {
return mFontFamilyName;
}
/**
* Returns the index to be used to access this font when accessing a TTC file.
* @deprecated Use getIndex instead.
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int getTtcIndex() {
return mIndex;
}
@@ -214,48 +290,46 @@ public final class FontConfig {
}
/**
* A class represents alias between named font families.
* Alias provides an alternative name for an existing font family.
*
* In the system font configuration, an font family can be an alias of another font family with
* In the system font configuration, a font family can be an alias of another font family with
* different font weight. For example, "sans-serif-medium" can be a medium weight of
* sans-serif font family.
* "sans-serif" font family. In this example, {@link #getName()} returns "sans-serif-medium" and
* {@link #getOriginal()} return "sans-serif". The font family that doesn't have name can not be
* an original of the alias.
*/
public static final class Alias {
private final @NonNull String mAliasName;
private final @NonNull String mReferName;
public static final class Alias implements Parcelable {
private final @NonNull String mName;
private final @NonNull String mOriginal;
private final @IntRange(from = 0, to = 1000) int mWeight;
/**
* Construct an alias instance.
*
* @param aliasName an alias of the named font family.
* @param referName a referring font family name.
* @param weight a font weight of the referring font family.
* @param name alias for the font family.
* @param original original font family name.
* @param weight font weight of the original font family.
* @hide Only system server can create this instance and passed via IPC.
*/
public Alias(@NonNull String aliasName, @NonNull String referName,
public Alias(@NonNull String name, @NonNull String original,
@IntRange(from = 0, to = 1000) int weight) {
mAliasName = aliasName;
mReferName = referName;
mName = name;
mOriginal = original;
mWeight = weight;
}
/**
* An alias of the named font family.
*
* @return an alias of the named font family.
* Alias for the font family
*/
public @NonNull String getAliasName() {
return mAliasName;
public @NonNull String getName() {
return mName;
}
/**
* A name of font family referring from {@link #getAliasName()}
*
* @return a referring font family name.
* The name of the original font family.
*/
public @NonNull String getReferName() {
return mReferName;
public @NonNull String getOriginal() {
return mOriginal;
}
/**
@@ -266,17 +340,47 @@ public final class FontConfig {
public @IntRange(from = 0, to = 1000) int getWeight() {
return mWeight;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString8(mName);
dest.writeString8(mOriginal);
dest.writeInt(mWeight);
}
public static final @NonNull Creator<Alias> CREATOR = new Creator<Alias>() {
@Override
public Alias createFromParcel(Parcel source) {
String alias = source.readString8();
String referName = source.readString8();
int weight = source.readInt();
return new Alias(alias, referName, weight);
}
@Override
public Alias[] newArray(int size) {
return new Alias[size];
}
};
}
/**
* A class represents single font family entry in system font configuration.
* Represents a font family in the system font configuration.
*
* <p>
* A font family is a bundle of fonts for drawing text in various styles.
* For example, regular style font and bold style font can be bundled into a single font family,
* then system will select the correct style font from family for drawing.
* A {@link FontFamily} is a list of {@link Font}s for drawing text in various styles such as
* weight, slant.
*
* For example, a {@link FontFamily} can include the regular and bold styles of a {@link Font}.
*
* @see android.graphics.fonts.FontFamily
*/
public static final class Family {
public static final class FontFamily implements Parcelable {
private final @NonNull List<Font> mFonts;
private final @Nullable String mName;
private final @Nullable LocaleList mLocaleList;
@@ -319,7 +423,7 @@ public final class FontConfig {
*
* @hide Only system server can create this instance and passed via IPC.
*/
public Family(@NonNull List<Font> fonts, @Nullable String name,
public FontFamily(@NonNull List<Font> fonts, @Nullable String name,
@Nullable LocaleList localeList, @Variant int variant) {
mFonts = fonts;
mName = name;
@@ -328,7 +432,7 @@ public final class FontConfig {
}
/**
* Returns a list of font files in this family.
* Returns the list of {@link Font}s in this {@link FontFamily}.
*
* @return a list of font files.
*/
@@ -337,61 +441,77 @@ public final class FontConfig {
}
/**
* Returns a family name if this family defines a new fallback.
* Returns the name of the {@link FontFamily}.
*
* @return non-null if a family name is associated. Otherwise null.
* When the name of a {@link FontFamily} is not null, this name is used to create a new
* {@code Fallback List}, and that {@code Fallback List}. Fallback List is the
* main building block for a {@link android.graphics.Typeface}.
*
* For example, if the {@link FontFamily} has the name "serif", then the system will create
* a “serif” {@code Fallback List} and it can be used by creating a Typeface via
* {@code Typeface.create("serif", Typeface.NORMAL);}
*
* When the name of a {@link FontFamily} is null, it will be appended to all of the
* {@code Fallback List}s.
*/
public @Nullable String getFallbackName() {
public @Nullable String getName() {
return mName;
}
/**
* Returns a locale list if associated.
* Returns the locale list if available.
*
* @return non-null if a locale list is associated. Otherwise null.
* The locale list will be used for deciding which font family should be used in fallback
* list.
*
* @return non-null if a locale list is available. Otherwise null.
*/
public @NonNull LocaleList getLocaleList() {
return mLocaleList;
}
/**
* Returns a text height variant.
*
* @return text height variant.
* Returns the text height variant.
*/
public @Variant int getTextHeightVariant() {
return mVariant;
}
/**
* Returns a family variant associated.
*
* @return a family variant.
* @deprecated Use getTextHeightVariant instead.
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public @Variant int getVariant() {
return mVariant;
}
/**
* Returns a family name if associated.
*
* @return non-null if a family name is associated. Otherwise null.
* @deprecated Use getFallbackName instead.
* @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public @Nullable String getName() {
return mName;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelableList(mFonts, flags);
dest.writeString8(mName);
dest.writeString8(mLocaleList.toLanguageTags());
dest.writeInt(mVariant);
}
public static final @NonNull Creator<FontFamily> CREATOR = new Creator<FontFamily>() {
@Override
public FontFamily createFromParcel(Parcel source) {
List<Font> fonts = source.readParcelableList(
new ArrayList<>(), Font.class.getClassLoader());
String name = source.readString8();
String langTags = source.readString8();
int variant = source.readInt();
return new FontFamily(fonts, name, LocaleList.forLanguageTags(langTags), variant);
}
@Override
public FontFamily[] newArray(int size) {
return new FontFamily[size];
}
};
/**
* Returns the list of fonts included in this family.
* @deprecated Use getFontFiles instead
* @deprecated Use getFontList instead
* @hide
*/
@Deprecated

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.graphics.fonts;
import android.text.FontConfig;
import android.graphics.fonts.SystemFontState;
/**
* System private interface for talking with
* {@link com.android.server.graphics.fonts.FontManagerService}.
* @hide
*/
interface IFontManager {
FontConfig getFontConfig();
}

View File

@@ -100,10 +100,10 @@ public class FontListParser {
@NonNull FontCustomizationParser.Result customization,
@Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
List<FontConfig.Family> families = new ArrayList<>();
List<FontConfig.FontFamily> families = new ArrayList<>();
List<FontConfig.Alias> aliases = new ArrayList<>(customization.getAdditionalAliases());
Map<String, FontConfig.Family> oemNamedFamilies =
Map<String, FontConfig.FontFamily> oemNamedFamilies =
customization.getAdditionalNamedFamilies();
parser.require(XmlPullParser.START_TAG, null, "familyset");
@@ -111,8 +111,8 @@ public class FontListParser {
if (parser.getEventType() != XmlPullParser.START_TAG) continue;
String tag = parser.getName();
if (tag.equals("family")) {
FontConfig.Family family = readFamily(parser, fontDir, updatableFontMap);
String name = family.getFallbackName();
FontConfig.FontFamily family = readFamily(parser, fontDir, updatableFontMap);
String name = family.getName();
if (name == null || !oemNamedFamilies.containsKey(name)) {
// The OEM customization overrides system named family. Skip if OEM
// customization XML defines the same named family.
@@ -132,7 +132,7 @@ public class FontListParser {
/**
* Read family tag in fonts.xml or oem_customization.xml
*/
public static FontConfig.Family readFamily(XmlPullParser parser, String fontDir,
public static FontConfig.FontFamily readFamily(XmlPullParser parser, String fontDir,
@Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
final String name = parser.getAttributeValue(null, "name");
@@ -148,15 +148,15 @@ public class FontListParser {
skip(parser);
}
}
int intVariant = FontConfig.Family.VARIANT_DEFAULT;
int intVariant = FontConfig.FontFamily.VARIANT_DEFAULT;
if (variant != null) {
if (variant.equals("compact")) {
intVariant = FontConfig.Family.VARIANT_COMPACT;
intVariant = FontConfig.FontFamily.VARIANT_COMPACT;
} else if (variant.equals("elegant")) {
intVariant = FontConfig.Family.VARIANT_ELEGANT;
intVariant = FontConfig.FontFamily.VARIANT_ELEGANT;
}
}
return new FontConfig.Family(fonts, name, LocaleList.forLanguageTags(lang), intVariant);
return new FontConfig.FontFamily(fonts, name, LocaleList.forLanguageTags(lang), intVariant);
}
/** Matches leading and trailing XML whitespace. */

View File

@@ -1151,10 +1151,10 @@ public class Typeface {
for (int i = 0; i < aliases.size(); ++i) {
final FontConfig.Alias alias = aliases.get(i);
if (outSystemFontMap.containsKey(alias.getAliasName())) {
if (outSystemFontMap.containsKey(alias.getName())) {
continue; // If alias and named family are conflict, use named family.
}
final Typeface base = outSystemFontMap.get(alias.getReferName());
final Typeface base = outSystemFontMap.get(alias.getOriginal());
if (base == null) {
// The missing target is a valid thing, some configuration don't have font files,
// e.g. wear devices. Just skip this alias.
@@ -1163,7 +1163,7 @@ public class Typeface {
final int weight = alias.getWeight();
final Typeface newFace = weight == 400 ? base :
new Typeface(nativeCreateWeightAlias(base.native_instance, weight));
outSystemFontMap.put(alias.getAliasName(), newFace);
outSystemFontMap.put(alias.getName(), newFace);
}
}

View File

@@ -17,7 +17,7 @@
package android.graphics.fonts;
import static android.text.FontConfig.Alias;
import static android.text.FontConfig.Family;
import static android.text.FontConfig.FontFamily;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -46,7 +46,7 @@ public class FontCustomizationParser {
* Represents a customization XML
*/
public static class Result {
private final Map<String, Family> mAdditionalNamedFamilies;
private final Map<String, FontFamily> mAdditionalNamedFamilies;
private final List<Alias> mAdditionalAliases;
public Result() {
@@ -54,13 +54,13 @@ public class FontCustomizationParser {
mAdditionalAliases = Collections.emptyList();
}
public Result(Map<String, Family> additionalNamedFamilies,
public Result(Map<String, FontFamily> additionalNamedFamilies,
List<Alias> additionalAliases) {
mAdditionalNamedFamilies = additionalNamedFamilies;
mAdditionalAliases = additionalAliases;
}
public Map<String, Family> getAdditionalNamedFamilies() {
public Map<String, FontFamily> getAdditionalNamedFamilies() {
return mAdditionalNamedFamilies;
}
@@ -85,11 +85,11 @@ public class FontCustomizationParser {
return readFamilies(parser, fontDir, updatableFontMap);
}
private static Map<String, Family> validateAndTransformToMap(List<Family> families) {
HashMap<String, Family> namedFamily = new HashMap<>();
private static Map<String, FontFamily> validateAndTransformToMap(List<FontFamily> families) {
HashMap<String, FontFamily> namedFamily = new HashMap<>();
for (int i = 0; i < families.size(); ++i) {
final Family family = families.get(i);
final String name = family.getFallbackName();
final FontFamily family = families.get(i);
final String name = family.getName();
if (name == null) {
throw new IllegalArgumentException("new-named-family requires name attribute");
}
@@ -106,7 +106,7 @@ public class FontCustomizationParser {
@NonNull String fontDir,
@Nullable Map<String, File> updatableFontMap
) throws XmlPullParserException, IOException {
List<Family> families = new ArrayList<>();
List<FontFamily> families = new ArrayList<>();
List<Alias> aliases = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, null, "fonts-modification");
while (parser.next() != XmlPullParser.END_TAG) {
@@ -126,7 +126,7 @@ public class FontCustomizationParser {
private static void readFamily(
@NonNull XmlPullParser parser,
@NonNull String fontDir,
@NonNull List<Family> out,
@NonNull List<FontFamily> out,
@Nullable Map<String, File> updatableFontMap)
throws XmlPullParserException, IOException {
final String customizationType = parser.getAttributeValue(null, "customizationType");

View File

@@ -109,7 +109,7 @@ public final class FontFamily {
* @return a font family
*/
public @NonNull FontFamily build() {
return build("", FontConfig.Family.VARIANT_DEFAULT, true /* isCustomFallback */);
return build("", FontConfig.FontFamily.VARIANT_DEFAULT, true /* isCustomFallback */);
}
/** @hide */

View File

@@ -117,12 +117,12 @@ public final class SystemFonts {
}
}
private static void pushFamilyToFallback(@NonNull FontConfig.Family xmlFamily,
private static void pushFamilyToFallback(@NonNull FontConfig.FontFamily xmlFamily,
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackMap,
@NonNull Map<String, ByteBuffer> cache) {
final String languageTags = xmlFamily.getLocaleList().toLanguageTags();
final int variant = xmlFamily.getTextHeightVariant();
final int variant = xmlFamily.getVariant();
final ArrayList<FontConfig.Font> defaultFonts = new ArrayList<>();
final ArrayMap<String, ArrayList<FontConfig.Font>> specificFallbackFonts =
@@ -130,7 +130,7 @@ public final class SystemFonts {
// Collect default fallback and specific fallback fonts.
for (final FontConfig.Font font : xmlFamily.getFonts()) {
final String fallbackName = font.getFallback();
final String fallbackName = font.getFontFamilyName();
if (fallbackName == null) {
defaultFonts.add(font);
} else {
@@ -144,14 +144,14 @@ public final class SystemFonts {
}
final FontFamily defaultFamily = defaultFonts.isEmpty() ? null : createFontFamily(
xmlFamily.getFallbackName(), defaultFonts, languageTags, variant, cache);
xmlFamily.getName(), defaultFonts, languageTags, variant, cache);
// Insert family into fallback map.
for (int i = 0; i < fallbackMap.size(); i++) {
String name = fallbackMap.keyAt(i);
final ArrayList<FontConfig.Font> fallback = specificFallbackFonts.get(name);
if (fallback == null) {
String familyName = xmlFamily.getFallbackName();
String familyName = xmlFamily.getName();
if (defaultFamily != null
// do not add myself to the fallback chain.
&& (familyName == null || !familyName.equals(name))) {
@@ -159,7 +159,7 @@ public final class SystemFonts {
}
} else {
final FontFamily family = createFontFamily(
xmlFamily.getFallbackName(), fallback, languageTags, variant, cache);
xmlFamily.getName(), fallback, languageTags, variant, cache);
if (family != null) {
fallbackMap.valueAt(i).add(family);
} else if (defaultFamily != null) {
@@ -174,7 +174,7 @@ public final class SystemFonts {
private static @Nullable FontFamily createFontFamily(@NonNull String familyName,
@NonNull List<FontConfig.Font> fonts,
@NonNull String languageTags,
@FontConfig.Family.Variant int variant,
@FontConfig.FontFamily.Variant int variant,
@NonNull Map<String, ByteBuffer> cache) {
if (fonts.size() == 0) {
return null;
@@ -183,7 +183,7 @@ public final class SystemFonts {
FontFamily.Builder b = null;
for (int i = 0; i < fonts.size(); i++) {
final FontConfig.Font fontConfig = fonts.get(i);
final String fullPath = fontConfig.getFilePath().getAbsolutePath();
final String fullPath = fontConfig.getFile().getAbsolutePath();
ByteBuffer buffer = cache.get(fullPath);
if (buffer == null) {
if (cache.containsKey(fullPath)) {
@@ -201,7 +201,7 @@ public final class SystemFonts {
font = new Font.Builder(buffer, new File(fullPath), languageTags)
.setWeight(fontConfig.getStyle().getWeight())
.setSlant(fontConfig.getStyle().getSlant())
.setTtcIndex(fontConfig.getIndex())
.setTtcIndex(fontConfig.getTtcIndex())
.setFontVariationSettings(fontConfig.getFontVariationSettings())
.build();
} catch (IOException e) {
@@ -217,13 +217,13 @@ public final class SystemFonts {
return b == null ? null : b.build(languageTags, variant, false /* isCustomFallback */);
}
private static void appendNamedFamily(@NonNull FontConfig.Family xmlFamily,
private static void appendNamedFamily(@NonNull FontConfig.FontFamily xmlFamily,
@NonNull HashMap<String, ByteBuffer> bufferCache,
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap) {
final String familyName = xmlFamily.getFallbackName();
final String familyName = xmlFamily.getName();
final FontFamily family = createFontFamily(
familyName, xmlFamily.getFontList(),
xmlFamily.getLocaleList().toLanguageTags(), xmlFamily.getTextHeightVariant(),
xmlFamily.getLocaleList().toLanguageTags(), xmlFamily.getVariant(),
bufferCache);
if (family == null) {
return;
@@ -281,12 +281,12 @@ public final class SystemFonts {
public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig) {
final Map<String, FontFamily[]> fallbackMap = new HashMap<>();
final HashMap<String, ByteBuffer> bufferCache = new HashMap<>();
final List<FontConfig.Family> xmlFamilies = fontConfig.getFontFamilies();
final List<FontConfig.FontFamily> xmlFamilies = fontConfig.getFontFamilies();
final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>();
// First traverse families which have a 'name' attribute to create fallback map.
for (final FontConfig.Family xmlFamily : xmlFamilies) {
final String familyName = xmlFamily.getFallbackName();
for (final FontConfig.FontFamily xmlFamily : xmlFamilies) {
final String familyName = xmlFamily.getName();
if (familyName == null) {
continue;
}
@@ -295,10 +295,10 @@ public final class SystemFonts {
// Then, add fallback fonts to the each fallback map.
for (int i = 0; i < xmlFamilies.size(); i++) {
final FontConfig.Family xmlFamily = xmlFamilies.get(i);
final FontConfig.FontFamily xmlFamily = xmlFamilies.get(i);
// The first family (usually the sans-serif family) is always placed immediately
// after the primary family in the fallback.
if (i == 0 || xmlFamily.getFallbackName() == null) {
if (i == 0 || xmlFamily.getName() == null) {
pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache);
}
}

View File

@@ -23,12 +23,17 @@ import android.graphics.Typeface;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.FontFileUtil;
import android.graphics.fonts.SystemFonts;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.text.FontConfig;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.graphics.fonts.IFontManager;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.security.FileIntegrityService;
@@ -38,6 +43,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.NioUtils;
import java.nio.channels.FileChannel;
@@ -46,21 +52,25 @@ import java.util.Map;
/** A service for managing system fonts. */
// TODO(b/173619554): Add API to update fonts.
public final class FontManagerService {
public final class FontManagerService extends IFontManager.Stub {
private static final String TAG = "FontManagerService";
// TODO: make this a DeviceConfig flag.
private static final boolean ENABLE_FONT_UPDATES = false;
private static final String FONT_FILES_DIR = "/data/fonts/files";
@Override
public FontConfig getFontConfig() throws RemoteException {
return getCurrentFontSettings().getSystemFontConfig();
}
/** Class to manage FontManagerService's lifecycle. */
public static final class Lifecycle extends SystemService {
private final FontManagerService mService;
public Lifecycle(@NonNull Context context) {
super(context);
mService = new FontManagerService();
mService = new FontManagerService(context);
}
@Override
@@ -76,10 +86,11 @@ public final class FontManagerService {
return mService.getCurrentFontSettings().getSerializedSystemFontMap();
}
});
publishBinderService(Context.FONT_SERVICE, mService);
}
}
private static class OtfFontFileParser implements UpdatableFontDir.FontFileParser {
/* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser {
@Override
public String getPostScriptName(File file) throws IOException {
ByteBuffer buffer = mmap(file);
@@ -133,7 +144,8 @@ public final class FontManagerService {
@Nullable
private SystemFontSettings mCurrentFontSettings = null;
private FontManagerService() {
private FontManagerService(Context context) {
mContext = context;
mUpdatableFontDir = createUpdatableFontDir();
}
@@ -148,8 +160,16 @@ public final class FontManagerService {
new OtfFontFileParser(), new FsverityUtilImpl());
}
@NonNull
private SystemFontSettings getCurrentFontSettings() {
private final Context mContext;
@NonNull
public Context getContext() {
return mContext;
}
@NonNull /* package */ SystemFontSettings getCurrentFontSettings() {
synchronized (FontManagerService.this) {
if (mCurrentFontSettings == null) {
mCurrentFontSettings = SystemFontSettings.create(mUpdatableFontDir);
@@ -174,7 +194,22 @@ public final class FontManagerService {
}
}
private static class SystemFontSettings {
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
new FontManagerShellCommand(this).dumpAll(new IndentingPrintWriter(writer, " "));
}
@Override
public int handleShellCommand(@NonNull ParcelFileDescriptor in,
@NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
@NonNull String[] args) {
return new FontManagerShellCommand(this).exec(this,
in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
}
/* package */ static class SystemFontSettings {
private final @NonNull SharedMemory mSerializedSystemFontMap;
private final @NonNull FontConfig mSystemFontConfig;
private final @NonNull Map<String, FontFamily[]> mSystemFallbackMap;

View File

@@ -0,0 +1,269 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.graphics.fonts;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.fonts.Font;
import android.graphics.fonts.FontFamily;
import android.graphics.fonts.FontVariationAxis;
import android.os.ShellCommand;
import android.text.FontConfig;
import android.util.IndentingPrintWriter;
import com.android.internal.util.DumpUtils;
import java.io.File;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
/**
* A shell command implementation of font service.
*/
public class FontManagerShellCommand extends ShellCommand {
private static final String TAG = "FontManagerShellCommand";
@NonNull private final FontManagerService mService;
FontManagerShellCommand(@NonNull FontManagerService service) {
mService = service;
}
@Override
public int onCommand(String cmd) {
return execCommand(this, cmd);
}
@Override
public void onHelp() {
dumpHelp(getOutPrintWriter());
}
/* package */ void dumpAll(@NonNull IndentingPrintWriter w) {
final FontManagerService.SystemFontSettings settings = mService.getCurrentFontSettings();
dumpFontConfig(w, settings.getSystemFontConfig());
}
private void dumpSingleFontConfig(
@NonNull IndentingPrintWriter w,
@NonNull FontConfig.Font font
) {
StringBuilder sb = new StringBuilder();
sb.append("style = ");
sb.append(font.getStyle());
sb.append(", path = ");
sb.append(font.getFile().getAbsolutePath());
if (font.getTtcIndex() != 0) {
sb.append(", index = ");
sb.append(font.getTtcIndex());
}
if (!font.getFontVariationSettings().isEmpty()) {
sb.append(", axes = ");
sb.append(font.getFontVariationSettings());
}
if (font.getFontFamilyName() != null) {
sb.append(", fallback = ");
sb.append(font.getFontFamilyName());
}
w.println(sb.toString());
if (font.getOriginalFile() != null) {
w.increaseIndent();
w.println("Font is updated from " + font.getOriginalFile());
w.decreaseIndent();
}
}
private void dumpFontConfig(
@NonNull IndentingPrintWriter w,
@NonNull FontConfig fontConfig
) {
// Dump named font family first.
List<FontConfig.FontFamily> families = fontConfig.getFontFamilies();
w.println("Named Font Families");
w.increaseIndent();
for (int i = 0; i < families.size(); ++i) {
final FontConfig.FontFamily family = families.get(i);
// Here, only dump the named family only.
if (family.getName() == null) continue;
w.println("Named Family (" + family.getName() + ")");
final List<FontConfig.Font> fonts = family.getFontList();
w.increaseIndent();
for (int j = 0; j < fonts.size(); ++j) {
dumpSingleFontConfig(w, fonts.get(j));
}
w.decreaseIndent();
}
w.decreaseIndent();
// Dump Fallback fonts.
w.println("Dump Fallback Families");
w.increaseIndent();
int c = 0;
for (int i = 0; i < families.size(); ++i) {
final FontConfig.FontFamily family = families.get(i);
// Skip named font family since they are already dumped.
if (family.getName() != null) continue;
StringBuilder sb = new StringBuilder("Fallback Family [");
sb.append(c++);
sb.append("]: lang=\"");
sb.append(family.getLocaleList().toLanguageTags());
if (family.getVariant() != FontConfig.FontFamily.VARIANT_DEFAULT) {
sb.append("\", variant=");
switch (family.getVariant()) {
case FontConfig.FontFamily.VARIANT_COMPACT:
sb.append("Compact");
break;
case FontConfig.FontFamily.VARIANT_ELEGANT:
sb.append("Elegant");
break;
default:
sb.append("Unknown");
break;
}
}
w.println(sb.toString());
final List<FontConfig.Font> fonts = family.getFontList();
w.increaseIndent();
for (int j = 0; j < fonts.size(); ++j) {
dumpSingleFontConfig(w, fonts.get(j));
}
w.decreaseIndent();
}
w.decreaseIndent();
// Dump aliases
w.println("Dump Family Aliases");
w.increaseIndent();
List<FontConfig.Alias> aliases = fontConfig.getAliases();
for (int i = 0; i < aliases.size(); ++i) {
final FontConfig.Alias alias = aliases.get(i);
w.println("alias = " + alias.getName() + ", reference = " + alias.getOriginal()
+ ", width = " + alias.getWeight());
}
w.decreaseIndent();
}
private static void dumpHelp(@NonNull PrintWriter w) {
w.println("Font service (font) commands");
w.println("help");
w.println(" Print this help text.");
w.println();
w.println("dump [family name]");
w.println(" Dump all font files in the specified family name.");
w.println(" Dump current system font configuration if no family name was specified.");
}
private void dumpFallback(@NonNull IndentingPrintWriter writer,
@NonNull FontFamily[] families) {
for (FontFamily family : families) {
dumpFamily(writer, family);
}
}
private void dumpFamily(@NonNull IndentingPrintWriter writer, @NonNull FontFamily family) {
StringBuilder sb = new StringBuilder("Family:");
if (family.getLangTags() != null) {
sb.append(" langTag = ");
sb.append(family.getLangTags());
}
if (family.getVariant() != FontConfig.FontFamily.VARIANT_DEFAULT) {
sb.append(" variant = ");
switch (family.getVariant()) {
case FontConfig.FontFamily.VARIANT_COMPACT:
sb.append("Compact");
break;
case FontConfig.FontFamily.VARIANT_ELEGANT:
sb.append("Elegant");
break;
default:
sb.append("UNKNOWN");
break;
}
}
writer.println(sb.toString());
for (int i = 0; i < family.getSize(); ++i) {
writer.increaseIndent();
try {
dumpFont(writer, family.getFont(i));
} finally {
writer.decreaseIndent();
}
}
}
private void dumpFont(@NonNull IndentingPrintWriter writer, @NonNull Font font) {
File file = font.getFile();
StringBuilder sb = new StringBuilder();
sb.append(font.getStyle());
sb.append(", path = ");
sb.append(file == null ? "[Not a file]" : file.getAbsolutePath());
if (font.getTtcIndex() != 0) {
sb.append(", index = ");
sb.append(font.getTtcIndex());
}
FontVariationAxis[] axes = font.getAxes();
if (axes != null && axes.length != 0) {
sb.append(", axes = \"");
sb.append(FontVariationAxis.toFontVariationSettings(axes));
sb.append("\"");
}
writer.println(sb.toString());
}
private int execCommand(@NonNull ShellCommand shell, @NonNull String cmd) {
final Context ctx = mService.getContext();
if (cmd == null) {
return shell.handleDefaultCommands(null);
}
final FontManagerService.SystemFontSettings settings = mService.getCurrentFontSettings();
switch (cmd) {
case "dump":
if (!DumpUtils.checkDumpPermission(ctx, TAG, shell.getErrPrintWriter())) {
return 1;
}
final IndentingPrintWriter writer =
new IndentingPrintWriter(shell.getOutPrintWriter(), " ");
String nextArg = shell.getNextArg();
if (nextArg == null) {
dumpFontConfig(writer, settings.getSystemFontConfig());
} else {
final Map<String, FontFamily[]> fallbackMap = settings.getSystemFallbackMap();
FontFamily[] families = fallbackMap.get(nextArg);
if (families == null) {
writer.println("Font Family \"" + nextArg + "\" not found");
} else {
dumpFallback(writer, families);
}
}
return 0;
default:
shell.handleDefaultCommands(cmd);
}
return 0;
}
}