[go: nahoru, domu]

Add support for weights to ArcLayout

Test: Added a new unit test
Bug: 230730731
Relnote: We've added weight to ArcLayout.LayoutParams which allows a widget to expand to fill the available space, if there's more then one widget then their share of the available space is proportional to their weight. In addition we've added ArcLayout.setMaxAngleDegrees so you can for example cap the expansion at 90 degrees (NB this does not affect layout of any fixed sized child widgets). Finally ArcLayout.Widget now has setSweepAngleDegrees which allows the ArcLayout to inform a Widget with a non-zero weight of its size.
Change-Id: I75f2449c6bed88e2f6f8a443dd8951b2ce275d76
diff --git a/wear/wear/api/current.txt b/wear/wear/api/current.txt
index 8c2d6d1..30a2fbd 100644
--- a/wear/wear/api/current.txt
+++ b/wear/wear/api/current.txt
@@ -129,10 +129,12 @@
     ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
     method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
     method public int getAnchorType();
+    method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxAngleDegrees();
     method public boolean isClockwise();
     method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
     method public void setAnchorType(int);
     method public void setClockwise(boolean);
+    method public void setMaxAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
     field public static final int ANCHOR_CENTER = 1; // 0x1
     field public static final int ANCHOR_END = 2; // 0x2
     field public static final int ANCHOR_START = 0; // 0x0
@@ -143,9 +145,11 @@
     ctor public ArcLayout.LayoutParams(int, int);
     ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     method public int getVerticalAlignment();
+    method public float getWeight();
     method public boolean isRotated();
     method public void setRotated(boolean);
     method public void setVerticalAlignment(int);
+    method public void setWeight(float);
     field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
     field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
     field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
@@ -156,6 +160,7 @@
     method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
     method @Px public int getThickness();
     method public boolean isPointInsideClickArea(float, float);
+    method public default void setSweepAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
   }
 
   @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
diff --git a/wear/wear/api/public_plus_experimental_current.txt b/wear/wear/api/public_plus_experimental_current.txt
index 8c2d6d1..30a2fbd 100644
--- a/wear/wear/api/public_plus_experimental_current.txt
+++ b/wear/wear/api/public_plus_experimental_current.txt
@@ -129,10 +129,12 @@
     ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
     method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
     method public int getAnchorType();
+    method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxAngleDegrees();
     method public boolean isClockwise();
     method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
     method public void setAnchorType(int);
     method public void setClockwise(boolean);
+    method public void setMaxAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
     field public static final int ANCHOR_CENTER = 1; // 0x1
     field public static final int ANCHOR_END = 2; // 0x2
     field public static final int ANCHOR_START = 0; // 0x0
@@ -143,9 +145,11 @@
     ctor public ArcLayout.LayoutParams(int, int);
     ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     method public int getVerticalAlignment();
+    method public float getWeight();
     method public boolean isRotated();
     method public void setRotated(boolean);
     method public void setVerticalAlignment(int);
+    method public void setWeight(float);
     field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
     field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
     field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
@@ -156,6 +160,7 @@
     method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
     method @Px public int getThickness();
     method public boolean isPointInsideClickArea(float, float);
+    method public default void setSweepAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
   }
 
   @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
diff --git a/wear/wear/api/restricted_current.txt b/wear/wear/api/restricted_current.txt
index 036a396..38baf3e1 100644
--- a/wear/wear/api/restricted_current.txt
+++ b/wear/wear/api/restricted_current.txt
@@ -129,10 +129,12 @@
     ctor public ArcLayout(android.content.Context, android.util.AttributeSet?, int, int);
     method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getAnchorAngleDegrees();
     method @androidx.wear.widget.ArcLayout.AnchorType public int getAnchorType();
+    method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getMaxAngleDegrees();
     method public boolean isClockwise();
     method public void setAnchorAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
     method public void setAnchorType(@androidx.wear.widget.ArcLayout.AnchorType int);
     method public void setClockwise(boolean);
+    method public void setMaxAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
     field public static final int ANCHOR_CENTER = 1; // 0x1
     field public static final int ANCHOR_END = 2; // 0x2
     field public static final int ANCHOR_START = 0; // 0x0
@@ -146,9 +148,11 @@
     ctor public ArcLayout.LayoutParams(int, int);
     ctor public ArcLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
     method @androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment public int getVerticalAlignment();
