Make TextElement reapply styles if base text height has changed.

If the size or typeface style was rebound, it would already trigger the text styles to be re-applied. However, it's possible that changing the language to one that uses a different alphabet, or changing accessibility settings could change the base text height, even if the actual font size or typeface was not changed. Because Piet uses padding to adjust the top and bottom of TextElements to have the correct line height, the styles in the StyleProvider need to be updated as well.

PiperOrigin-RevId: 257635138
Change-Id: I4b1eec5ecda6c3b44e6dffd56bf0063a30f3be36
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 c6b54df..c7a7a9c 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
@@ -80,8 +80,8 @@
 
     if (textStyle.getFont().hasLineHeight()) {
       textView.setIncludeFontPadding(false);
-      textView.setLineSpacing(
-          /* add= */ getExtraLineHeight().betweenLinesExtraPx(), /* mult= */ 1.0f);
+      ExtraLineHeight extraLineHeight = getExtraLineHeight();
+      textView.setLineSpacing(/* add= */ extraLineHeight.betweenLinesExtraPx(), /* mult= */ 1.0f);
     } else if (textStyle.getFont().hasLineHeightRatio()) {
       // TODO Remove this code once transition to line height is complete.
       textView.setIncludeFontPadding(false);
@@ -144,6 +144,9 @@
 
     if (textLine.getStyleReferences().hasStyleBinding()) {
       updateTextStyle();
+    } else if (baseFontHeightChanged()) {
+      updateTextStyle();
+      getElementStyle().applyElementStyles(this);
     }
   }
 
@@ -164,7 +167,7 @@
     textView.setText("");
   }
 
-  private float calculateOriginalAndExpectedLineHeightDifference() {
+  private float calculateCurrentAndExpectedLineHeightDifference() {
     TextView textView = getBaseView();
     StyleProvider textStyle = getElementStyle();
 
@@ -183,21 +186,22 @@
   ExtraLineHeight getExtraLineHeight() {
     Font font = getElementStyle().getFont();
 
-    // The line height cannot change in the same text element adapter, so there is no need to
-    // calculate this more than once. In fact, it should not be calculated more than once, because
-    // if calculateOriginalAndExpectedLineHeightDifference() is called again after adjusting line
-    // spacing, it will return 0, even though we still need the original calculation for padding. If
-    // it was already calculated or there is no line height set, return the saved object.
-    if (extraLineHeight.betweenLinesExtraPx() != 0
-        || (!font.hasLineHeight() && !font.hasLineHeightRatio())) {
+    if (!font.hasLineHeight() && !font.hasLineHeightRatio()) {
       return extraLineHeight;
     }
 
-    float extraLineHeightBetweenLinesFloat = calculateOriginalAndExpectedLineHeightDifference();
-    int extraLineHeightBetweenLines = Math.round(extraLineHeightBetweenLinesFloat);
-
     int totalExtraPadding = 0;
+    int extraLineHeightBetweenLines = 0;
     if (font.hasLineHeight()) {
+      float changeInLineHeight = calculateCurrentAndExpectedLineHeightDifference();
+      if (changeInLineHeight == 0) {
+        return extraLineHeight;
+      }
+
+      float extraLineHeightBetweenLinesFloat =
+          extraLineHeight.betweenLinesExtraPx() + changeInLineHeight;
+      extraLineHeightBetweenLines = Math.round(extraLineHeightBetweenLinesFloat);
+
       // Adjust the rounding for the extra top and bottom padding, to make the total height of the
       // text element a little more exact.
       totalExtraPadding = adjustRounding(extraLineHeightBetweenLinesFloat);
@@ -233,6 +237,19 @@
     return extraLineHeight;
   }
 
+  private boolean baseFontHeightChanged() {
+    // Check if we've already calculated the extra line height and there is a significant difference
+    // between the current and expected line heights.
+    if (extraLineHeight.betweenLinesExtraPx() == 0) {
+      return false;
+    }
+    float lineHeightDifference = calculateCurrentAndExpectedLineHeightDifference();
+    if (Math.round(lineHeightDifference) == 0) {
+      return false;
+    }
+    return true;
+  }
+
   /**
    * Rounds the float value away from the nearest integer, i.e. 4.75 rounds to 4, and 7.2 rounds to
    * 8.
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 f1c1afd..9033a0f 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
@@ -670,6 +670,36 @@
   }
 
   @Test
+  public void bindWithUpdatedDensity_shouldUpdateLineHeight() {
+    final int lineHeightInTextElement = 50;
+    context.getResources().getDisplayMetrics().scaledDensity = 1;
+    Style style =
+        Style.newBuilder()
+            .setFont(Font.newBuilder().setLineHeight(lineHeightInTextElement))
+            .build();
+    StyleProvider styleProvider = new StyleProvider(style, mockAssetProvider);
+    Element textElement = getBaseTextElement(styleProvider);
+
+    adapter.createAdapter(textElement, frameContext);
+    adapter.bindModel(textElement, frameContext);
+    assertThat(adapter.getBaseView().getLineHeight()).isEqualTo(lineHeightInTextElement);
+
+    adapter.unbindModel();
+    // Change line height by changing the scale density
+    context.getResources().getDisplayMetrics().scaledDensity = 2;
+    adapter.bindModel(textElement, frameContext);
+    // getLineHeight() still returns pixels. The number of pixels should have been updated to
+    // reflect the new density.
+    assertThat(adapter.getBaseView().getLineHeight()).isEqualTo(lineHeightInTextElement * 2);
+
+    adapter.unbindModel();
+    // Make sure the line height is updated again when the scale density is changed back.
+    context.getResources().getDisplayMetrics().scaledDensity = 1;
+    adapter.bindModel(textElement, frameContext);
+    assertThat(adapter.getBaseView().getLineHeight()).isEqualTo(lineHeightInTextElement);
+  }
+
+  @Test
   public void testUnbind() {
     Element textElement = getBaseTextElement(null);
     adapter.createAdapter(textElement, frameContext);