Load typefaces via Consumer in Piet Android
TextElementAdapter still handles typeface fallbacks when the host calls consumer.accept(null).
I changed the missing fonts error to be called as a warning, since it is still be able to load a default font. I also updated it so that it's only called when no typefaces can be loaded, which is what is specified in errors.proto. That's also the behavior errors.proto specifies for image loading.
I had to update all of the font/typeface tests, since getTypeface() is a void method now that we're using a consumer.
PiperOrigin-RevId: 244713868
Change-Id: I14246f5a91f071e616811843615e48edb14e00e9
diff --git a/src/main/java/com/google/android/libraries/feed/piet/TextElementAdapter.java b/src/main/java/com/google/android/libraries/feed/piet/TextElementAdapter.java
index ed34181..bfa5190 100644
--- a/src/main/java/com/google/android/libraries/feed/piet/TextElementAdapter.java
+++ b/src/main/java/com/google/android/libraries/feed/piet/TextElementAdapter.java
@@ -26,6 +26,7 @@
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
+import com.google.android.libraries.feed.common.functional.Consumer;
import com.google.android.libraries.feed.common.ui.LayoutUtils;
import com.google.android.libraries.feed.piet.AdapterFactory.AdapterKeySupplier;
import com.google.android.libraries.feed.piet.DebugLogger.MessageType;
@@ -249,6 +250,179 @@
return intWithRegularRounding;
}
+ @VisibleForTesting
+ // LINT.IfChange
+ void setValuesUsedInRecyclerKey(TextElementKey fontKey, FrameContext frameContext) {
+ TextView textView = getBaseView();
+ textView.setTextSize(fontKey.getSize());
+ if (!fontKey.typefaces.isEmpty()) {
+ FontDetails fontDetails =
+ new FontDetails(fontKey.typefaces, fontKey.isItalic(), frameContext);
+ loadFont(textView, fontDetails);
+ } else {
+ makeFontItalic(textView, fontKey.isItalic());
+ }
+ }
+
+ private void loadFont(TextView textView, FontDetails fontDetails) {
+ StylesProto.Typeface typeface = fontDetails.getTypefaceToLoad();
+ if (typeface == null) {
+ fontDetails
+ .getFrameContext()
+ .reportMessage(
+ MessageType.WARNING,
+ ErrorCode.ERR_MISSING_FONTS,
+ "Could not load specified typefaces.");
+ // We didn't load a typeface, but we can at least respect italicization.
+ makeFontItalic(textView, fontDetails.isItalic());
+ return;
+ }
+ switch (typeface.getTypefaceSpecifierCase()) {
+ case COMMON_TYPEFACE:
+ loadCommonTypeface(typeface.getCommonTypeface(), fontDetails, textView);
+ break;
+ case CUSTOM_TYPEFACE:
+ loadCustomTypeface(typeface.getCustomTypeface(), fontDetails, textView);
+ break;
+ default:
+ // do nothing
+ }
+ }
+
+ /** Load one of the typefaces from the {@link CommonTypeface} enum. */
+ private void loadCommonTypeface(
+ CommonTypeface commonTypeface, FontDetails fontDetails, TextView textView) {
+ switch (commonTypeface) {
+ case PLATFORM_DEFAULT_LIGHT:
+ TextViewCompat.setTextAppearance(textView, R.style.gm_font_weight_light);
+ break;
+ case PLATFORM_DEFAULT_REGULAR:
+ TextViewCompat.setTextAppearance(textView, R.style.gm_font_weight_regular);
+ break;
+ case PLATFORM_DEFAULT_MEDIUM:
+ TextViewCompat.setTextAppearance(textView, R.style.gm_font_weight_medium);
+ break;
+ case GOOGLE_SANS_MEDIUM:
+ case GOOGLE_SANS_REGULAR:
+ loadCustomTypeface(googleSansEnumToStringDef(commonTypeface), fontDetails, textView);
+ // The host should take care of italicization for custom fonts, so return here.
+ return;
+ default:
+ // Unrecognized common typeface. Try to load the next typeface from fontDetails.
+ // This should never happen.
+ fontDetails.currentTypefaceFailedToLoad();
+ loadFont(textView, fontDetails);
+ return;
+ }
+ makeFontItalic(textView, fontDetails.isItalic());
+ }
+
+ /** Ask the host to load a typeface by string identifier. */
+ private void loadCustomTypeface(
+ String customTypefaceName, FontDetails fontDetails, TextView textView) {
+ TypefaceCallback typefaceCallback = new TypefaceCallback(textView, fontDetails);
+ getParameters()
+ .hostProviders
+ .getAssetProvider()
+ .getTypeface(customTypefaceName, fontDetails.isItalic(), typefaceCallback);
+ }
+
+ /**
+ * Conversion method to avoid version skew issues if we would ever change the enum names in the
+ * CommonTypeface proto, so we don't need to change all the hosts or old clients.
+ */
+ @VisibleForTesting
+ @GoogleSansTypeface
+ static String googleSansEnumToStringDef(CommonTypeface googleSansType) {
+ switch (googleSansType) {
+ case GOOGLE_SANS_MEDIUM:
+ return GoogleSansTypeface.GOOGLE_SANS_MEDIUM;
+ case GOOGLE_SANS_REGULAR:
+ return GoogleSansTypeface.GOOGLE_SANS_REGULAR;
+ default:
+ return GoogleSansTypeface.UNDEFINED;
+ }
+ }
+
+ private static void makeFontItalic(TextView textView, boolean isItalic) {
+ if (isItalic) {
+ textView.setTypeface(textView.getTypeface(), Typeface.ITALIC);
+ } else {
+ textView.setTypeface(Typeface.create(textView.getTypeface(), Typeface.NORMAL));
+ }
+ }
+
+ private static TextView createView(Context context) {
+ TextView view = new TextView(context);
+ if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
+ view.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
+ }
+ return view;
+ }
+
+ TextElementKey createKey(Font font) {
+ return new TextElementKey(font);
+ }
+
+ abstract static class TextElementKeySupplier<A extends TextElementAdapter>
+ implements AdapterKeySupplier<A, TextElement> {
+ @Override
+ public TextElementKey getKey(FrameContext frameContext, TextElement model) {
+ StyleProvider styleProvider = frameContext.makeStyleFor(model.getStyleReferences());
+ return new TextElementKey(styleProvider.getFont());
+ }
+ }
+
+ /** We will Key TextViews off of Font Size, Typefaces and Italics. */
+ // LINT.IfChange
+ static class TextElementKey extends RecyclerKey {
+ private final int size;
+ private final boolean italic;
+ private final List<StylesProto.Typeface> typefaces;
+
+ TextElementKey(Font font) {
+ size = font.getSize();
+ italic = font.getItalic();
+ typefaces = font.getTypefaceList();
+ }
+
+ public int getSize() {
+ return size;
+ }
+
+ public boolean isItalic() {
+ return italic;
+ }
+
+ @Override
+ public int hashCode() {
+ // Can't use Objects.hash() as it is only available in KK+ and can't use Guava's impl either.
+ int result = size;
+ result = 31 * result + (italic ? 1 : 0);
+ result = 31 * result + typefaces.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(/*@Nullable*/ Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj == null) {
+ return false;
+ }
+
+ if (!(obj instanceof TextElementKey)) {
+ return false;
+ }
+
+ TextElementKey key = (TextElementKey) obj;
+ return key.size == size && key.italic == italic && typefaces.equals(key.typefaces);
+ }
+ }
+ // LINT.ThenChange
+
static class ExtraLineHeight {
private final int topPaddingPx;
private final int bottomPaddingPx;
@@ -302,194 +476,58 @@
}
}
- @VisibleForTesting
- // LINT.IfChange
- void setValuesUsedInRecyclerKey(TextElementKey fontKey, FrameContext frameContext) {
- // TODO: Implement typefaces
- TextView textView = getBaseView();
- textView.setTextSize(fontKey.getSize());
+ static class FontDetails {
+ private int fontIndexToLoad;
+ private final List<StylesProto.Typeface> typefaceList;
+ private final boolean isItalic;
+ private final FrameContext frameContextForErrors;
- for (StylesProto.Typeface typeface : fontKey.typefaces) {
- switch (typeface.getTypefaceSpecifierCase()) {
- case COMMON_TYPEFACE:
- if (loadCommonTypeface(
- typeface.getCommonTypeface(), textView, fontKey.isItalic(), frameContext)) {
- return;
- }
- break;
- case CUSTOM_TYPEFACE:
- if (loadCustomTypeface(typeface.getCustomTypeface(), textView, fontKey.isItalic())) {
- return;
- }
- break;
- default:
- // do nothing
+ FontDetails(
+ List<StylesProto.Typeface> typefaceList, boolean isItalic, FrameContext frameContext) {
+ this.typefaceList = typefaceList;
+ this.isItalic = isItalic;
+ this.frameContextForErrors = frameContext;
+ }
+
+ FrameContext getFrameContext() {
+ return frameContextForErrors;
+ }
+
+ StylesProto./*@Nullable*/ Typeface getTypefaceToLoad() {
+ if (typefaceList.size() <= fontIndexToLoad) {
+ return null;
}
- }
- // We didn't load a font, but we can at least respect italicization.
- makeFontItalic(textView, fontKey.isItalic());
- }
-
- /**
- * Load one of the typefaces from the {@link CommonTypeface} enum.
- *
- * @return true for success, false for failure
- */
- private boolean loadCommonTypeface(
- CommonTypeface commonTypeface,
- TextView textView,
- boolean isItalic,
- FrameContext frameContext) {
- switch (commonTypeface) {
- case PLATFORM_DEFAULT_LIGHT:
- TextViewCompat.setTextAppearance(textView, R.style.gm_font_weight_light);
- break;
- case PLATFORM_DEFAULT_REGULAR:
- TextViewCompat.setTextAppearance(textView, R.style.gm_font_weight_regular);
- break;
- case PLATFORM_DEFAULT_MEDIUM:
- TextViewCompat.setTextAppearance(textView, R.style.gm_font_weight_medium);
- break;
- case GOOGLE_SANS_MEDIUM:
- case GOOGLE_SANS_REGULAR:
- return loadGoogleSans(commonTypeface, textView, isItalic, frameContext);
- default:
- return false;
+ return typefaceList.get(fontIndexToLoad);
}
- makeFontItalic(textView, isItalic);
- return true;
- }
-
- /**
- * Ask the host to load a typeface by string identifier.
- *
- * @return true for success, false for failure
- */
- private boolean loadCustomTypeface(String customTypeface, TextView textView, boolean isItalic) {
- Typeface hostTypeface =
- getParameters().hostProviders.getAssetProvider().getTypeface(customTypeface, isItalic);
- if (hostTypeface != null) {
- textView.setTypeface(hostTypeface);
- return true;
+ void currentTypefaceFailedToLoad() {
+ fontIndexToLoad++;
}
- return false;
- }
- /**
- * Ask the host to load a Google Sans variant. These typefaces are expected to be present, but
- * can't be included in the Piet library.
- *
- * @return true for success, false for failure
- */
- private boolean loadGoogleSans(
- CommonTypeface googleSansType,
- TextView textView,
- boolean isItalic,
- FrameContext frameContext) {
- boolean success =
- loadCustomTypeface(googleSansEnumToStringDef(googleSansType), textView, isItalic);
- if (!success) {
- frameContext.reportMessage(
- MessageType.ERROR, ErrorCode.ERR_MISSING_FONTS, "Could not load Google Sans");
- }
- return success;
- }
- // LINT.ThenChange
-
- /**
- * Conversion method to avoid version skew issues if we would ever change the enum names in the
- * CommonTypeface proto, so we don't need to change all the hosts or old clients.
- */
- @VisibleForTesting
- @GoogleSansTypeface
- static String googleSansEnumToStringDef(CommonTypeface googleSansType) {
- switch (googleSansType) {
- case GOOGLE_SANS_MEDIUM:
- return GoogleSansTypeface.GOOGLE_SANS_MEDIUM;
- case GOOGLE_SANS_REGULAR:
- return GoogleSansTypeface.GOOGLE_SANS_REGULAR;
- default:
- return GoogleSansTypeface.UNDEFINED;
+ boolean isItalic() {
+ return isItalic;
}
}
- private static void makeFontItalic(TextView textView, boolean isItalic) {
- if (isItalic) {
- textView.setTypeface(textView.getTypeface(), Typeface.ITALIC);
- } else {
- textView.setTypeface(Typeface.create(textView.getTypeface(), Typeface.NORMAL));
- }
- }
+ class TypefaceCallback implements Consumer</*@Nullable*/ Typeface> {
+ private final TextView textView;
+ private final FontDetails fontDetails;
- private static TextView createView(Context context) {
- TextView view = new TextView(context);
- if (Build.VERSION.SDK_INT >= VERSION_CODES.M) {
- view.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
- }
- return view;
- }
-
- TextElementKey createKey(Font font) {
- return new TextElementKey(font);
- }
-
- abstract static class TextElementKeySupplier<A extends TextElementAdapter>
- implements AdapterKeySupplier<A, TextElement> {
- @Override
- public TextElementKey getKey(FrameContext frameContext, TextElement model) {
- StyleProvider styleProvider = frameContext.makeStyleFor(model.getStyleReferences());
- return new TextElementKey(styleProvider.getFont());
- }
- }
-
- /** We will Key TextViews off of the Ellipsizing, Font Size and FontWeight, and Italics. */
- // LINT.IfChange
- static class TextElementKey extends RecyclerKey {
- private final int size;
- private final boolean italic;
- private final List<StylesProto.Typeface> typefaces;
-
- TextElementKey(Font font) {
- size = font.getSize();
- italic = font.getItalic();
- typefaces = font.getTypefaceList();
- }
-
- public int getSize() {
- return size;
- }
-
- public boolean isItalic() {
- return italic;
+ TypefaceCallback(TextView textView, FontDetails fontDetails) {
+ this.textView = textView;
+ this.fontDetails = fontDetails;
}
@Override
- public int hashCode() {
- // Can't use Objects.hash() as it is only available in KK+ and can't use Guava's impl either.
- int result = size;
- result = 31 * result + (italic ? 1 : 0);
- result = 31 * result + typefaces.hashCode();
- return result;
- }
-
- @Override
- public boolean equals(/*@Nullable*/ Object obj) {
- if (obj == this) {
- return true;
+ public void accept(/*@Nullable*/ Typeface typeface) {
+ if (typeface == null) {
+ fontDetails.currentTypefaceFailedToLoad();
+ loadFont(textView, fontDetails);
+ return;
}
-
- if (obj == null) {
- return false;
+ if (!textView.getTypeface().equals(typeface)) {
+ textView.setTypeface(typeface);
}
-
- if (!(obj instanceof TextElementKey)) {
- return false;
- }
-
- TextElementKey key = (TextElementKey) obj;
- return key.size == size && key.italic == italic && typefaces.equals(key.typefaces);
}
}
- // LINT.ThenChange
}
diff --git a/src/main/java/com/google/android/libraries/feed/piet/host/AssetProvider.java b/src/main/java/com/google/android/libraries/feed/piet/host/AssetProvider.java
index ddea907..ce68532 100644
--- a/src/main/java/com/google/android/libraries/feed/piet/host/AssetProvider.java
+++ b/src/main/java/com/google/android/libraries/feed/piet/host/AssetProvider.java
@@ -103,9 +103,9 @@
* the {@link GoogleSansTypeface} StringDef. Piet will report errors if Google Sans is requested
* and not found.
*/
- /*@Nullable*/
- public Typeface getTypeface(String typeface, boolean isItalic) {
- return typefaceProvider.getTypeface(typeface, isItalic);
+ public void getTypeface(
+ String typeface, boolean isItalic, Consumer</*@Nullable*/ Typeface> consumer) {
+ typefaceProvider.getTypeface(typeface, isItalic, consumer);
}
/** Returns whether Piet should render layouts using a right-to-left orientation. */
diff --git a/src/main/java/com/google/android/libraries/feed/piet/host/NullTypefaceProvider.java b/src/main/java/com/google/android/libraries/feed/piet/host/NullTypefaceProvider.java
index 3994945..89f9b0b 100644
--- a/src/main/java/com/google/android/libraries/feed/piet/host/NullTypefaceProvider.java
+++ b/src/main/java/com/google/android/libraries/feed/piet/host/NullTypefaceProvider.java
@@ -15,13 +15,14 @@
package com.google.android.libraries.feed.piet.host;
import android.graphics.Typeface;
+import com.google.android.libraries.feed.common.functional.Consumer;
/** Typeface provider that does not provide any typefaces; for use as a default implementation. */
public class NullTypefaceProvider implements TypefaceProvider {
@Override
- /*@Nullable*/
- public Typeface getTypeface(String typeface, boolean isItalic) {
- return null;
+ public void getTypeface(
+ String typeface, boolean isItalic, Consumer</*@Nullable*/ Typeface> consumer) {
+ consumer.accept(null);
}
}
diff --git a/src/main/java/com/google/android/libraries/feed/piet/host/TypefaceProvider.java b/src/main/java/com/google/android/libraries/feed/piet/host/TypefaceProvider.java
index 2d10390..d93c34c 100644
--- a/src/main/java/com/google/android/libraries/feed/piet/host/TypefaceProvider.java
+++ b/src/main/java/com/google/android/libraries/feed/piet/host/TypefaceProvider.java
@@ -16,21 +16,32 @@
import android.graphics.Typeface;
import android.support.annotation.StringDef;
+import com.google.android.libraries.feed.common.functional.Consumer;
/** Allows the host to provide Typefaces to Piet. */
public interface TypefaceProvider {
/**
- * Allows the host to return a typeface Piet would otherwise not be able to access (ex. from
- * assets). Piet will call this when the typeface is not one Piet recognizes (as a default Android
- * typeface). If host does not specially handle the specified typeface, host can return {@code
- * null}, and Piet will proceed through its fallback typefaces.
+ * Allows the host to load a typeface Piet would otherwise not be able to access (ex. from
+ * assets), and return it via the consumer. Piet will call this when the typeface is not one Piet
+ * recognizes (as a default Android typeface). If host does not specially handle the specified
+ * typeface, host can accept {@code null} through the consumer, and Piet will proceed through its
+ * fallback typefaces.
*
* <p>Piet also expects the host to provide the Google Sans typeface, and will request it using
* the {@link GoogleSansTypeface} StringDef. Piet will report errors if Google Sans is requested
* and not found.
+ *
+ * @param typeface the String that the host uses to identify which typeface to load.
+ * @param isItalic specifies whether the font should be italic. This is passed to the host instead
+ * of being handled by Piet so that the host can decide whether to just set the italic bits
+ * for the typeface or, if they want, return an entirely different font for the italic
+ * version.
+ * @param consumer accepts the typeface once it's loaded, via consumer.accept(Typeface). If the
+ * host does not recognize the typeface name or fails to load the typeface, it should accept
+ * {@code null}. If the host does NOT call consumer.accept(null), Piet will not load the
+ * fallback font, and will just use the platform default.
*/
- /*@Nullable*/
- Typeface getTypeface(String typeface, boolean isItalic);
+ void getTypeface(String typeface, boolean isItalic, Consumer</*@Nullable*/ Typeface> consumer);
/**
* Strings the host can expect to receive to request Google Sans fonts. These are intentionally
diff --git a/src/test/java/com/google/android/libraries/feed/piet/BUILD b/src/test/java/com/google/android/libraries/feed/piet/BUILD
index b1d446f..0cd5cc3 100644
--- a/src/test/java/com/google/android/libraries/feed/piet/BUILD
+++ b/src/test/java/com/google/android/libraries/feed/piet/BUILD
@@ -531,6 +531,7 @@
aapt_version = "aapt2",
manifest_values = DEFAULT_ANDROID_LOCAL_TEST_MANIFEST,
deps = [
+ "//src/main/java/com/google/android/libraries/feed/common/functional",
"//src/main/java/com/google/android/libraries/feed/common/testing",
"//src/main/java/com/google/android/libraries/feed/common/time/testing",
"//src/main/java/com/google/android/libraries/feed/common/ui",
diff --git a/src/test/java/com/google/android/libraries/feed/piet/PietManagerImplTest.java b/src/test/java/com/google/android/libraries/feed/piet/PietManagerImplTest.java
index 0d6f1af..2a07f2b 100644
--- a/src/test/java/com/google/android/libraries/feed/piet/PietManagerImplTest.java
+++ b/src/test/java/com/google/android/libraries/feed/piet/PietManagerImplTest.java
@@ -21,6 +21,7 @@
import android.app.Activity;
import android.content.Context;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -206,8 +207,9 @@
assetProvider.getRelativeElapsedString(789);
verify(stringFormatter).getRelativeElapsedString(789);
- assetProvider.getTypeface("blah", true);
- verify(typefaceProvider).getTypeface("blah", true);
+ Consumer<Typeface> typefaceConsumer = typeface -> {};
+ assetProvider.getTypeface("blah", false, typefaceConsumer);
+ verify(typefaceProvider).getTypeface("blah", false, typefaceConsumer);
assertThat(assetProvider.isDarkTheme()).isEqualTo(isDarkTheme);
assertThat(assetProvider.isRtL()).isEqualTo(isRtL);
diff --git a/src/test/java/com/google/android/libraries/feed/piet/TextElementAdapterTest.java b/src/test/java/com/google/android/libraries/feed/piet/TextElementAdapterTest.java
index 1de4a54..2719f51 100644
--- a/src/test/java/com/google/android/libraries/feed/piet/TextElementAdapterTest.java
+++ b/src/test/java/com/google/android/libraries/feed/piet/TextElementAdapterTest.java
@@ -19,6 +19,10 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -34,11 +38,13 @@
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
+import com.google.android.libraries.feed.common.functional.Consumer;
import com.google.android.libraries.feed.common.time.testing.FakeClock;
import com.google.android.libraries.feed.common.ui.LayoutUtils;
import com.google.android.libraries.feed.piet.DebugLogger.MessageType;
import com.google.android.libraries.feed.piet.TextElementAdapter.TextElementKey;
import com.google.android.libraries.feed.piet.host.AssetProvider;
+import com.google.android.libraries.feed.piet.host.TypefaceProvider;
import com.google.android.libraries.feed.piet.host.TypefaceProvider.GoogleSansTypeface;
import com.google.search.now.ui.piet.BindingRefsProto.StyleBindingRef;
import com.google.search.now.ui.piet.ElementsProto.CustomElement;
@@ -56,6 +62,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
@@ -68,6 +76,7 @@
@Mock private StyleProvider mockStyleProvider;
@Mock private HostProviders mockHostProviders;
@Mock private AssetProvider mockAssetProvider;
+ @Mock private TypefaceProvider mockTypefaceProvider;
private AdapterParameters adapterParameters;
@@ -142,7 +151,8 @@
adapter.setValuesUsedInRecyclerKey(key, frameContext);
- verify(mockAssetProvider, never()).getTypeface(any(), anyBoolean());
+ verify(mockAssetProvider, never())
+ .getTypeface(anyString(), anyBoolean(), ArgumentMatchers.<Consumer<Typeface>>any());
}
@Test
@@ -151,15 +161,12 @@
Font.newBuilder()
.addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("goodfont"))
.build();
- Typeface hostTypeface = Typeface.create("host", Typeface.BOLD_ITALIC);
- when(mockAssetProvider.getTypeface("goodfont", false)).thenReturn(hostTypeface);
-
TextElementKey key = new TextElementKey(font);
adapter.setValuesUsedInRecyclerKey(key, frameContext);
- Typeface typeface = adapter.getBaseView().getTypeface();
- assertThat(typeface).isEqualTo(hostTypeface);
+ verify(mockAssetProvider, atLeastOnce())
+ .getTypeface(eq("goodfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any());
}
@Test
@@ -170,15 +177,12 @@
.addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("badfont"))
.setItalic(true)
.build();
- Typeface hostTypeface = Typeface.create("host", Typeface.BOLD_ITALIC);
- when(mockAssetProvider.getTypeface("goodfont", true)).thenReturn(hostTypeface);
-
TextElementKey key = new TextElementKey(font);
adapter.setValuesUsedInRecyclerKey(key, frameContext);
- Typeface typeface = adapter.getBaseView().getTypeface();
- assertThat(typeface).isEqualTo(hostTypeface);
+ verify(mockAssetProvider, atLeastOnce())
+ .getTypeface(eq("goodfont"), eq(true), ArgumentMatchers.<Consumer<Typeface>>any());
}
@Test
@@ -188,15 +192,38 @@
.addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("badfont"))
.addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("goodfont"))
.build();
- Typeface hostTypeface = Typeface.create("host", Typeface.BOLD_ITALIC);
- when(mockAssetProvider.getTypeface("goodfont", false)).thenReturn(hostTypeface);
-
TextElementKey key = new TextElementKey(font);
+ // Consumer accepts null for badfont
+ doAnswer(
+ answer -> {
+ Consumer<Typeface> typefaceConsumer = answer.getArgument(2);
+ typefaceConsumer.accept(null);
+ return null;
+ })
+ .when(mockAssetProvider)
+ .getTypeface(eq("badfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any());
+ // Consumer accepts hosttypeface for goodfont
+ Typeface hostTypeface = Typeface.create("host", Typeface.BOLD_ITALIC);
+ doAnswer(
+ answer -> {
+ Consumer<Typeface> typefaceConsumer = answer.getArgument(2);
+ typefaceConsumer.accept(hostTypeface);
+ return null;
+ })
+ .when(mockAssetProvider)
+ .getTypeface(eq("goodfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any());
adapter.setValuesUsedInRecyclerKey(key, frameContext);
- Typeface typeface = adapter.getBaseView().getTypeface();
+ Typeface typeface = adapter.getBaseView().getTypeface();
assertThat(typeface).isEqualTo(hostTypeface);
+ InOrder inOrder = inOrder(mockAssetProvider);
+ inOrder
+ .verify(mockAssetProvider, atLeastOnce())
+ .getTypeface(eq("badfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any());
+ inOrder
+ .verify(mockAssetProvider, atLeastOnce())
+ .getTypeface(eq("goodfont"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any());
}
@Test
@@ -205,13 +232,24 @@
Font.newBuilder()
.addTypeface(StylesProto.Typeface.newBuilder().setCustomTypeface("notvalid"))
.build();
- when(mockAssetProvider.getTypeface(anyString(), anyBoolean())).thenReturn(null);
-
+ doAnswer(
+ answer -> {
+ Consumer<Typeface> typefaceConsumer = answer.getArgument(2);
+ typefaceConsumer.accept(null);
+ return null;
+ })
+ .when(mockAssetProvider)
+ .getTypeface(eq("notvalid"), eq(false), ArgumentMatchers.<Consumer<Typeface>>any());
TextElementKey key = new TextElementKey(font);
adapter.setValuesUsedInRecyclerKey(key, frameContext);
Typeface typeface = adapter.getBaseView().getTypeface();
+ verify(frameContext)
+ .reportMessage(
+ MessageType.WARNING,
+ ErrorCode.ERR_MISSING_FONTS,
+ "Could not load specified typefaces.");
assertThat(typeface).isEqualTo(new TextView(context).getTypeface());
}
@@ -223,36 +261,15 @@
StylesProto.Typeface.newBuilder()
.setCommonTypeface(CommonTypeface.GOOGLE_SANS_MEDIUM))
.build();
- Typeface hostTypeface = Typeface.create("fakegooglesans", Typeface.BOLD_ITALIC);
- when(mockAssetProvider.getTypeface(GoogleSansTypeface.GOOGLE_SANS_MEDIUM, false))
- .thenReturn(hostTypeface);
-
- TextElementKey key = new TextElementKey(font);
-
- adapter.setValuesUsedInRecyclerKey(key, frameContext);
- Typeface typeface = adapter.getBaseView().getTypeface();
-
- assertThat(typeface).isEqualTo(hostTypeface);
- }
-
- @Test
- public void testSetFont_reportsFailureWithGoogleSans() {
- Font font =
- Font.newBuilder()
- .addTypeface(
- StylesProto.Typeface.newBuilder()
- .setCommonTypeface(CommonTypeface.GOOGLE_SANS_MEDIUM))
- .build();
- when(mockAssetProvider.getTypeface(GoogleSansTypeface.GOOGLE_SANS_MEDIUM, false))
- .thenReturn(null);
-
TextElementKey key = new TextElementKey(font);
adapter.setValuesUsedInRecyclerKey(key, frameContext);
- verify(frameContext)
- .reportMessage(
- MessageType.ERROR, ErrorCode.ERR_MISSING_FONTS, "Could not load Google Sans");
+ verify(mockAssetProvider, atLeastOnce())
+ .getTypeface(
+ eq(GoogleSansTypeface.GOOGLE_SANS_MEDIUM),
+ eq(false),
+ ArgumentMatchers.<Consumer<Typeface>>any());
}
@Test
@@ -684,9 +701,7 @@
}
@Override
- void setTextOnView(FrameContext frameContext, TextElement textElement) {
- return;
- }
+ void setTextOnView(FrameContext frameContext, TextElement textElement) {}
@Override
TextElementKey createKey(Font font) {
diff --git a/src/test/java/com/google/android/libraries/feed/piet/host/AssetProviderTest.java b/src/test/java/com/google/android/libraries/feed/piet/host/AssetProviderTest.java
index 96e03f6..e295f44 100644
--- a/src/test/java/com/google/android/libraries/feed/piet/host/AssetProviderTest.java
+++ b/src/test/java/com/google/android/libraries/feed/piet/host/AssetProviderTest.java
@@ -83,8 +83,14 @@
@Test
public void testNullTypefaceProvider() {
TypefaceProvider typefaceProvider = new NullTypefaceProvider();
+ final Object[] consumedObject = {""};
- assertThat(typefaceProvider.getTypeface("GOOGLE_SANS_MEDIUM", false)).isNull();
+ // Make sure the object isn't already null, or we'll get a false positive.
+ assertThat(consumedObject[0]).isNotNull();
+ // The consumer passed in just saves the value that is consumed, so we can check that it's null.
+ typefaceProvider.getTypeface(
+ "GOOGLE_SANS_MEDIUM", false, typeface -> consumedObject[0] = typeface);
+ assertThat(consumedObject[0]).isNull();
}
@Test