+    method public float getWeight();
     method public boolean isRotated();
     method public void setRotated(boolean);
     method public void setVerticalAlignment(@androidx.wear.widget.ArcLayout.LayoutParams.VerticalAlignment int);
+    method public void setWeight(float);
     field public static final int VERTICAL_ALIGN_CENTER = 1; // 0x1
     field public static final int VERTICAL_ALIGN_INNER = 2; // 0x2
     field public static final int VERTICAL_ALIGN_OUTER = 0; // 0x0
@@ -162,6 +166,7 @@
     method @FloatRange(from=0.0f, to=360.0f, toInclusive=true) public float getSweepAngleDegrees();
     method @Px public int getThickness();
     method public boolean isPointInsideClickArea(float, float);
+    method public default void setSweepAngleDegrees(@FloatRange(from=0.0f, to=360.0f, toInclusive=true) float);
   }
 
   @UiThread public class BoxInsetLayout extends android.view.ViewGroup {
diff --git a/wear/wear/build.gradle b/wear/wear/build.gradle
index 6f65819..401ee9b 100644
--- a/wear/wear/build.gradle
+++ b/wear/wear/build.gradle
@@ -23,6 +23,7 @@
     androidTestImplementation(libs.espressoCore, excludes.espresso)
     androidTestImplementation(libs.mockitoCore, excludes.bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(libs.dexmakerMockito, excludes.bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(libs.truth)
 
     testImplementation(libs.kotlinStdlib)
     testImplementation(libs.testCore)
diff --git a/wear/wear/src/androidTest/java/androidx/wear/widget/ArcLayoutTest.kt b/wear/wear/src/androidTest/java/androidx/wear/widget/ArcLayoutTest.kt
index d8dcea7..b03ecf3 100644
--- a/wear/wear/src/androidTest/java/androidx/wear/widget/ArcLayoutTest.kt
+++ b/wear/wear/src/androidTest/java/androidx/wear/widget/ArcLayoutTest.kt
@@ -53,6 +53,7 @@
 import androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_INNER
 import androidx.wear.widget.ArcLayout.LayoutParams.VERTICAL_ALIGN_OUTER
 import androidx.wear.widget.util.AsyncViewActions.waitForMatchingView
+import com.google.common.truth.Truth.assertThat
 import org.hamcrest.CoreMatchers.allOf
 import org.hamcrest.CoreMatchers.any
 import org.hamcrest.Matcher
@@ -298,38 +299,40 @@
         clockwise: Boolean = true,
         textSize: Float = 14f,
         textAlignment: Int = View.TEXT_ALIGNMENT_TEXT_START,
-        minSweep: Float = 0f
-    ) {
-        addView(
-            CurvedTextView(ApplicationProvider.getApplicationContext())
-                .also {
-                    it.text = text
-                    it.setBackgroundColor(color)
-                    it.isClockwise = clockwise
-                    it.textSize = textSize
-                    it.textAlignment = textAlignment
-                    it.setSweepRangeDegrees(minSweep, 360f)
-                    it.setPadding(
-                        paddingLeft ?: padding ?: 0,
-                        paddingTop ?: padding ?: 0,
-                        paddingRight ?: padding ?: 0,
-                        paddingBottom ?: padding ?: 0
+        minSweep: Float = 0f,
+        weight: Float = 0f
+    ): CurvedTextView {
+        val curvedTextView = CurvedTextView(ApplicationProvider.getApplicationContext())
+            .also {
+                it.text = text
+                it.setBackgroundColor(color)
+                it.isClockwise = clockwise
+                it.textSize = textSize
+                it.textAlignment = textAlignment
+                it.setSweepRangeDegrees(minSweep, 360f)
+                it.setPadding(
+                    paddingLeft ?: padding ?: 0,
+                    paddingTop ?: padding ?: 0,
+                    paddingRight ?: padding ?: 0,
+                    paddingBottom ?: padding ?: 0
+                )
+                it.layoutParams = ArcLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT
+                ).apply {
+                    setMargins(
+                        marginLeft ?: margin ?: 0,
+                        marginTop ?: margin ?: 0,
+                        marginRight ?: margin ?: 0,
+                        marginBottom ?: margin ?: 0
                     )
-                    it.layoutParams = ArcLayout.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.MATCH_PARENT
-                    ).apply {
-                        setMargins(
-                            marginLeft ?: margin ?: 0,
-                            marginTop ?: margin ?: 0,
-                            marginRight ?: margin ?: 0,
-                            marginBottom ?: margin ?: 0
-                        )
-                        verticalAlignment = vAlign
-                    }
+                    verticalAlignment = vAlign
+                    this.weight = weight
                 }
-        )
+            }
+        addView(curvedTextView)
         testColors.add(colorProcessor(color))
+        return curvedTextView
     }
 
     fun ArcLayout.addTextView(
@@ -433,6 +436,106 @@
     }
 
     @Test
+    fun testLayoutWeight() {
+        var child1: CurvedTextView
+        var child2: CurvedTextView
+        doOneTest(
+            "layout_weight_180",
+            listOf(
+                ArcLayout(ApplicationProvider.getApplicationContext())
+                    .apply {
+                        anchorType = ArcLayout.ANCHOR_START
+                        maxAngleDegrees = 180f
+                        child1 = addCurvedText("1/4", Color.RED, textSize = 30f, weight = 1f)
+                        child2 = addCurvedText("3/4", Color.GREEN, textSize = 30f, weight = 3f)
+                    }
+            )
+        )
+
+        assertThat(child1.sweepAngleDegrees).isEqualTo(45f)
+        assertThat(child2.sweepAngleDegrees).isEqualTo(135f)
+    }
+
+    @Test
+    fun testLayoutWeightWithPadding() {
+        doOneTest(
+            "layout_weight_180_padding",
+            listOf(
+                ArcLayout(ApplicationProvider.getApplicationContext())
+                    .apply {
+                        anchorType = ArcLayout.ANCHOR_START
+                        maxAngleDegrees = 180f
+                        addCurvedText(
+                            "1/4",
+                            Color.RED,
+                            textSize = 30f,
+                            weight = 1f,
+                            padding = 20
+                        )
+                        addCurvedText(
+                            "3/4",
+                            Color.GREEN,
+                            textSize = 30f,
+                            weight = 3f,
+                            padding = 20
+                        )
+                    }
+            )
+        )
+    }
+
+    @Test
+    fun testLayoutWeightRtl() {
+        doOneTest(
+            "layout_weight_180_rtl",
+            listOf(
+                ArcLayout(ApplicationProvider.getApplicationContext())
+                    .apply {
+                        anchorType = ArcLayout.ANCHOR_START
+                        layoutDirection = View.LAYOUT_DIRECTION_RTL
+                        maxAngleDegrees = 180f
+                        addCurvedText("1/4", Color.RED, textSize = 30f, weight = 1f)
+                        addCurvedText("3/4", Color.GREEN, textSize = 30f, weight = 3f)
+                    }
+            )
+        )
+    }
+
+    @Test
+    fun testMixedLayoutWeight() {
+        doOneTest(
+            "mixed_layout_weight",
+            listOf(
+                ArcLayout(ApplicationProvider.getApplicationContext())
+                    .apply {
+                        anchorType = ArcLayout.ANCHOR_START
+                        maxAngleDegrees = 180f
+                        addCurvedText("Fixed", Color.BLUE, textSize = 30f)
+                        addCurvedText("1/4", Color.RED, textSize = 30f, weight = 1f)
+                        addCurvedText("3/4", Color.GREEN, textSize = 30f, weight = 3f)
+                    }
+            )
+        )
+    }
+
+    @Test
+    fun testMixedLayoutWeightAnchorEnd() {
+        doOneTest(
+            "mixed_layout_weight_anchor_end",
+            listOf(
+                ArcLayout(ApplicationProvider.getApplicationContext())
+                    .apply {
+                        anchorType = ArcLayout.ANCHOR_END
+                        maxAngleDegrees = 180f
+                        addCurvedText("Fixed", Color.BLUE, textSize = 30f)
+                        addCurvedText("1/4", Color.RED, textSize = 30f, weight = 1f)
+                        addCurvedText("3/4", Color.GREEN, textSize = 30f, weight = 3f)
+                    }
+            )
+        )
+    }
+
+    @Test
     fun testInvisibleAndGone() {
         doOneTest(
             "inivisible_gone_test",
diff --git a/wear/wear/src/main/java/androidx/wear/widget/ArcLayout.java b/wear/wear/src/main/java/androidx/wear/widget/ArcLayout.java
index 9673223..4c7c768 100644
--- a/wear/wear/src/main/java/androidx/wear/widget/ArcLayout.java
+++ b/wear/wear/src/main/java/androidx/wear/widget/ArcLayout.java
@@ -90,6 +90,15 @@
         @FloatRange(from = 0.0f, to = 360.0f, toInclusive = true)
         float getSweepAngleDegrees();
 
+        /**
+         * Set the sweep angle that this widget is drawn with. This is only called during layout,
+         * and only if the {@link LayoutParams#mWeight} is non-zero. Note your widget will need to
+         * handle alignment.
+         */
+        default void setSweepAngleDegrees(
+                @FloatRange(from = 0.0f, to = 360.0f, toInclusive = true) float sweepAngleDegrees) {
+        }
+
         /** Returns the thickness of this widget inside the arc. */
         @Px
         int getThickness();
@@ -151,13 +160,16 @@
         float mCenterX;
         float mCenterY;
 
+        // The layout weight for this view, a value of zero means no expansion.
+        float mWeight;
+
         /**
          * Creates a new set of layout parameters. The values are extracted from the supplied
          * attributes set and context.
          *
-         * @param context  The Context the ArcLayout is running in, through which it can access the
-         *                 current theme, resources, etc.
-         * @param attrs    The set of attributes from which to extract the layout parameters' values
+         * @param context The Context the ArcLayout is running in, through which it can access the
+         *                current theme, resources, etc.
+         * @param attrs   The set of attributes from which to extract the layout parameters' values
          */
         public LayoutParams(@NonNull Context context, @Nullable AttributeSet attrs) {
             super(context, attrs);
@@ -167,6 +179,7 @@
             mRotated = a.getBoolean(R.styleable.ArcLayout_Layout_layout_rotate, true);
             mVerticalAlignment =
                     a.getInt(R.styleable.ArcLayout_Layout_layout_valign, VERTICAL_ALIGN_CENTER);
+            mWeight = a.getFloat(R.styleable.ArcLayout_Layout_layout_weight, 0f);
 
             a.recycle();
         }
@@ -174,8 +187,8 @@
         /**
          * Creates a new set of layout parameters with specified width and height
          *
-         * @param width   The width, either WRAP_CONTENT, MATCH_PARENT or a fixed size in pixels
-         * @param height  The height, either WRAP_CONTENT, MATCH_PARENT or a fixed size in pixels
+         * @param width  The width, either WRAP_CONTENT, MATCH_PARENT or a fixed size in pixels
+         * @param height The height, either WRAP_CONTENT, MATCH_PARENT or a fixed size in pixels
          */
         public LayoutParams(int width, int height) {
             super(width, height);
@@ -212,11 +225,32 @@
 
         /**
          * Sets how the widget is positioned vertically in the ArcLayout.
+         *
          * @param verticalAlignment align the widget to outer, inner edges or center.
          */
         public void setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
             mVerticalAlignment = verticalAlignment;
         }
+
+        /** Returns the weight used for computing expansion. */
+        public float getWeight() {
+            return mWeight;
+        }
+
+        /**
+         * Indicates how much of the extra space in the ArcLayout will be allocated to the
+         * view associated with these LayoutParams up to the limit specified by
+         * {@link ArcLayout#setMaxAngleDegrees}. Specify 0 if the view should not be
+         * stretched.
+         * Otherwise the extra pixels will be pro-rated among all views whose weight is greater than
+         * 0.
+         *
+         * Note non zero weights are only supported for Views that implement {@link ArcLayout
+         * .Widget}.
+         */
+        public void setWeight(float weight) {
+            mWeight = weight;
+        }
     }
 
     /** Annotation for anchor types. */
@@ -266,6 +300,12 @@
     @AnchorType
     private int mAnchorType;
     private float mAnchorAngleDegrees;
+    /**
+     * This is the target angle that will be used by the layout when expanding child views with
+     * weights.
+     */
+    private float mMaxAngleDegrees = 360.0f;
+
     private boolean mClockwise;
 
     @SuppressWarnings("SyntheticAccessor")
@@ -378,7 +418,7 @@
             }
             LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();
             maxChildHeightPx = max(maxChildHeightPx, childMeasuredHeight
-                    + childLayoutParams.topMargin +  childLayoutParams.bottomMargin);
+                    + childLayoutParams.topMargin + childLayoutParams.bottomMargin);
         }
 
         mThicknessPx = maxChildHeightPx;
