From e8f7e6134b5bf2fe31f990ba0199f150ac822d6b Mon Sep 17 00:00:00 2001 From: Thorben Primke Date: Thu, 29 Jun 2017 16:11:30 -0700 Subject: [PATCH 1/2] Adds A Config Option To Provide a FontPath Substitution Map Summary: In order to A/B test fonts, this adds an option to the CalligraphyConfig to provide a fontPath substitution map. This enables dynamically changing fonts at run time and requires no changes to XML files. The logic to substitute the fontPath is in the TypefaceUtils. The reason the map is set on the TypeFaceUtils instead of the TypefaceUtils to checked the CalligraphyConfig is that this way it doesn't require constant invokations to CalligraphyConfig.get(). Test Plan: - Verified with sample app that the new config option works as expected. --- .../calligraphy/CalligraphyConfig.java | 19 +++++++++++++++++++ .../chrisjenx/calligraphy/TypefaceUtils.java | 14 +++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java index 2fb8f63..6cf9618 100644 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/CalligraphyConfig.java @@ -1,5 +1,6 @@ package uk.co.chrisjenx.calligraphy; +import android.content.res.AssetManager; import android.os.Build; import android.text.TextUtils; import android.view.View; @@ -71,6 +72,7 @@ private static void addAppCompatViews() { */ public static void initDefault(CalligraphyConfig calligraphyConfig) { sInstance = calligraphyConfig; + TypefaceUtils.setFontPathSubstitutionMap(sInstance.getFontPathSubstitutionMap()); } /** @@ -116,6 +118,11 @@ public static CalligraphyConfig get() { * @see uk.co.chrisjenx.calligraphy.CalligraphyConfig.Builder#addCustomViewWithSetTypeface(Class) */ private final Set> hasTypefaceViews; + /** + * A map of font paths that should be used to dynamically substitute a new fontPath for the + * fontPath that's specified in XML / passed to {@link TypefaceUtils#load(AssetManager, String)} + */ + private Map mFontPathSubstitutionMap = null; protected CalligraphyConfig(Builder builder) { mIsFontSet = builder.isFontSet; @@ -128,6 +135,7 @@ protected CalligraphyConfig(Builder builder) { tempMap.putAll(builder.mStyleClassMap); mClassStyleAttributeMap = Collections.unmodifiableMap(tempMap); hasTypefaceViews = Collections.unmodifiableSet(builder.mHasTypefaceClasses); + mFontPathSubstitutionMap = builder.fontPathSubstitutionMap; } /** @@ -171,6 +179,10 @@ public int getAttrId() { return mAttrId; } + public Map getFontPathSubstitutionMap() { + return mFontPathSubstitutionMap; + } + public static class Builder { /** * Default AttrID if not set. @@ -207,6 +219,8 @@ public static class Builder { private Set> mHasTypefaceClasses = new HashSet<>(); + private Map fontPathSubstitutionMap = null; + /** * This defaults to R.attr.fontPath. So only override if you want to use your own attrId. * @@ -312,6 +326,11 @@ public Builder addCustomViewWithSetTypeface(Class clazz) { return this; } + public Builder setFontPathSubstitutionMap(Map fontPathSubstitutionMap) { + this.fontPathSubstitutionMap = fontPathSubstitutionMap; + return this; + } + public CalligraphyConfig build() { this.isFontSet = !TextUtils.isEmpty(fontAssetPath); return new CalligraphyConfig(this); diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java index 8ad3a8c..04c6d30 100644 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java @@ -2,6 +2,7 @@ import android.content.res.AssetManager; import android.graphics.Typeface; +import android.support.annotation.Nullable; import android.util.Log; import java.util.HashMap; @@ -20,6 +21,7 @@ public final class TypefaceUtils { private static final Map sCachedFonts = new HashMap(); private static final Map sCachedSpans = new HashMap(); + private static Map sFontPathSubstitutionMap = null; /** * A helper loading a custom font. @@ -28,9 +30,15 @@ public final class TypefaceUtils { * @param filePath The path of the file. * @return Return {@link android.graphics.Typeface} or null if the path is invalid. */ - public static Typeface load(final AssetManager assetManager, final String filePath) { + public static Typeface load(final AssetManager assetManager, String filePath) { synchronized (sCachedFonts) { try { + // If a valid fontPath substitution map exists, check if the filePath should be + // updated in order to load a different font. + if (sFontPathSubstitutionMap != null + && sFontPathSubstitutionMap.containsKey(filePath)) { + filePath = sFontPathSubstitutionMap.get(filePath); + } if (!sCachedFonts.containsKey(filePath)) { final Typeface typeface = Typeface.createFromAsset(assetManager, filePath); sCachedFonts.put(filePath, typeface); @@ -75,4 +83,8 @@ public static boolean isLoaded(Typeface typeface) { private TypefaceUtils() { } + + static void setFontPathSubstitutionMap(@Nullable Map fontPathSubstitutionMap) { + sFontPathSubstitutionMap = fontPathSubstitutionMap; + } } From a82de7e9f8166640b9e3d944e4ea2a40f205ec0b Mon Sep 17 00:00:00 2001 From: Thorben Primke Date: Fri, 7 Jul 2017 15:21:58 -0700 Subject: [PATCH 2/2] Updates external / subsitution fonts to be loaded from the filesystem --- .../java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java index 04c6d30..f32121a 100644 --- a/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java +++ b/calligraphy/src/main/java/uk/co/chrisjenx/calligraphy/TypefaceUtils.java @@ -35,12 +35,19 @@ public static Typeface load(final AssetManager assetManager, String filePath) { try { // If a valid fontPath substitution map exists, check if the filePath should be // updated in order to load a different font. + boolean loadFromFile = false; if (sFontPathSubstitutionMap != null && sFontPathSubstitutionMap.containsKey(filePath)) { filePath = sFontPathSubstitutionMap.get(filePath); + loadFromFile = true; } if (!sCachedFonts.containsKey(filePath)) { - final Typeface typeface = Typeface.createFromAsset(assetManager, filePath); + final Typeface typeface; + if (loadFromFile) { + typeface = Typeface.createFromFile(filePath); + } else { + typeface = Typeface.createFromAsset(assetManager, filePath); + } sCachedFonts.put(filePath, typeface); return typeface; }