Implement custom fonts

Starting in Android 15, variable fonts are rendered at runtime with better efficiency and granularity. With this update, vendors must add new variable font configurations to font_fallback.xml instead of fonts.xml, as fonts.xml is being deprecated. See Support for variable fonts for more information.

In Android 11 and lower, updating device-installed font files in AOSP (in the /system/fonts partition) or the vendor partitions (in the /product/fonts or /system/fonts partitions) requires a system update from the OEM. This requirement has a significant impact on emoji compatibility. In Android 12 you can use the FontManager system service to manage installed font files and update device-installed font files without a system update.

Android 12 features three process interactions; FontManagerService, Font Updater, and Application.

The FontManagerService is the central management system in the system server. FontManagerService stores the latest per-user system font settings.

The FontUpdater is a pluggable font updater that’s trusted by a signature|privileged permission check. The FontUpdater communicates with the FontManagerService to get, install, remove, or update current system font settings. The FontUpdater can pass new font file contents by inter-process communications (IPC) mechanisms. The FontManagerService saves the contents to a world-readable storage location, such as in the /data/fonts files. This storage is guarded. It can be written by the FontManagerService only, by SELinux policy.

When the Application class launches, it passes the system font settings as arguments of the bindApplication method; then it initializes the font settings for use by the app process.

Support for variable fonts

Starting in Android 15, variable font configurations are specified in font_fallback.xml using the following format:

<family lang="und-Ethi" supportedAxes="wght,ital">
    <font>NotoSansEthiopic-VF.ttf</font>
</family>

In this format, a variable font has all of the attributes of a static font with an additional supportedAxes attribute. A supportedAxes attribute is a comma-separated list of supported axis tags. With Android 15, only the wght and ital axes can be specified.

If the supportedAxes attribute isn't specified, the font node works as a static font of a single instance of a variable font specified with axis children.

If the supportedAxes attribute is specified, the system dynamically creates a font instance for the given weight and style value at runtime.

Developers can use the android.graphics.fonts.SystemFonts#getAvailableFonts Java API or the ASystemFontIterator_open NDK API to get a list of system-installed font files. For information on developer APIs that support this update, see Improved OpenType Variable Font API and buildVariableFamily.

Customize fonts

Some OEMs install or replace font files in AOSP to show their brands. Android 12 supports this functionality, but adds requirements to keep emoji fonts updated in devices. OEMs that don’t modify or update emoji font files don't need to use this feature.

Google updates the font files, especially the NotoColorEmoji files through GMS Core, so don’t modify or remove the NotoColorEmoji.ttf file from the /system partition, and don't remove it from /frameworks/base/data/fonts/fonts.xml. Note the following three ways that you can customize your fonts:

  1. Replace the NotoColorEmoji.ttf file with an OEM-branded emoji font.
  2. Modify the NotoColorEmoji.ttf file for your local market needs.
  3. Replace or modify other font files.

If you aren't modifying emoji fonts in AOSP, you don't need to take action. If you want to customize emoji fonts, use the instructions in the following sections.

Replace NotoColorEmoji.ttf with OEM-branded emoji fonts

To replace the NotoColorEmoji.ttf file with your OEM-branded emoji fonts file, put the emoji font just before the font fallback chain:

  1. Place your own font, called OEMCustomEmoji.ttf, in the /system partition.
  2. Modify /frameworks/base/data/fonts/fonts.xml (and /frameworks/base/data/fonts/font-fallback.xml in Android 15 and higher) as in the following code:

    <family lang="ko">
    <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
    </family>
    <!-- ADD FOLLOWING LINE -->
    <family lang="und-Zsye">
       <font weight="400" style="normal">OEMCustomEmoji.ttf</font>
    </family>
    <!-- END OF MODIFICATION -->
    <family lang="und-Zsye">
       <font weight="400" style="normal">NotoColorEmoji.ttf</font>
    </family>
    <family lang="und-Zsym">
       <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
    </family>
    

Modify NotoColorEmoji.ttf for local market needs

Follow these steps to customize for your local market needs:

  1. Create your own NotoColorEmoji file with a different name; for example, name it Modified\_NotoColorEmoji.ttf.
  2. Place it before the original NotoColorEmoji.ttf file.

After you perform step 2, the modified glyph supported by Modified\NotoColorEmoji.ttf shows instead of the original NotoColorEmoji.ttf. Google recommends the following:

  • Only have the necessary glyph in this font.
  • Delegate unmodified glyphs to the original NotoColorEmoji.ttf file so that your devices receive any design fixes made in future emoji releases.

Remove glyphs: To remove glyphs from the NotoColorEmoji.ttf file, follow steps 1 and 2, and specify glyph ID = 0 in your cmap.

Use a regional flag: If the target glyph is a regional flag, specify the glyph ID as an unknown country code. (Use country code = "ZZ".)

Make a tofu glyph: You can explicitly specify a tofu glyph ID if you want to use one. When you specify glyphID = 0, the related app interprets that as “glyph is not available”. For example, when you use this attribute, the Paint#hasGlyph app returns false.

Replace or modify other font files

To replace or modify other fonts, the customization is similar to that for modifying the TTF files for local market needs. Unknown font files that are updated in the AOSP at runtime are ignored, and aren't updated. Google ignores unknown fonts in your device. This includes font files that were modified from the original fonts in AOSP.

Although font updates are done by Google in GMS Core, the general font update mechanism is open to all OEMs. OEMs can install additional font updaters using the steps in Meeting prerequisites, Signing font files, and Making runtime font updates.

Meet prerequisites

The font update mechanism uses the fs-verity Linux kernel feature. Verify that your device is fs-verity compliant and include the certificate in your device.

Sign font files

Since font files are risky resources, they must be verified with trusted keys. Carefully review all font files that are to be updated, and sign with your private key. The signature must befs-verity compatible.

Make runtime font updates

The FontManager system app performs font updates. The FontManager app provides the latest installed system font status and the ability to update font files with signatures. To call update apps, add the UPDATE_FONT signature|privileged permission to your app allowlist, and to your manifest.

Provide the UPDATE_FONT signature|privileged permission to your app’s updater function.