@@ -422,8 +462,39 @@
         // != is equivalent to xor, we want to invert clockwise when the layout is rtl
         final float multiplier = mClockwise != isLayoutRtl ? 1f : -1f;
 
-         // Layout the children in the arc, computing the center angle where they should be drawn.
+        // Layout the children in the arc, computing the center angle where they should be drawn.
         float currentCumulativeAngle = calculateInitialRotation(multiplier);
+
+        // Compute the sum of any weights and the sum of the angles take up by fixed sized children.
+        // Unfortunately we can't move this to measure because calculateArcAngle relies upon
+        // getMeasuredWidth() which returns 0 in measure.
+        float totalAngle = 0f;
+        float weightSum = 0f;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();
+            if (childLayoutParams.mWeight > 0) {
+                weightSum += childLayoutParams.mWeight;
+                calculateArcAngle(child, mChildArcAngles);
+                totalAngle +=
+                        mChildArcAngles.leftMarginAsAngle + mChildArcAngles.rightMarginAsAngle;
+            } else {
+                calculateArcAngle(child, mChildArcAngles);
+                totalAngle += mChildArcAngles.getTotalAngle();
+            }
+        }
+
+        float weightMultiplier = 0f;
+        if (weightSum > 0f) {
+            weightMultiplier = (mMaxAngleDegrees - totalAngle) / weightSum;
+        }
+
+        // Now perform the layout.
         for (int i = 0; i < getChildCount(); i++) {
             View child = getChildAt(i);
 
@@ -432,11 +503,21 @@
             }
 
             calculateArcAngle(child, mChildArcAngles);
