Merge "Fix Float/Int formatters based on API feedback." into androidx-main
diff --git a/development/build_log_simplifier/messages.ignore b/development/build_log_simplifier/messages.ignore
index d905952..86a4aa1 100644
--- a/development/build_log_simplifier/messages.ignore
+++ b/development/build_log_simplifier/messages.ignore
@@ -804,6 +804,7 @@
 public abstract java\.util\.List<androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameEntity> jvmQuery\(\);
 public abstract androidx\.room\.integration\.kotlintestapp\.test\.JvmNameInDaoTest\.JvmNameDao jvmDao\(\);
 \^
+Note: \$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/TitleChip\.java has additional uses or overrides of a deprecated API\.
 \$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/layouts/PrimaryLayout\.java:[0-9]+: warning: \[deprecation\] CompactChip in androidx\.wear\.tiles\.material has been deprecated
 Note: \$SUPPORT/wear/tiles/tiles\-material/src/main/java/androidx/wear/tiles/material/Button\.java has additional uses or overrides of a deprecated API\.
 \$SUPPORT/wear/tiles/tiles\-material/src/androidTest/java/androidx/wear/tiles/material/layouts/TestCasesGenerator\.java:[0-9]+: warning: \[deprecation\] ButtonDefaults in androidx\.wear\.tiles\.material has been deprecated
diff --git a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
index 458ab19..a201b99 100644
--- a/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
+++ b/wear/protolayout/protolayout-expression-pipeline/src/test/java/androidx/wear/protolayout/expression/pipeline/DynamicTypeEvaluatorTest.java
@@ -218,42 +218,59 @@
             test(
                     DynamicFloat.constant(12.345f)
                             .format(
-                                    FloatFormatter.with()
-                                            .maxFractionDigits(2)
-                                            .minIntegerDigits(4)
-                                            .groupingUsed(true)),
+                                    new FloatFormatter.Builder()
+                                            .setMaxFractionDigits(2)
+                                            .setMinIntegerDigits(4)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "0,012.35"),
             test(
                     DynamicFloat.constant(12.345f)
                             .format(
-                                    FloatFormatter.with()
-                                            .minFractionDigits(4)
-                                            .minIntegerDigits(4)
-                                            .groupingUsed(false)),
+                                    new FloatFormatter.Builder()
+                                            .setMinFractionDigits(4)
+                                            .setMinIntegerDigits(4)
+                                            .setGroupingUsed(false)
+                                            .build()),
                     "0012.3450"),
             test(
                     DynamicFloat.constant(12.345f)
-                            .format(FloatFormatter.with().maxFractionDigits(1).groupingUsed(true))
+                            .format(
+                                    new FloatFormatter.Builder()
+                                            .setMaxFractionDigits(1)
+                                            .setGroupingUsed(true)
+                                            .build())
                             .concat(DynamicString.constant("°")),
                     "12.3°"),
             test(
                     DynamicFloat.constant(12.345678f)
                             .format(
-                                    FloatFormatter.with()
-                                            .minFractionDigits(4)
-                                            .maxFractionDigits(2)
-                                            .groupingUsed(true)),
+                                    new FloatFormatter.Builder()
+                                            .setMinFractionDigits(4)
+                                            .setMaxFractionDigits(2)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "12.3457"),
             test(
                     DynamicFloat.constant(12.345678f)
-                            .format(FloatFormatter.with().minFractionDigits(2).groupingUsed(true)),
+                            .format(
+                                    new FloatFormatter.Builder()
+                                            .setMinFractionDigits(2)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "12.346"),
-            test(DynamicFloat.constant(12.3456f).format(FloatFormatter.with()), "12.346"),
+            test(
+                    DynamicFloat.constant(12.3456f).format(new FloatFormatter.Builder().build()),
+                    "12.346"),
             test(
                     DynamicInt32.constant(12)
-                            .format(IntFormatter.with().minIntegerDigits(4).groupingUsed(true)),
+                            .format(
+                                    new IntFormatter.Builder()
+                                            .setMinIntegerDigits(4)
+                                            .setGroupingUsed(true)
+                                            .build()),
                     "0,012"),
-            test(DynamicInt32.constant(12).format(IntFormatter.with()), "12")
+            test(DynamicInt32.constant(12).format(new IntFormatter.Builder().build()), "12")
         };
         ImmutableList.Builder<Object[]> immutableListBuilder = new ImmutableList.Builder<>();
         for (DynamicTypeEvaluatorTest.TestCase<?> testCase : testCases) {
diff --git a/wear/protolayout/protolayout-expression/api/current.txt b/wear/protolayout/protolayout-expression/api/current.txt
index b526915..9433db9 100644
--- a/wear/protolayout/protolayout-expression/api/current.txt
+++ b/wear/protolayout/protolayout-expression/api/current.txt
@@ -175,11 +175,19 @@
   }
 
   public static class DynamicBuilders.DynamicFloat.FloatFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter maxFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter with();
+    method @IntRange(from=0) public int getMaxFractionDigits();
+    method @IntRange(from=0) public int getMinFractionDigits();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicFloat.FloatFormatter.Builder {
+    ctor public DynamicBuilders.DynamicFloat.FloatFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMaxFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicInstant extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
@@ -240,9 +248,15 @@
   }
 
   public static class DynamicBuilders.DynamicInt32.IntFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter with();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicInt32.IntFormatter.Builder {
+    ctor public DynamicBuilders.DynamicInt32.IntFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicString extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
diff --git a/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt b/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
index 6bcfb7b..932652c 100644
--- a/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
+++ b/wear/protolayout/protolayout-expression/api/public_plus_experimental_current.txt
@@ -175,11 +175,19 @@
   }
 
   public static class DynamicBuilders.DynamicFloat.FloatFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter maxFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter with();
