Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 789c4b4b authored by Diego Perez's avatar Diego Perez
Browse files

Add dynamic font support

This CL allows loading fonts from resources.

Test: Added new fonts test
Change-Id: Ic82239121cc3f78f2a22b22de42e54575c1f2d98
parent 349a8aef
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import com.android.resources.ResourceType;
import android.annotation.Nullable;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -696,6 +697,22 @@ public final class BridgeTypedArray extends TypedArray {
    }


    /**
     * Retrieve the Typeface for the attribute at <var>index</var>.
     * @param index Index of attribute to retrieve.
     *
     * @return Typeface for the attribute, or null if not defined.
     */
    @Override
    public Typeface getFont(int index) {
        if (!hasValue(index)) {
            return null;
        }

        ResourceValue value = mResourceData[index];
        return ResourceHelper.getFont(value, mContext, mTheme);
    }

    /**
     * Retrieve the CharSequence[] for the attribute at <var>index</var>.
     * This gets the resource ID of the selected attribute, and uses
+30 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.icu.text.PluralRules;
import android.util.AttributeSet;
@@ -778,6 +779,35 @@ public class Resources_Delegate {
        return getQuantityString(resources, id, quantity);
    }

    @LayoutlibDelegate
    static Typeface getFont(Resources resources, int id) throws
            NotFoundException {
        Pair<String, ResourceValue> value = getResourceValue(resources, id, mPlatformResourceFlag);
        if (value != null) {
            return ResourceHelper.getFont(value.getSecond(), resources.mContext, null);
        }

        throwException(resources, id);

        // this is not used since the method above always throws
        return null;
    }

    @LayoutlibDelegate
    static Typeface getFont(Resources resources, TypedValue outValue, int id) throws
            NotFoundException {
        Resources_Delegate.getValue(resources, id, outValue, true);
        if (outValue.string != null) {
            return ResourceHelper.getFont(outValue.string.toString(), resources.mContext, null,
                    mPlatformResourceFlag[0]);
        }

        throwException(resources, id);

        // this is not used since the method above always throws
        return null;
    }

    @LayoutlibDelegate
    static void getValue(Resources resources, int id, TypedValue outValue, boolean resolveRefs)
            throws NotFoundException {
+3 −1
Original line number Diff line number Diff line
@@ -344,7 +344,9 @@ public class FontFamily_Delegate {
                    ffd.addFont(fontInfo);
                    return true;
                }
                fontStream = assetRepository.openAsset(path, AssetManager.ACCESS_STREAMING);
                fontStream = isAsset ?
                        assetRepository.openAsset(path, AssetManager.ACCESS_STREAMING) :
                        assetRepository.openNonAsset(cookie, path, AssetManager.ACCESS_STREAMING);
                if (fontStream == null) {
                    Bridge.getLog().error(LayoutLog.TAG_MISSING_ASSET, "Asset not found: " + path,
                            path);
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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;

import android.annotation.NonNull;

/**
 * Class allowing access to package-protected methods/fields.
 */
public class Typeface_Accessor {
    public static boolean isSystemFont(@NonNull String fontName) {
        return Typeface.sSystemFontMap.containsKey(fontName);
    }
}
+87 −0
Original line number Diff line number Diff line
@@ -38,16 +38,20 @@ import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.content.res.ComplexColor;
import android.content.res.ComplexColor_Accessor;
import android.content.res.FontResourcesParser;
import android.content.res.GradientColor;
import android.content.res.Resources.Theme;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
import android.graphics.NinePatch_Delegate;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.Typeface_Accessor;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.text.FontConfig;
import android.util.TypedValue;

import java.io.File;
@@ -367,6 +371,89 @@ public final class ResourceHelper {
        return null;
    }

    /**
     * Returns a {@link Typeface} given a font name. The font name, can be a system font family
     * (like sans-serif) or a full path if the font is to be loaded from resources.
     */
    public static Typeface getFont(String fontName, BridgeContext context, Theme theme, boolean
            isFramework) {
        if (fontName == null) {
            return null;
        }

        if (Typeface_Accessor.isSystemFont(fontName)) {
            // Shortcut for the case where we are asking for a system font name. Those are not
            // loaded using external resources.
            return null;
        }

        // Check if this is an asset that we've already loaded dynamically
        Typeface typeface = Typeface.findFromCache(context.getAssets(), fontName);
        if (typeface != null) {
            return typeface;
        }

        String lowerCaseValue = fontName.toLowerCase();
        if (lowerCaseValue.endsWith(".xml")) {
            // create a block parser for the file
            Boolean psiParserSupport = context.getLayoutlibCallback().getFlag(
                    RenderParamsFlags.FLAG_KEY_XML_FILE_PARSER_SUPPORT);
            XmlPullParser parser = null;
            if (psiParserSupport != null && psiParserSupport) {
                parser = context.getLayoutlibCallback().getXmlFileParser(fontName);
            }
            else {
                File f = new File(fontName);
                if (f.isFile()) {
                    try {
                        parser = ParserFactory.create(f);
                    } catch (XmlPullParserException | FileNotFoundException e) {
                        // this is an error and not warning since the file existence is checked before
                        // attempting to parse it.
                        Bridge.getLog().error(null, "Failed to parse file " + fontName,
                                e, null /*data*/);
                    }
                }
            }

            if (parser != null) {
                BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
                        parser, context, isFramework);
                try {
                    FontConfig config = FontResourcesParser.parse(blockParser, context
                            .getResources());
                    typeface = Typeface.createFromResources(config, context.getAssets(),
                            fontName);
                } catch (XmlPullParserException | IOException e) {
                    Bridge.getLog().error(null, "Failed to parse file " + fontName,
                            e, null /*data*/);
                } finally {
                    blockParser.ensurePopped();
                }
            } else {
                Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                        String.format("File %s does not exist (or is not a file)", fontName),
                        null /*data*/);
            }
        } else {
            typeface = Typeface.createFromResources(context.getAssets(), fontName, 0);
        }

        return typeface;
    }

    /**
     * Returns a {@link Typeface} given a font name. The font name, can be a system font family
     * (like sans-serif) or a full path if the font is to be loaded from resources.
     */
    public static Typeface getFont(ResourceValue value, BridgeContext context, Theme theme) {
        if (value == null) {
            return null;
        }

        return getFont(value.getValue(), context, theme, value.isFramework());
    }

    private static Drawable getNinePatchDrawable(InputStream inputStream, Density density,
            boolean isFramework, String cacheKey, BridgeContext context) throws IOException {
        // see if we still have both the chunk and the bitmap in the caches
Loading