+            LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();
+            if (childLayoutParams.mWeight > 0) {
+                mChildArcAngles.actualChildAngle = childLayoutParams.mWeight * weightMultiplier;
+                if (child instanceof Widget) {
+                    // NB we need to be careful since the child itself may set this value dueing
+                    // measure.
+                    ((Widget) child).setSweepAngleDegrees(mChildArcAngles.actualChildAngle);
+                } else {
+                    throw new IllegalStateException("ArcLayout.LayoutParams with non zero weights"
+                            + " are only supported for views implementing ArcLayout.Widget");
+                }
+            }
             float preRotation = mChildArcAngles.leftMarginAsAngle
                     + mChildArcAngles.actualChildAngle / 2f;
-
             float middleAngle = multiplier * (currentCumulativeAngle + preRotation);
-            LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();
             childLayoutParams.mMiddleAngle = middleAngle;
 
             // Distance from the center of the ArcLayout to the center of the child widget
@@ -608,11 +689,21 @@
 
         float totalArcAngle = 0;
 
+        boolean hasWeights = false;
         for (int i = 0; i < getChildCount(); i++) {
-            calculateArcAngle(getChildAt(i), mChildArcAngles);
+            View child = getChildAt(i);
+            LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();
+            if (childLayoutParams.getWeight() > 0f) {
+                hasWeights = true;
+            }
+            calculateArcAngle(child, mChildArcAngles);
             totalArcAngle += mChildArcAngles.getTotalAngle();
         }
 