+    method @IntRange(from=0) public int getMaxFractionDigits();
+    method @IntRange(from=0) public int getMinFractionDigits();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicFloat.FloatFormatter.Builder {
+    ctor public DynamicBuilders.DynamicFloat.FloatFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMaxFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicInstant extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
@@ -240,9 +248,15 @@
   }
 
   public static class DynamicBuilders.DynamicInt32.IntFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter with();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicInt32.IntFormatter.Builder {
+    ctor public DynamicBuilders.DynamicInt32.IntFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicString extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
diff --git a/wear/protolayout/protolayout-expression/api/restricted_current.txt b/wear/protolayout/protolayout-expression/api/restricted_current.txt
index b526915..9433db9 100644
--- a/wear/protolayout/protolayout-expression/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-expression/api/restricted_current.txt
@@ -175,11 +175,19 @@
   }
 
   public static class DynamicBuilders.DynamicFloat.FloatFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter maxFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minFractionDigits(@IntRange(from=0) int);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter with();
+    method @IntRange(from=0) public int getMaxFractionDigits();
+    method @IntRange(from=0) public int getMinFractionDigits();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicFloat.FloatFormatter.Builder {
+    ctor public DynamicBuilders.DynamicFloat.FloatFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMaxFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinFractionDigits(@IntRange(from=0) int);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat.FloatFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicInstant extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
@@ -240,9 +248,15 @@
   }
 
   public static class DynamicBuilders.DynamicInt32.IntFormatter {
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter groupingUsed(boolean);
-    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter minIntegerDigits(@IntRange(from=0) int);
-    method public static androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter with();
+    method @IntRange(from=0) public int getMinIntegerDigits();
+    method public boolean isGroupingUsed();
+  }
+
+  public static final class DynamicBuilders.DynamicInt32.IntFormatter.Builder {
+    ctor public DynamicBuilders.DynamicInt32.IntFormatter.Builder();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter build();
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setGroupingUsed(boolean);
+    method public androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32.IntFormatter.Builder setMinIntegerDigits(@IntRange(from=0) int);
   }
 
   public static interface DynamicBuilders.DynamicString extends androidx.wear.protolayout.expression.DynamicBuilders.DynamicType {
diff --git a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
index f726c3f..864a32d 100644
--- a/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
+++ b/wear/protolayout/protolayout-expression/src/main/java/androidx/wear/protolayout/expression/DynamicBuilders.java
@@ -2222,8 +2222,8 @@
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicInt32} (with default formatting parameters). As an example, in the English locale,
-         * the following is equal to {@code DynamicString.constant("12")}
+         * DynamicInt32} (with default formatting parameters). As an example, for locale en_US, the
+         * following is equal to {@code DynamicString.constant("12")}
          *
          * <pre>
          *   DynamicInt32.constant(12).format()
@@ -2233,65 +2233,115 @@
          */
         @NonNull
         default DynamicString format() {
-            return IntFormatter.with().buildForInput(this);
+            return new IntFormatter.Builder().build().getInt32FormatOp(this);
         }
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicInt32}. As an example, in the English locale, the following is equal to {@code
+         * DynamicInt32}. As an example, for locale en_US, the following is equal to {@code
          * DynamicString.constant("0,012")}
          *
          * <pre>
          *   DynamicInt32.constant(12)
          *            .format(
-         *                IntFormatter.with().minIntegerDigits(4).groupingUsed(true));
+         *                new IntFormatter.Builder()
+         *                                .setMinIntegerDigits(4)
+         *                                .setGroupingUsed(true)
+         *                                .build());
          * </pre>
          *