+        if (hasWeights && totalArcAngle < mMaxAngleDegrees) {
+            totalArcAngle = mMaxAngleDegrees;
+        }
+
         if (mAnchorType == ANCHOR_CENTER) {
             return multiplier * mAnchorAngleDegrees - (totalArcAngle / 2f);
         } else if (mAnchorType == ANCHOR_END) {
@@ -742,6 +833,28 @@
         invalidate();
     }
 
+    /**
+     * Returns the target angle that will be used by the layout when expanding child views with
+     * weights (see {@link LayoutParams#setWeight}).
+     */
+    @FloatRange(from = 0.0f, to = 360.0f, toInclusive = true)
+    public float getMaxAngleDegrees() {
+        return mMaxAngleDegrees;
+    }
+
+    /**
+     * Sets the target angle that will be used by the layout when expanding child views with
+     * weights (see {@link LayoutParams#setWeight}). If not set the default is 360 degrees. This
+     * target may not be achievable if other non-expandable views bring us past this value.
+     */
+    public void setMaxAngleDegrees(
+            @FloatRange(from = 0.0f, to = 360.0f, toInclusive = true)
+            float maxAngleDegrees) {
+        mMaxAngleDegrees = maxAngleDegrees;
+        invalidate();
+        requestLayout();
+    }
+
     /** returns the layout direction */
     public boolean isClockwise() {
         return mClockwise;
diff --git a/wear/wear/src/main/java/androidx/wear/widget/CurvedTextView.java b/wear/wear/src/main/java/androidx/wear/widget/CurvedTextView.java
index 3843c1e..b0f8c80 100644
--- a/wear/wear/src/main/java/androidx/wear/widget/CurvedTextView.java
+++ b/wear/wear/src/main/java/androidx/wear/widget/CurvedTextView.java
@@ -208,6 +208,13 @@
     }
 
     @Override