-         * The resulted {@link DynamicString} is subject to being truncated if it's too long.
-         *
          * @param formatter The formatting parameter.
          */
         @NonNull
         default DynamicString format(@NonNull IntFormatter formatter) {
-            return formatter.buildForInput(this);
+            return formatter.getInt32FormatOp(this);
         }
 
         /** Allows formatting {@link DynamicInt32} into a {@link DynamicString}. */
         class IntFormatter {
-            private final Int32FormatOp.Builder builder;
+            private final Int32FormatOp.Builder mInt32FormatOpBuilder;
+            private final Int32FormatOp mInt32FormatOp;
 
-            private IntFormatter() {
-                builder = new Int32FormatOp.Builder();
-            }
-
-            /** Creates an instance of {@link IntFormatter} with default configuration. */
-            @NonNull
-            public static IntFormatter with() {
-                return new IntFormatter();
-            }
-
-            /**
-             * Sets minimum number of integer digits for the formatter. Defaults to one if not
-             * specified.
-             */
-            @NonNull
-            public IntFormatter minIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
-                builder.setMinIntegerDigits(minIntegerDigits);
-                return this;
-            }
-
-            /**
-             * Sets whether grouping is used for the formatter. Defaults to false if not specified.
-             */
-            @NonNull
-            public IntFormatter groupingUsed(boolean groupingUsed) {
-                builder.setGroupingUsed(groupingUsed);
-                return this;
+            IntFormatter(@NonNull Int32FormatOp.Builder int32FormatOpBuilder) {
+                mInt32FormatOpBuilder = int32FormatOpBuilder;
+                mInt32FormatOp = int32FormatOpBuilder.build();
             }
 
             @NonNull
-            Int32FormatOp buildForInput(@NonNull DynamicInt32 dynamicInt32) {
-                return builder.setInput(dynamicInt32).build();
+            Int32FormatOp getInt32FormatOp(@NonNull DynamicInt32 dynamicInt32) {
+                return mInt32FormatOpBuilder.setInput(dynamicInt32).build();
+            }
+
+            /** Returns the minimum number of digits allowed in the integer portion of a number. */
+            @IntRange(from = 0)
+            public int getMinIntegerDigits() {
+                return mInt32FormatOp.getMinIntegerDigits();
+            }
+
+            /** Returns whether digit grouping is used or not. */
+            public boolean isGroupingUsed() {
+                return mInt32FormatOp.getGroupingUsed();
+            }
+
+            /** Builder to create {@link IntFormatter} objects. */
+            public static final class Builder {
+                private static final int MAX_INTEGER_PART_LENGTH = 15;
+                final Int32FormatOp.Builder mBuilder;
+
+                public Builder() {
+                    mBuilder = new Int32FormatOp.Builder();
+                }
+
+                /**
+                 * Sets minimum number of integer digits for the formatter. Defaults to one if not
+                 * specified. If minIntegerDigits is zero and the -1 < input < 1, the Integer
+                 * part will not appear.
+                 */
+                @NonNull
+                public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
+                    mBuilder.setMinIntegerDigits(minIntegerDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets whether grouping is used for the formatter. Defaults to false if not
+                 * specified. If grouping is used, digits will be grouped into digit groups using a
+                 * separator. Digit group size and used separator can vary in different
+                 * countries/regions. As an example, for locale en_US, the following is equal to
+                 * {@code * DynamicString.constant("1,234")}
+                 *
+                 * <pre>
+                 *   DynamicInt32.constant(1234)
+                 *       .format(
+                 *           new IntFormatter.Builder()
+                 *                           .setGroupingUsed(true).build());
+                 * </pre>
+                 */
+                @NonNull
+                public Builder setGroupingUsed(boolean groupingUsed) {
+                    mBuilder.setGroupingUsed(groupingUsed);
+                    return this;
+                }
+
+                /** Builds an instance with values accumulated in this Builder. */
+                @NonNull
+                public IntFormatter build() {
+                    throwIfExceedingMaxValue(
+                            "MinIntegerDigits",
+                            mBuilder.build().getMinIntegerDigits(),
+                            MAX_INTEGER_PART_LENGTH);
+                    return new IntFormatter(mBuilder);
+                }
+
+                private static void throwIfExceedingMaxValue(
+                        String paramName, int value, int maxValue) {
+                    if (value > maxValue) {
+                        throw new IllegalArgumentException(
+                                String.format(
+                                        "%s (%d) is too large. Maximum value for %s is %d",
+                                        paramName, value, paramName, maxValue));
+                    }
+                }
             }
         }
 
@@ -2377,8 +2427,8 @@
 
         /**
          * Gets minimum integer digits. Sign and grouping characters are not considered when
-         * applying minIntegerDigits constraint. If not defined, defaults to one. For example,in the
-         * English locale, applying minIntegerDigit=4 to 12 would yield "0012".
+         * applying minIntegerDigits constraint. If not defined, defaults to one. For example, for
+         * locale en_US, applying minIntegerDigit=4 to 12 would yield "0012".
          *
          * @since 1.2
          */
@@ -2389,8 +2439,8 @@
 
         /**
          * Gets digit grouping used. Grouping size and grouping character depend on the current
-         * locale. If not defined, defaults to false. For example, in the English locale, using
-         * grouping with 1234 would yield "1,234".
+         * locale. If not defined, defaults to false. For example, for locale en_US, using grouping
+         * with 1234 would yield "1,234".
          *
          * @since 1.2
          */
@@ -2437,7 +2487,7 @@
 
         /** Builder for {@link Int32FormatOp}. */
         public static final class Builder implements DynamicString.Builder {
-            private final DynamicProto.Int32FormatOp.Builder mImpl =
+            final DynamicProto.Int32FormatOp.Builder mImpl =
                     DynamicProto.Int32FormatOp.newBuilder();
             private final Fingerprint mFingerprint = new Fingerprint(196209833);
 
@@ -2458,8 +2508,8 @@
 
             /**
              * Sets minimum integer digits. Sign and grouping characters are not considered when
-             * applying minIntegerDigits constraint. If not defined, defaults to one. For example,in
-             * the English locale, applying minIntegerDigit=4 to 12 would yield "0012".
+             * applying minIntegerDigits constraint. If not defined, defaults to one. For example,
+             * for locale en_US, applying minIntegerDigit=4 to 12 would yield "0012".
              *
              * @since 1.2
              */
@@ -2472,7 +2522,7 @@
 
             /**
              * Sets digit grouping used. Grouping size and grouping character depend on the current
-             * locale. If not defined, defaults to false. For example, in the English locale, using
+             * locale. If not defined, defaults to false. For example, for locale en_US, using
              * grouping with 1234 would yield "1,234".
              *
              * @since 1.2
@@ -2901,8 +2951,8 @@
 
         /**
          * Gets minimum integer digits. Sign and grouping characters are not considered when
-         * applying minIntegerDigits constraint. If not defined, defaults to one. For example, in
-         * the English locale, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
+         * applying minIntegerDigits constraint. If not defined, defaults to one. For example, for
+         * locale en_US, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
          *
          * @since 1.2
          */
@@ -2913,8 +2963,8 @@
 
         /**
          * Gets digit grouping used. Grouping size and grouping character depend on the current
-         * locale. If not defined, defaults to false. For example, in the English locale, using
-         * grouping with 1234.56 would yield "1,234.56".
+         * locale. If not defined, defaults to false. For example, for locale en_US, using grouping
+         * with 1234.56 would yield "1,234.56".
          *
          * @since 1.2
          */
@@ -3017,7 +3067,7 @@
             /**
              * Sets minimum integer digits. Sign and grouping characters are not considered when
              * applying minIntegerDigits constraint. If not defined, defaults to one. For example,
-             * in the English locale, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
+             * for locale en_US, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
              *
              * @since 1.2
              */
@@ -3030,7 +3080,7 @@
 
             /**
              * Sets digit grouping used. Grouping size and grouping character depend on the current
-             * locale. If not defined, defaults to false. For example, in the English locale, using
+             * locale. If not defined, defaults to false. For example, for locale en_US, using
              * grouping with 1234.56 would yield "1,234.56".
              *
              * @since 1.2
@@ -4481,8 +4531,8 @@
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicFloat} (with default formatting parameters). As an example, in the English locale,
-         * the following is equal to {@code DynamicString.constant("12.346")}
+         * DynamicFloat} (with default formatting parameters). As an example, for locale en_US, the
+         * following is equal to {@code DynamicString.constant("12.346")}
          *
          * <pre>
          *   DynamicFloat.constant(12.34567f).format();
@@ -4492,19 +4542,19 @@
          */
         @NonNull
         default DynamicString format() {
-            return FloatFormatter.with().buildForInput(this);
+            return new FloatFormatter.Builder().build().getFloatFormatOp(this);
         }
 
         /**
          * Returns a {@link DynamicString} that contains the formatted value of this {@link
-         * DynamicFloat}. As an example, in the English locale, the following is equal to {@code
+         * DynamicFloat}. As an example, for locale en_US, the following is equal to {@code
          * DynamicString.constant("0,012.34")}
          *
          * <pre>
          *   DynamicFloat.constant(12.345f)
          *       .format(
-         *           FloatFormatter.with().maxFractionDigits(2).minIntegerDigits(4)
-         *                         .groupingUsed(true));
+         *           new FloatFormatter.Builder().setMaxFractionDigits(2).setMinIntegerDigits(4)
+         *                             .setGroupingUsed(true).build());
          * </pre>
          *
          * The resulted {@link DynamicString} is subject to being truncated if it's too long.
@@ -4513,67 +4563,138 @@
          */
         @NonNull
         default DynamicString format(@NonNull FloatFormatter formatter) {
-            return formatter.buildForInput(this);
+            return formatter.getFloatFormatOp(this);
         }
 
         /** Allows formatting {@link DynamicFloat} into a {@link DynamicString}. */
         class FloatFormatter {
-            private final FloatFormatOp.Builder builder;
+            private final FloatFormatOp.Builder mFloatFormatOpBuilder;
+            private final FloatFormatOp mFloatFormatOp;
 
-            private FloatFormatter() {
-                builder = new FloatFormatOp.Builder();
-            }
-
-            /** Creates an instance of {@link FloatFormatter} with default configuration. */
-            @NonNull
-            public static FloatFormatter with() {
-                return new FloatFormatter();
-            }
-
-            /**
-             * Sets minimum number of fraction digits for the formatter. Defaults to zero if not
-             * specified. minimumFractionDigits must be <= maximumFractionDigits. If the condition
-             * is not satisfied, then minimumFractionDigits will be used for both fields.
-             */
-            @NonNull
-            public FloatFormatter minFractionDigits(@IntRange(from = 0) int minFractionDigits) {
-                builder.setMinFractionDigits(minFractionDigits);
-                return this;
-            }
-
-            /**
-             * Sets maximum number of fraction digits for the formatter. Defaults to three if not
-             * specified. minimumFractionDigits must be <= maximumFractionDigits. If the condition
-             * is not satisfied, then minimumFractionDigits will be used for both fields.
-             */
-            @NonNull
-            public FloatFormatter maxFractionDigits(@IntRange(from = 0) int maxFractionDigits) {
-                builder.setMaxFractionDigits(maxFractionDigits);
-                return this;
-            }
-
-            /**
-             * Sets minimum number of integer digits for the formatter. Defaults to one if not
-             * specified.
-             */
-            @NonNull
-            public FloatFormatter minIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
-                builder.setMinIntegerDigits(minIntegerDigits);
-                return this;
-            }
-
-            /**
-             * Sets whether grouping is used for the formatter. Defaults to false if not specified.
-             */
-            @NonNull
-            public FloatFormatter groupingUsed(boolean groupingUsed) {
-                builder.setGroupingUsed(groupingUsed);
-                return this;
+            FloatFormatter(FloatFormatOp.Builder floatFormatOpBuilder) {
+                mFloatFormatOpBuilder = floatFormatOpBuilder;
+                mFloatFormatOp = floatFormatOpBuilder.build();
             }
 
             @NonNull
-            FloatFormatOp buildForInput(@NonNull DynamicFloat dynamicFloat) {
-                return builder.setInput(dynamicFloat).build();
+            FloatFormatOp getFloatFormatOp(@NonNull DynamicFloat dynamicFloat) {
+                return mFloatFormatOpBuilder.setInput(dynamicFloat).build();
+            }
+
+            /** Returns the minimum number of digits allowed in the fraction portion of a number. */
+            @IntRange(from = 0)
+            public int getMinFractionDigits() {
+                return mFloatFormatOp.getMinFractionDigits();
+            }
+
+            /** Returns the maximum number of digits allowed in the fraction portion of a number. */
+            @IntRange(from = 0)
+            public int getMaxFractionDigits() {
+                return mFloatFormatOp.getMaxFractionDigits();
+            }
+
+            /** Returns the minimum number of digits allowed in the integer portion of a number. */
+            @IntRange(from = 0)
+            public int getMinIntegerDigits() {
+                return mFloatFormatOp.getMinIntegerDigits();
+            }
+
+            /** Returns whether digit grouping is used or not. */
+            public boolean isGroupingUsed() {
+                return mFloatFormatOp.getGroupingUsed();
+            }
+
+            /** Builder to create {@link FloatFormatter} objects. */
+            public static final class Builder {
+                private static final int MAX_INTEGER_PART_LENGTH = 15;
+                private static final int MAX_FRACTION_PART_LENGTH = 15;
+                final FloatFormatOp.Builder mBuilder;
+
+                public Builder() {
+                    mBuilder = new FloatFormatOp.Builder();
+                }
+
+                /**
+                 * Sets minimum number of fraction digits for the formatter. Defaults to zero if not
+                 * specified. minimumFractionDigits must be <= maximumFractionDigits. If the
+                 * condition is not satisfied, then minimumFractionDigits will be used for both
+                 * fields.
+                 */
+                @NonNull
+                public Builder setMinFractionDigits(@IntRange(from = 0) int minFractionDigits) {
+                    mBuilder.setMinFractionDigits(minFractionDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets maximum number of fraction digits for the formatter. Defaults to three if
+                 * not specified. minimumFractionDigits must be <= maximumFractionDigits. If the
+                 * condition is not satisfied, then minimumFractionDigits will be used for both
+                 * fields.
+                 */
+                @NonNull
+                public Builder setMaxFractionDigits(@IntRange(from = 0) int maxFractionDigits) {
+                    mBuilder.setMaxFractionDigits(maxFractionDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets minimum number of integer digits for the formatter. Defaults to one if not
+                 * specified. If minIntegerDigits is zero and the -1 < input < 1, the Integer
+                 * part will not appear.
+                 */
+                @NonNull
+                public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
+                    mBuilder.setMinIntegerDigits(minIntegerDigits);
+                    return this;
+                }
+
+                /**
+                 * Sets whether grouping is used for the formatter. Defaults to false if not
+                 * specified. If grouping is used, digits will be grouped into digit groups using a
+                 * separator. Digit group size and used separator can vary in different
+                 * countries/regions. As an example, for locale en_US, the following is equal to
+                 * {@code * DynamicString.constant("1,234")}
+                 *
+                 * <pre>
+                 *   DynamicFloat.constant(1234)
+                 *       .format(
+                 *           new FloatFormatter.Builder()
+                 *                           .setGroupingUsed(true).build());
+                 * </pre>
+                 */
+                @NonNull
+                public Builder setGroupingUsed(boolean groupingUsed) {
+                    mBuilder.setGroupingUsed(groupingUsed);
+                    return this;
+                }
+
+                /** Builds an instance with values accumulated in this Builder. */
+                @NonNull
+                public FloatFormatter build() {
+                    FloatFormatOp op = mBuilder.build();
+                    throwIfExceedingMaxValue(
+                            "MinFractionDigits",
+                            op.getMinFractionDigits(),
+                            MAX_FRACTION_PART_LENGTH);
+                    throwIfExceedingMaxValue(
+                            "MaxFractionDigits",
+                            op.getMaxFractionDigits(),
+                            MAX_FRACTION_PART_LENGTH);
+                    throwIfExceedingMaxValue(
+                            "MinIntegerDigits", op.getMinIntegerDigits(), MAX_INTEGER_PART_LENGTH);
+                    return new FloatFormatter(mBuilder);
+                }
+
+                private static void throwIfExceedingMaxValue(
+                        String paramName, int value, int maxValue) {
+                    if (value > maxValue) {
+                        throw new IllegalArgumentException(
+                                String.format(
+                                        "%s (%d) is too large. Maximum value for %s is %d",
+                                        paramName, value, paramName, maxValue));
+                    }
+                }
             }
         }
 
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
index b178ff8..d00b7f3 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicFloatTest.java
@@ -17,7 +17,9 @@
 package androidx.wear.protolayout.expression;
 
 import static androidx.wear.protolayout.expression.AnimationParameterBuilders.REPEAT_MODE_REVERSE;
+
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertThrows;
 
 import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationParameters;
@@ -26,207 +28,225 @@
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicString;
 import androidx.wear.protolayout.expression.proto.DynamicProto;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DynamicFloatTest {
-  private static final String STATE_KEY = "state-key";
-  private static final float CONSTANT_VALUE = 42.42f;
-  private static final AnimationSpec SPEC =
-      new AnimationSpec.Builder()
-          .setAnimationParameters(
-                  new AnimationParameters.Builder()
-                          .setDurationMillis(2)
-                          .setDelayMillis(1)
-                          .build())
-          .setRepeatable(
-              new AnimationParameterBuilders.Repeatable.Builder()
-                  .setRepeatMode(REPEAT_MODE_REVERSE)
-                  .setIterations(10)
-                  .build())
-          .build();
+    private static final String STATE_KEY = "state-key";
+    private static final float CONSTANT_VALUE = 42.42f;
+    private static final AnimationSpec SPEC =
+            new AnimationSpec.Builder()
+                    .setAnimationParameters(
+                            new AnimationParameters.Builder()
+                                    .setDurationMillis(2)
+                                    .setDelayMillis(1)
+                                    .build())
+                    .setRepeatable(
+                            new AnimationParameterBuilders.Repeatable.Builder()
+                                    .setRepeatMode(REPEAT_MODE_REVERSE)
+                                    .setIterations(10)
+                                    .build())
+                    .build();
 
-  @Test
-  public void constantFloat() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+    @Test
+    public void constantFloat() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
 
-    assertThat(constantFloat.toDynamicFloatProto().getFixed().getValue())
-        .isWithin(0.0001f)
-        .of(CONSTANT_VALUE);
-  }
+        assertThat(constantFloat.toDynamicFloatProto().getFixed().getValue())
+                .isWithin(0.0001f)
+                .of(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantToString() {
-    assertThat(DynamicFloat.constant(1f).toString()).isEqualTo("FixedFloat{value=1.0}");
-  }
+    @Test
+    public void constantToString() {
+        assertThat(DynamicFloat.constant(1f).toString()).isEqualTo("FixedFloat{value=1.0}");
+    }
 
-  @Test
-  public void stateEntryValueFloat() {
-    DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
+    @Test
+    public void stateEntryValueFloat() {
+        DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
 
-    assertThat(stateFloat.toDynamicFloatProto().getStateSource().getSourceKey())
-        .isEqualTo(STATE_KEY);
-  }
+        assertThat(stateFloat.toDynamicFloatProto().getStateSource().getSourceKey())
+                .isEqualTo(STATE_KEY);
+    }
 
-  @Test
-  public void stateToString() {
-    assertThat(DynamicFloat.fromState("key").toString())
-        .isEqualTo("StateFloatSource{sourceKey=key}");
-  }
+    @Test
+    public void stateToString() {
+        assertThat(DynamicFloat.fromState("key").toString())
+                .isEqualTo("StateFloatSource{sourceKey=key}");
+    }
 
-  @Test
-  public void constantFloat_asInt() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+    @Test
+    public void constantFloat_asInt() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
 
-    DynamicInt32 dynamicInt32 = constantFloat.asInt();
+        DynamicInt32 dynamicInt32 = constantFloat.asInt();
 
-    assertThat(dynamicInt32.toDynamicInt32Proto().getFloatToInt().getInput().getFixed().getValue())
-        .isWithin(0.0001f)
-        .of(CONSTANT_VALUE);
-  }
+        assertThat(
+                        dynamicInt32
+                                .toDynamicInt32Proto()
+                                .getFloatToInt()
+                                .getInput()
+                                .getFixed()
+                                .getValue())
+                .isWithin(0.0001f)
+                .of(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantFloat_asIntToString() {
-    assertThat(DynamicFloat.constant(1f).asInt().toString())
-        .isEqualTo("FloatToInt32Op{input=FixedFloat{value=1.0}, roundMode=1}");
-  }
+    @Test
+    public void constantFloat_asIntToString() {
+        assertThat(DynamicFloat.constant(1f).asInt().toString())
+                .isEqualTo("FloatToInt32Op{input=FixedFloat{value=1.0}, roundMode=1}");
+    }
 
-  @Test
-  public void formatFloat_defaultParameters() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+    @Test
+    public void formatFloat_defaultParameters() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
 
-    DynamicString defaultFormat = constantFloat.format();
+        DynamicString defaultFormat = constantFloat.format();
 
-    DynamicProto.FloatFormatOp floatFormatOp =
-        defaultFormat.toDynamicStringProto().getFloatFormatOp();
-    assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
-    assertThat(floatFormatOp.getGroupingUsed()).isFalse();
-    assertThat(floatFormatOp.hasMaxFractionDigits()).isFalse();
-    assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(0);
-    assertThat(floatFormatOp.hasMinIntegerDigits()).isFalse();
-  }
+        DynamicProto.FloatFormatOp floatFormatOp =
+                defaultFormat.toDynamicStringProto().getFloatFormatOp();
+        assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
+        assertThat(floatFormatOp.getGroupingUsed()).isFalse();
+        assertThat(floatFormatOp.hasMaxFractionDigits()).isFalse();
+        assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(0);
+        assertThat(floatFormatOp.hasMinIntegerDigits()).isFalse();
+    }
 
-  @Test
-  public void formatFloat_customFormatter() {
-    DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
-    boolean groupingUsed = true;
-    int minFractionDigits = 1;
-    int maxFractionDigits = 2;
-    int minIntegerDigits = 3;
-    DynamicFloat.FloatFormatter floatFormatter =
-        DynamicFloat.FloatFormatter.with()
-            .minFractionDigits(minFractionDigits)
-            .maxFractionDigits(maxFractionDigits)
-            .minIntegerDigits(minIntegerDigits)
-            .groupingUsed(groupingUsed);
+    @Test
+    public void formatFloat_customFormatter() {
+        DynamicFloat constantFloat = DynamicFloat.constant(CONSTANT_VALUE);
+        boolean groupingUsed = true;
+        int minFractionDigits = 1;
+        int maxFractionDigits = 2;
+        int minIntegerDigits = 3;
+        DynamicFloat.FloatFormatter floatFormatter =
+                new DynamicFloat.FloatFormatter.Builder()
+                        .setMinFractionDigits(minFractionDigits)
+                        .setMaxFractionDigits(maxFractionDigits)
+                        .setMinIntegerDigits(minIntegerDigits)
+                        .setGroupingUsed(groupingUsed)
+                        .build();
 
-    DynamicString customFormat = constantFloat.format(floatFormatter);
+        DynamicString customFormat = constantFloat.format(floatFormatter);
 
-    DynamicProto.FloatFormatOp floatFormatOp =
-        customFormat.toDynamicStringProto().getFloatFormatOp();
-    assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
-    assertThat(floatFormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
-    assertThat(floatFormatOp.getMaxFractionDigits()).isEqualTo(maxFractionDigits);
-    assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(minFractionDigits);
-    assertThat(floatFormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
-  }
+        DynamicProto.FloatFormatOp floatFormatOp =
+                customFormat.toDynamicStringProto().getFloatFormatOp();
+        assertThat(floatFormatOp.getInput()).isEqualTo(constantFloat.toDynamicFloatProto());
+        assertThat(floatFormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
+        assertThat(floatFormatOp.getMaxFractionDigits()).isEqualTo(maxFractionDigits);
+        assertThat(floatFormatOp.getMinFractionDigits()).isEqualTo(minFractionDigits);
+        assertThat(floatFormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
+    }
 
-  @Test
-  public void formatToString() {
-    assertThat(
-            DynamicFloat.constant(1f)
-                .format(
-                    DynamicFloat.FloatFormatter.with()
-                        .maxFractionDigits(2)
-                        .minFractionDigits(3)
-                        .minIntegerDigits(4)
-                        .groupingUsed(true))
-                .toString())
-        .isEqualTo(
-            "FloatFormatOp{input=FixedFloat{value=1.0}, maxFractionDigits=2, "
-                + "minFractionDigits=3, minIntegerDigits=4, groupingUsed=true}");
-  }
+    @Test
+    public void formatToString() {
+        assertThat(
+                        DynamicFloat.constant(1f)
+                                .format(
+                                        new DynamicFloat.FloatFormatter.Builder()
+                                                .setMaxFractionDigits(2)
+                                                .setMinFractionDigits(3)
+                                                .setMinIntegerDigits(4)
+                                                .setGroupingUsed(true)
+                                                .build())
+                                .toString())
+                .isEqualTo(
+                        "FloatFormatOp{input=FixedFloat{value=1.0}, maxFractionDigits=2, "
+                                + "minFractionDigits=3, minIntegerDigits=4, groupingUsed=true}");
+    }
 
-  @Test
-  public void rangeAnimatedFloat() {
-    float startFloat = 100f;
-    float endFloat = 200f;
+    @Test
+    public void rangeAnimatedFloat() {
+        float startFloat = 100f;
+        float endFloat = 200f;
 
-    DynamicFloat animatedFloat = DynamicFloat.animate(startFloat, endFloat);
-    DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(startFloat, endFloat, SPEC);
+        DynamicFloat animatedFloat = DynamicFloat.animate(startFloat, endFloat);
+        DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(startFloat, endFloat, SPEC);
 
-    assertThat(animatedFloat.toDynamicFloatProto().getAnimatableFixed().hasAnimationSpec())
-        .isFalse();
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getFromValue())
-        .isEqualTo(startFloat);
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getToValue())
-        .isEqualTo(endFloat);
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getAnimationSpec())
-        .isEqualTo(SPEC.toProto());
-  }
+        assertThat(animatedFloat.toDynamicFloatProto().getAnimatableFixed().hasAnimationSpec())
+                .isFalse();
+        assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getFromValue())
+                .isEqualTo(startFloat);
+        assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableFixed().getToValue())
+                .isEqualTo(endFloat);
+        assertThat(
+                        animatedFloatWithSpec
+                                .toDynamicFloatProto()
+                                .getAnimatableFixed()
+                                .getAnimationSpec())
+                .isEqualTo(SPEC.toProto());
+    }
 
-  @Test
-  public void rangeAnimatedToString() {
-    assertThat(
-            DynamicFloat.animate(
-                    /* start= */ 1f,
-                    /* end= */ 2f,
-                    new AnimationSpec.Builder().build())
-                .toString())
-        .isEqualTo(
-            "AnimatableFixedFloat{fromValue=1.0, toValue=2.0, animationSpec=AnimationSpec{"
-                + "animationParameters=null, repeatable=null}}");
-  }
+    @Test
+    public void rangeAnimatedToString() {
+        assertThat(
+                        DynamicFloat.animate(
+                                        /* start= */ 1f,
+                                        /* end= */ 2f,
+                                        new AnimationSpec.Builder().build())
+                                .toString())
+                .isEqualTo(
+                        "AnimatableFixedFloat{fromValue=1.0, toValue=2.0,"
+                                + " animationSpec=AnimationSpec{animationParameters=null,"
+                                + " repeatable=null}}");
+    }
 
-  @Test
-  public void stateAnimatedFloat() {
-    DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
+    @Test
+    public void stateAnimatedFloat() {
+        DynamicFloat stateFloat = DynamicFloat.fromState(STATE_KEY);
 
-    DynamicFloat animatedFloat = DynamicFloat.animate(STATE_KEY);
-    DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(STATE_KEY, SPEC);
+        DynamicFloat animatedFloat = DynamicFloat.animate(STATE_KEY);
+        DynamicFloat animatedFloatWithSpec = DynamicFloat.animate(STATE_KEY, SPEC);
 
-    assertThat(animatedFloat.toDynamicFloatProto().getAnimatableDynamic().hasAnimationSpec())
-        .isFalse();
-    assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableDynamic().getInput())
-        .isEqualTo(stateFloat.toDynamicFloatProto());
-    assertThat(
-            animatedFloatWithSpec.toDynamicFloatProto().getAnimatableDynamic().getAnimationSpec()
-    ).isEqualTo(SPEC.toProto());
-    assertThat(animatedFloat.toDynamicFloatProto())
-        .isEqualTo(stateFloat.animate().toDynamicFloatProto());
-  }
+        assertThat(animatedFloat.toDynamicFloatProto().getAnimatableDynamic().hasAnimationSpec())
+                .isFalse();
+        assertThat(animatedFloatWithSpec.toDynamicFloatProto().getAnimatableDynamic().getInput())
+                .isEqualTo(stateFloat.toDynamicFloatProto());
+        assertThat(
+                        animatedFloatWithSpec
+                                .toDynamicFloatProto()
+                                .getAnimatableDynamic()
+                                .getAnimationSpec())
+                .isEqualTo(SPEC.toProto());
+        assertThat(animatedFloat.toDynamicFloatProto())
+                .isEqualTo(stateFloat.animate().toDynamicFloatProto());
+    }
 
-  @Test
-  public void stateAnimatedToString() {
-    assertThat(
-            DynamicFloat.animate(
-                    /* stateKey= */ "key",
-                    new AnimationSpec.Builder()
-                            .setAnimationParameters(
-                                    new AnimationParameters.Builder()
-                                            .setDelayMillis(1)
-                                            .build())
-                            .build())
-                .toString())
-        .isEqualTo(
-            "AnimatableDynamicFloat{"
-                + "input=StateFloatSource{sourceKey=key}, animationSpec=AnimationSpec{"
-                + "animationParameters=AnimationParameters{durationMillis=0, easing=null, "
-                + "delayMillis=1}, repeatable=null}}");
-  }
+    @Test
+    public void stateAnimatedToString() {
+        assertThat(
+                        DynamicFloat.animate(
+                                        /* stateKey= */ "key",
+                                        new AnimationSpec.Builder()
+                                                .setAnimationParameters(
+                                                        new AnimationParameters.Builder()
+                                                                .setDelayMillis(1)
+                                                                .build())
+                                                .build())
+                                .toString())
+                .isEqualTo(
+                        "AnimatableDynamicFloat{input=StateFloatSource{sourceKey=key},"
+                                + " animationSpec=AnimationSpec{animationParameters"
+                                + "=AnimationParameters{durationMillis=0,"
+                                + " easing=null, delayMillis=1}, repeatable=null}}");
+    }
 
-  @Test
-  public void validProto() {
-    DynamicFloat from = DynamicFloat.constant(CONSTANT_VALUE);
-    DynamicFloat to = DynamicFloat.fromByteArray(from.toDynamicFloatByteArray());
+    @Test
+    public void validProto() {
+        DynamicFloat from = DynamicFloat.constant(CONSTANT_VALUE);
+        DynamicFloat to = DynamicFloat.fromByteArray(from.toDynamicFloatByteArray());
 
-    assertThat(to.toDynamicFloatProto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(to.toDynamicFloatProto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void invalidProto() {
-    assertThrows(IllegalArgumentException.class, () -> DynamicFloat.fromByteArray(new byte[] {1}));
-  }
+    @Test
+    public void invalidProto() {
+        assertThrows(
+                IllegalArgumentException.class, () -> DynamicFloat.fromByteArray(new byte[] {1}));
+    }
 }
diff --git a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java
index 416e35b..f87e5b5 100644
--- a/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java
+++ b/wear/protolayout/protolayout-expression/src/test/java/androidx/wear/protolayout/expression/DynamicInt32Test.java
@@ -17,120 +17,130 @@
 package androidx.wear.protolayout.expression;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertThrows;
 
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicFloat;
 import androidx.wear.protolayout.expression.DynamicBuilders.DynamicInt32;
 import androidx.wear.protolayout.expression.proto.DynamicProto;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 
 @RunWith(RobolectricTestRunner.class)
 public final class DynamicInt32Test {
-  private static final String STATE_KEY = "state-key";
-  private static final int CONSTANT_VALUE = 42;
+    private static final String STATE_KEY = "state-key";
+    private static final int CONSTANT_VALUE = 42;
 
-  @Test
-  public void constantInt32() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+    @Test
+    public void constantInt32() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
 
-    assertThat(constantInt32.toDynamicInt32Proto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(constantInt32.toDynamicInt32Proto().getFixed().getValue())
+                .isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantToString() {
-    assertThat(DynamicInt32.constant(1).toString()).isEqualTo("FixedInt32{value=1}");
-  }
+    @Test
+    public void constantToString() {
+        assertThat(DynamicInt32.constant(1).toString()).isEqualTo("FixedInt32{value=1}");
+    }
 
-  @Test
-  public void stateEntryValueInt32() {
-    DynamicInt32 stateInt32 = DynamicInt32.fromState(STATE_KEY);
+    @Test
+    public void stateEntryValueInt32() {
+        DynamicInt32 stateInt32 = DynamicInt32.fromState(STATE_KEY);
 
-    assertThat(stateInt32.toDynamicInt32Proto().getStateSource().getSourceKey())
-        .isEqualTo(STATE_KEY);
-  }
+        assertThat(stateInt32.toDynamicInt32Proto().getStateSource().getSourceKey())
+                .isEqualTo(STATE_KEY);
+    }
 
-  @Test
-  public void stateToString() {
-    assertThat(DynamicInt32.fromState("key").toString())
-        .isEqualTo("StateInt32Source{sourceKey=key}");
-  }
+    @Test
+    public void stateToString() {
+        assertThat(DynamicInt32.fromState("key").toString())
+                .isEqualTo("StateInt32Source{sourceKey=key}");
+    }
 
-  @Test
-  public void constantInt32_asFloat() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+    @Test
+    public void constantInt32_asFloat() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
 
-    DynamicFloat dynamicFloat = constantInt32.asFloat();
+        DynamicFloat dynamicFloat = constantInt32.asFloat();
 
-    assertThat(
-            dynamicFloat
-                .toDynamicFloatProto()
-                .getInt32ToFloatOperation()
-                .getInput()
-                .getFixed()
-                .getValue())
-        .isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(
+                        dynamicFloat
+                                .toDynamicFloatProto()
+                                .getInt32ToFloatOperation()
+                                .getInput()
+                                .getFixed()
+                                .getValue())
+                .isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void constantInt32_asFloatToString() {
-    assertThat(DynamicInt32.constant(1).asFloat().toString())
-        .isEqualTo("Int32ToFloatOp{input=FixedInt32{value=1}}");
-  }
+    @Test
+    public void constantInt32_asFloatToString() {
+        assertThat(DynamicInt32.constant(1).asFloat().toString())
+                .isEqualTo("Int32ToFloatOp{input=FixedInt32{value=1}}");
+    }
 
-  @Test
-  public void formatInt32_defaultParameters() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+    @Test
+    public void formatInt32_defaultParameters() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
 
-    DynamicBuilders.DynamicString defaultFormat = constantInt32.format();
+        DynamicBuilders.DynamicString defaultFormat = constantInt32.format();
 
-    DynamicProto.Int32FormatOp int32FormatOp =
-        defaultFormat.toDynamicStringProto().getInt32FormatOp();
-    assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
-    assertThat(int32FormatOp.getGroupingUsed()).isFalse();
-    assertThat(int32FormatOp.hasMinIntegerDigits()).isFalse();
-  }
+        DynamicProto.Int32FormatOp int32FormatOp =
+                defaultFormat.toDynamicStringProto().getInt32FormatOp();
+        assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
+        assertThat(int32FormatOp.getGroupingUsed()).isFalse();
+        assertThat(int32FormatOp.hasMinIntegerDigits()).isFalse();
+    }
 
-  @Test
-  public void formatInt32_customFormatter() {
-    DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
-    boolean groupingUsed = true;
-    int minIntegerDigits = 3;
-    DynamicInt32.IntFormatter intFormatter =
-        DynamicInt32.IntFormatter.with()
-            .minIntegerDigits(minIntegerDigits)
-            .groupingUsed(groupingUsed);
+    @Test
+    public void formatInt32_customFormatter() {
+        DynamicInt32 constantInt32 = DynamicInt32.constant(CONSTANT_VALUE);
+        boolean groupingUsed = true;
+        int minIntegerDigits = 3;
+        DynamicInt32.IntFormatter intFormatter =
+                new DynamicInt32.IntFormatter.Builder()
+                        .setMinIntegerDigits(minIntegerDigits)
+                        .setGroupingUsed(groupingUsed)
+                        .build();
 
-    DynamicBuilders.DynamicString customFormat = constantInt32.format(intFormatter);
+        DynamicBuilders.DynamicString customFormat = constantInt32.format(intFormatter);
 
-    DynamicProto.Int32FormatOp int32FormatOp =
-        customFormat.toDynamicStringProto().getInt32FormatOp();
-    assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
-    assertThat(int32FormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
-    assertThat(int32FormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
-  }
+        DynamicProto.Int32FormatOp int32FormatOp =
+                customFormat.toDynamicStringProto().getInt32FormatOp();
+        assertThat(int32FormatOp.getInput()).isEqualTo(constantInt32.toDynamicInt32Proto());
+        assertThat(int32FormatOp.getGroupingUsed()).isEqualTo(groupingUsed);
+        assertThat(int32FormatOp.getMinIntegerDigits()).isEqualTo(minIntegerDigits);
+    }
 
-  @Test
-  public void formatToString() {
-    assertThat(
-            DynamicInt32.constant(1)
-                .format(DynamicInt32.IntFormatter.with().minIntegerDigits(2).groupingUsed(true))
-                .toString())
-        .isEqualTo(
-            "Int32FormatOp{input=FixedInt32{value=1}, minIntegerDigits=2, groupingUsed=true}");
-  }
+    @Test
+    public void formatToString() {
+        assertThat(
+                        DynamicInt32.constant(1)
+                                .format(
+                                        new DynamicInt32.IntFormatter.Builder()
+                                                .setMinIntegerDigits(2)
+                                                .setGroupingUsed(true)
+                                                .build())
+                                .toString())
+                .isEqualTo(
+                        "Int32FormatOp{input=FixedInt32{value=1}, minIntegerDigits=2,"
+                            + " groupingUsed=true}");
+    }
 
-  @Test
-  public void validProto() {
-    DynamicInt32 from = DynamicInt32.constant(CONSTANT_VALUE);
-    DynamicInt32 to = DynamicInt32.fromByteArray(from.toDynamicInt32ByteArray());
+    @Test
+    public void validProto() {
+        DynamicInt32 from = DynamicInt32.constant(CONSTANT_VALUE);
+        DynamicInt32 to = DynamicInt32.fromByteArray(from.toDynamicInt32ByteArray());
 
-    assertThat(to.toDynamicInt32Proto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
-  }
+        assertThat(to.toDynamicInt32Proto().getFixed().getValue()).isEqualTo(CONSTANT_VALUE);
+    }
 
-  @Test
-  public void invalidProto() {
-    assertThrows(IllegalArgumentException.class, () -> DynamicInt32.fromByteArray(new byte[] {1}));
-  }
+    @Test
+    public void invalidProto() {
+        assertThrows(
+                IllegalArgumentException.class, () -> DynamicInt32.fromByteArray(new byte[] {1}));
+    }
 }