+    public void setSweepAngleDegrees(
+            @FloatRange(from = 0.0f, to = 360.0f, toInclusive = true) float angleDegrees) {
+        /** We need to be careful because this is also set by {@link #onMeasure} below. */
+        mBackgroundSweepDegrees = angleDegrees;
+    }
+
+    @Override
     @Px
     public int getThickness() {
         return round(mPaint.getFontMetrics().descent - mPaint.getFontMetrics().ascent);
@@ -724,6 +731,7 @@
 
     /**
      * Sets the anchor type for positioning the curved text.
+     *
      * @param value the anchor type,  one of {ANCHOR_START, ANCHOR_CENTER, ANCHOR_END}
      */
     public void setAnchorType(@ArcLayout.AnchorType int value) {
@@ -744,7 +752,9 @@
         doRedraw();
     }
 
-    /** Sets the minimum and maximum sweep angle in degrees for rendering the text.
+    /**
+     * Sets the minimum and maximum sweep angle in degrees for rendering the text.
+     *
      * @param minSweep Ensure the text takes at least this angle (in degrees) in the arc. Use 0f if
      *                 you don't want to specify a minimum.
      * @param maxSweep Limit the maximum angle (in degrees) that this curved text can take. Use
@@ -858,6 +868,7 @@
     /**
      * Gets the text letter-space value, which determines the spacing between characters. The
      * value returned is in ems. Normally, this value is 0.0.
+     *
      * @return The text letter-space value in ems.
      */
     public float getLetterSpacing() {
@@ -867,6 +878,7 @@
     /**
      * Sets text letter-spacing in ems. Typical values for slight expansion will be around 0.05.
      * Negative values tighten text.
+     *
      * @param value A text letter-space value in ems.
      */
     public void setLetterSpacing(float value) {
@@ -877,6 +889,7 @@
     /**
      * Returns the font feature settings. The format is the same as the CSS font-feature-settings
      * attribute: https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop
+     *
      * @return The currently set font feature settings. Default is null.
      */
     @Nullable
@@ -887,8 +900,9 @@
     /**
      * Sets font feature settings. The format is the same as the CSS font-feature-settings
      * attribute: https://www.w3.org/TR/css-fonts-3/#font-feature-settings-prop
+     *
      * @param value Font feature settings represented as CSS compatible string. This value may be
-     *             null.
+     *              null.
      */
     public void setFontFeatureSettings(@Nullable String value) {
         mFontFeatureSettings = value;
@@ -903,6 +917,7 @@
 
     /**
      * Sets TrueType or OpenType font variation settings.
+     *
      * @param value Font variation settings. You can pass null or empty string as no variation
      *              settings. This value may be null
      */
diff --git a/wear/wear/src/main/res/values/attrs.xml b/wear/wear/src/main/res/values/attrs.xml
index 5031503..6b1e004 100644
--- a/wear/wear/src/main/res/values/attrs.xml
+++ b/wear/wear/src/main/res/values/attrs.xml
@@ -275,6 +275,7 @@
             <enum name="center" value="1" />
             <enum name="inner" value="2" />
         </attr>
+        <attr name="layout_weight" format="float" />
     </declare-styleable>
 
     <declare-styleable name="ArcLayout">