Add pill shape and image button component to ProtoLayout Material3

Bug: 368258583
Test: Added unit. Screenshot will be added when more button types are added.
Relnote: "Added pill shape button and image button components to ProtoLayout Material3."

Change-Id: Ifb88aa0ebce1b3923f08c012b8e4d65735d0c49b
diff --git a/wear/protolayout/protolayout-material3/api/current.txt b/wear/protolayout/protolayout-material3/api/current.txt
index bf31c9b..e50b137 100644
--- a/wear/protolayout/protolayout-material3/api/current.txt
+++ b/wear/protolayout/protolayout-material3/api/current.txt
@@ -13,13 +13,15 @@
 
   public final class ButtonColors {
     ctor public ButtonColors();
-    ctor public ButtonColors(optional androidx.wear.protolayout.types.LayoutColor container, optional androidx.wear.protolayout.types.LayoutColor icon, optional androidx.wear.protolayout.types.LayoutColor label);
+    ctor public ButtonColors(optional androidx.wear.protolayout.types.LayoutColor container, optional androidx.wear.protolayout.types.LayoutColor icon, optional androidx.wear.protolayout.types.LayoutColor label, optional androidx.wear.protolayout.types.LayoutColor secondaryLabel);
     method public androidx.wear.protolayout.types.LayoutColor getContainer();
     method public androidx.wear.protolayout.types.LayoutColor getIcon();
     method public androidx.wear.protolayout.types.LayoutColor getLabel();
+    method public androidx.wear.protolayout.types.LayoutColor getSecondaryLabel();
     property public final androidx.wear.protolayout.types.LayoutColor container;
     property public final androidx.wear.protolayout.types.LayoutColor icon;
     property public final androidx.wear.protolayout.types.LayoutColor label;
+    property public final androidx.wear.protolayout.types.LayoutColor secondaryLabel;
   }
 
   public final class ButtonDefaults {
@@ -46,11 +48,22 @@
   }
 
   public final class ButtonKt {
-    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement button(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? content, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement button(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? secondaryLabelContent, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? iconContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.ButtonStyle style, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement iconButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> iconContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.IconButtonStyle style, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement imageButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> backgroundContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement textButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.TextButtonStyle style, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
   }
 
+  public final class ButtonStyle {
+    field public static final androidx.wear.protolayout.material3.ButtonStyle.Companion Companion;
+  }
+
+  public static final class ButtonStyle.Companion {
+    method public androidx.wear.protolayout.material3.ButtonStyle defaultButtonStyle();
+    method public androidx.wear.protolayout.material3.ButtonStyle largeButtonStyle();
+    method public androidx.wear.protolayout.material3.ButtonStyle smallButtonStyle();
+  }
+
   public final class CardColors {
     ctor public CardColors(androidx.wear.protolayout.types.LayoutColor background, androidx.wear.protolayout.types.LayoutColor title, androidx.wear.protolayout.types.LayoutColor content, optional androidx.wear.protolayout.types.LayoutColor time, optional androidx.wear.protolayout.types.LayoutColor label, optional androidx.wear.protolayout.types.LayoutColor secondaryIcon, optional androidx.wear.protolayout.types.LayoutColor secondaryText);
     method public androidx.wear.protolayout.types.LayoutColor getBackground();
diff --git a/wear/protolayout/protolayout-material3/api/restricted_current.txt b/wear/protolayout/protolayout-material3/api/restricted_current.txt
index bf31c9b..e50b137 100644
--- a/wear/protolayout/protolayout-material3/api/restricted_current.txt
+++ b/wear/protolayout/protolayout-material3/api/restricted_current.txt
@@ -13,13 +13,15 @@
 
   public final class ButtonColors {
     ctor public ButtonColors();
-    ctor public ButtonColors(optional androidx.wear.protolayout.types.LayoutColor container, optional androidx.wear.protolayout.types.LayoutColor icon, optional androidx.wear.protolayout.types.LayoutColor label);
+    ctor public ButtonColors(optional androidx.wear.protolayout.types.LayoutColor container, optional androidx.wear.protolayout.types.LayoutColor icon, optional androidx.wear.protolayout.types.LayoutColor label, optional androidx.wear.protolayout.types.LayoutColor secondaryLabel);
     method public androidx.wear.protolayout.types.LayoutColor getContainer();
     method public androidx.wear.protolayout.types.LayoutColor getIcon();
     method public androidx.wear.protolayout.types.LayoutColor getLabel();
+    method public androidx.wear.protolayout.types.LayoutColor getSecondaryLabel();
     property public final androidx.wear.protolayout.types.LayoutColor container;
     property public final androidx.wear.protolayout.types.LayoutColor icon;
     property public final androidx.wear.protolayout.types.LayoutColor label;
+    property public final androidx.wear.protolayout.types.LayoutColor secondaryLabel;
   }
 
   public final class ButtonDefaults {
@@ -46,11 +48,22 @@
   }
 
   public final class ButtonKt {
-    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement button(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? content, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement button(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? secondaryLabelContent, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? iconContent, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.ButtonStyle style, optional int horizontalAlignment, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement iconButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> iconContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.IconButtonStyle style, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
+    method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement imageButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> backgroundContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height);
     method public static androidx.wear.protolayout.LayoutElementBuilders.LayoutElement textButton(androidx.wear.protolayout.material3.MaterialScope, androidx.wear.protolayout.ModifiersBuilders.Clickable onClick, kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement> labelContent, optional androidx.wear.protolayout.modifiers.LayoutModifier modifier, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension width, optional androidx.wear.protolayout.DimensionBuilders.ContainerDimension height, optional androidx.wear.protolayout.ModifiersBuilders.Corner shape, optional androidx.wear.protolayout.material3.ButtonColors colors, optional kotlin.jvm.functions.Function1<? super androidx.wear.protolayout.material3.MaterialScope,? extends androidx.wear.protolayout.LayoutElementBuilders.LayoutElement>? backgroundContent, optional androidx.wear.protolayout.material3.TextButtonStyle style, optional androidx.wear.protolayout.ModifiersBuilders.Padding contentPadding);
   }
 
+  public final class ButtonStyle {
+    field public static final androidx.wear.protolayout.material3.ButtonStyle.Companion Companion;
+  }
+
+  public static final class ButtonStyle.Companion {
+    method public androidx.wear.protolayout.material3.ButtonStyle defaultButtonStyle();
+    method public androidx.wear.protolayout.material3.ButtonStyle largeButtonStyle();
+    method public androidx.wear.protolayout.material3.ButtonStyle smallButtonStyle();
+  }
+
   public final class CardColors {
     ctor public CardColors(androidx.wear.protolayout.types.LayoutColor background, androidx.wear.protolayout.types.LayoutColor title, androidx.wear.protolayout.types.LayoutColor content, optional androidx.wear.protolayout.types.LayoutColor time, optional androidx.wear.protolayout.types.LayoutColor label, optional androidx.wear.protolayout.types.LayoutColor secondaryIcon, optional androidx.wear.protolayout.types.LayoutColor secondaryText);
     method public androidx.wear.protolayout.types.LayoutColor getBackground();
diff --git a/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt b/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt
index 5e95dbf..fdb49cf 100644
--- a/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt
+++ b/wear/protolayout/protolayout-material3/samples/src/main/java/androidx/wear/protolayout/material3/samples/Material3ComponentsSample.kt
@@ -23,6 +23,7 @@
 import androidx.wear.protolayout.DimensionBuilders.expand
 import androidx.wear.protolayout.DimensionBuilders.weight
 import androidx.wear.protolayout.LayoutElementBuilders
+import androidx.wear.protolayout.LayoutElementBuilders.Box
 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
 import androidx.wear.protolayout.ModifiersBuilders
 import androidx.wear.protolayout.ModifiersBuilders.Clickable
@@ -49,6 +50,7 @@
 import androidx.wear.protolayout.material3.iconButton
 import androidx.wear.protolayout.material3.iconDataCard
 import androidx.wear.protolayout.material3.iconEdgeButton
+import androidx.wear.protolayout.material3.imageButton
 import androidx.wear.protolayout.material3.materialScope
 import androidx.wear.protolayout.material3.primaryLayout
 import androidx.wear.protolayout.material3.text
@@ -312,7 +314,7 @@
     }
 
 @Sampled
-fun buttonSample(
+fun customButtonSample(
     context: Context,
     deviceConfiguration: DeviceParameters,
     clickable: Clickable
@@ -320,6 +322,7 @@
     materialScope(context, deviceConfiguration) {
         primaryLayout(
             mainSlot = {
+                // Button with custom content inside
                 button(
                     onClick = clickable,
                     modifier =
@@ -327,7 +330,10 @@
                             .backgroundColor(colorScheme.primary),
                     width = expand(),
                     height = expand(),
-                    content = { text("Button!".layoutString) }
+                    labelContent = {
+                        // This can be further built.
+                        Box.Builder().build()
+                    }
                 )
             }
         )
@@ -395,7 +401,7 @@
     materialScope(context, deviceConfiguration) {
         primaryLayout(
             mainSlot = {
-                button(
+                imageButton(
                     onClick = clickable,
                     modifier =
                         LayoutModifier.contentDescription("Big button with image background"),
@@ -426,3 +432,25 @@
             size = dp(85F)
         )
     }
+
+@Sampled
+fun pillShapeButtonsSample(
+    context: Context,
+    deviceConfiguration: DeviceParameters,
+    clickable: Clickable
+): LayoutElement =
+    materialScope(context, deviceConfiguration) {
+        primaryLayout(
+            mainSlot = {
+                button(
+                    onClick = clickable,
+                    modifier = LayoutModifier.contentDescription("Pill shape button"),
+                    width = expand(),
+                    height = expand(),
+                    labelContent = { text("First label".layoutString) },
+                    secondaryLabelContent = { text("Second label".layoutString) },
+                    iconContent = { icon("id") }
+                )
+            }
+        )
+    }
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt
index 8fd28cf..2d79449 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/Button.kt
@@ -17,8 +17,12 @@
 package androidx.wear.protolayout.material3
 
 import androidx.wear.protolayout.DimensionBuilders.ContainerDimension
+import androidx.wear.protolayout.DimensionBuilders.dp
 import androidx.wear.protolayout.DimensionBuilders.expand
 import androidx.wear.protolayout.DimensionBuilders.weight
+import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_CENTER
+import androidx.wear.protolayout.LayoutElementBuilders.HORIZONTAL_ALIGN_START
+import androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignment
 import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
 import androidx.wear.protolayout.ModifiersBuilders.Clickable
 import androidx.wear.protolayout.ModifiersBuilders.Corner
@@ -26,7 +30,9 @@
 import androidx.wear.protolayout.material3.ButtonDefaults.DEFAULT_CONTENT_PADDING
 import androidx.wear.protolayout.material3.ButtonDefaults.IMAGE_BUTTON_DEFAULT_SIZE_DP
 import androidx.wear.protolayout.material3.ButtonDefaults.METADATA_TAG_BUTTON
+import androidx.wear.protolayout.material3.ButtonDefaults.buildContentForPillShapeButton
 import androidx.wear.protolayout.material3.ButtonDefaults.filledButtonColors
+import androidx.wear.protolayout.material3.ButtonStyle.Companion.defaultButtonStyle
 import androidx.wear.protolayout.material3.IconButtonStyle.Companion.defaultIconButtonStyle
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.defaultTextButtonStyle
 import androidx.wear.protolayout.modifiers.LayoutModifier
@@ -61,7 +67,7 @@
  *   [backgroundImage] with the content. It can be combined with the specified
  *   [ButtonColors.container] behind it.
  * @param style The style which provides the attribute values required for constructing this icon
- *   button its inner content. It also provides default style for the inner content, that can be
+ *   button and its inner content. It also provides default style for the inner content, that can be
  *   overridden by each content slot.
  * @param contentPadding The inner padding used to prevent inner content from being too close to the
  *   button's edge. It's highly recommended to keep the default.
@@ -81,9 +87,9 @@
     colors: ButtonColors = filledButtonColors(),
     backgroundContent: (MaterialScope.() -> LayoutElement)? = null,
     style: IconButtonStyle = defaultIconButtonStyle(),
-    contentPadding: Padding = DEFAULT_CONTENT_PADDING
+    contentPadding: Padding = style.innerPadding
 ): LayoutElement =
-    button(
+    buttonContainer(
         onClick = onClick,
         modifier = modifier.background(color = colors.container, corner = shape),
         width = width,
@@ -92,8 +98,7 @@
         contentPadding = contentPadding,
         content = {
             withStyle(
-                    defaultIconStyle =
-                        IconStyle(size = style.iconSize.toDp(), tintColor = colors.icon)
+                    defaultIconStyle = IconStyle(size = dp(style.iconSize), tintColor = colors.icon)
                 )
                 .iconContent()
         }
@@ -125,14 +130,14 @@
  *   recommended to use the default styling that is automatically provided by only calling
  *   [backgroundImage] with the content. It can be combined with the specified
  *   [ButtonColors.container] behind it.
- * @param style The style which provides the attribute values required for constructing this icon
- *   button its inner content. It also provides default style for the inner content, that can be
+ * @param style The style which provides the attribute values required for constructing this text
+ *   button and its inner content. It also provides default style for the inner content, that can be
  *   overridden by each content slot.
  * @param contentPadding The inner padding used to prevent inner content from being too close to the
  *   button's edge. It's highly recommended to keep the default.
  * @param labelContent The text slot for content displayed in this button. It is recommended to use
- *   default styling that is automatically provided by only calling [text] with the resource ID.
- *   This should be small, usually up to 3 characters text.
+ *   default styling that is automatically provided by only calling [text]. This should be small
+ *   text, usually up to 3 characters text.
  * @sample androidx.wear.protolayout.material3.samples.oneSlotButtonsSample
  */
 // TODO: b/346958146 - Link Button visuals in DAC
@@ -147,9 +152,9 @@
     colors: ButtonColors = filledButtonColors(),
     backgroundContent: (MaterialScope.() -> LayoutElement)? = null,
     style: TextButtonStyle = defaultTextButtonStyle(),
-    contentPadding: Padding = DEFAULT_CONTENT_PADDING
+    contentPadding: Padding = style.innerPadding
 ): LayoutElement =
-    button(
+    buttonContainer(
         onClick = onClick,
         modifier = modifier.background(color = colors.container, corner = shape),
         width = width,
@@ -166,6 +171,149 @@
     )
 
 /**
+ * Opinionated ProtoLayout Material3 pill shape button that offers up to three slots to take content
+ * representing vertically stacked label and secondary label, and an icon next to it.
+ *
+ * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
+ *   the associated action.
+ * @param labelContent The text slot for content displayed in this button. It is recommended to use
+ *   default styling that is automatically provided by only calling [text].
+ * @param modifier Modifiers to set to this element. It's highly recommended to set a content
+ *   description using [contentDescription].
+ * @param secondaryLabelContent The text slot for content displayed in this button. It is
+ *   recommended to use default styling that is automatically provided by only calling [text].
+ * @param iconContent The icon slot for content displayed in this button. It is recommended to use
+ *   default styling that is automatically provided by only calling [icon] with the resource ID.
+ * @param shape Defines the button's shape, in other words the corner radius for this button.
+ * @param width The width of this button. It's highly recommended to set this to [expand] or
+ *   [weight]
+ * @param height The height of this button. It's highly recommended to set this to [expand] or
+ *   [weight]
+ * @param colors The colors used for this button. If not set, [ButtonDefaults.filledButtonColors]
+ *   will be used as high emphasis button. Other recommended colors are
+ *   [ButtonDefaults.filledTonalButtonColors] and [ButtonDefaults.filledVariantButtonColors]. If
+ *   using custom colors, it is important to choose a color pair from same role to ensure
+ *   accessibility with sufficient color contrast.
+ * @param backgroundContent The background object to be used behind the content in the button. It is
+ *   recommended to use the default styling that is automatically provided by only calling
+ *   [backgroundImage] with the content. It can be combined with the specified
+ *   [ButtonColors.container] behind it.
+ * @param style The style which provides the attribute values required for constructing this pill
+ *   shape button and its inner content. It also provides default style for the inner content, that
+ *   can be overridden by each content slot.
+ * @param horizontalAlignment The horizontal placement of the [labelContent] and
+ *   [secondaryLabelContent] content. If [iconContent] is present, this should be
+ *   [HORIZONTAL_ALIGN_START]. Defaults to [HORIZONTAL_ALIGN_CENTER] if only [labelContent] is
+ *   present, otherwise it default to [HORIZONTAL_ALIGN_START].
+ * @param contentPadding The inner padding used to prevent inner content from being too close to the
+ *   button's edge. It's highly recommended to keep the default.
+ * @sample androidx.wear.protolayout.material3.samples.pillShapeButtonsSample
+ * @sample androidx.wear.protolayout.material3.samples.customButtonSample
+ */
+// TODO: b/346958146 - Link Button visuals in DAC
+// TODO: b/373578620 - Add how corners affects margins in the layout.
+public fun MaterialScope.button(
+    onClick: Clickable,
+    labelContent: (MaterialScope.() -> LayoutElement),
+    modifier: LayoutModifier = LayoutModifier,
+    secondaryLabelContent: (MaterialScope.() -> LayoutElement)? = null,
+    iconContent: (MaterialScope.() -> LayoutElement)? = null,
+    width: ContainerDimension = wrapWithMinTapTargetDimension(),
+    height: ContainerDimension = wrapWithMinTapTargetDimension(),
+    shape: Corner = shapes.full,
+    colors: ButtonColors = filledButtonColors(),
+    backgroundContent: (MaterialScope.() -> LayoutElement)? = null,
+    style: ButtonStyle = defaultButtonStyle(),
+    @HorizontalAlignment
+    horizontalAlignment: Int =
+        if (iconContent == null && secondaryLabelContent == null) HORIZONTAL_ALIGN_CENTER
+        else HORIZONTAL_ALIGN_START,
+    contentPadding: Padding = style.innerPadding
+): LayoutElement =
+    buttonContainer(
+        onClick = onClick,
+        modifier = modifier.background(color = colors.container, corner = shape),
+        width = width,
+        height = height,
+        backgroundContent = backgroundContent,
+        contentPadding = contentPadding,
+        content = {
+            buildContentForPillShapeButton(
+                label =
+                    withStyle(
+                            defaultTextElementStyle =
+                                TextElementStyle(
+                                    typography = style.labelTypography,
+                                    color = colors.label
+                                )
+                        )
+                        .labelContent(),
+                secondaryLabel =
+                    secondaryLabelContent?.let {
+                        withStyle(
+                                defaultTextElementStyle =
+                                    TextElementStyle(
+                                        typography = style.secondaryLabelTypography,
+                                        color = colors.secondaryLabel
+                                    )
+                            )
+                            .secondaryLabelContent()
+                    },
+                icon =
+                    iconContent?.let {
+                        withStyle(
+                                defaultIconStyle =
+                                    IconStyle(size = dp(style.iconSize), tintColor = colors.icon)
+                            )
+                            .iconContent()
+                    },
+                horizontalAlignment = horizontalAlignment,
+                style = style
+            )
+        }
+    )
+
+/**
+ * ProtoLayout Material3 clickable image button that doesn't offer additional slots, only image (for
+ * example [backgroundImage] as a background.
+ *
+ * The button is usually stadium or circle shaped with fully rounded corners by default. It is
+ * highly recommended to set its width and height to fill the available space, by [expand] or
+ * [weight] for optimal experience across different screen sizes, and use [buttonGroup] to arrange
+ * them.
+ *
+ * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
+ *   the associated action.
+ * @param modifier Modifiers to set to this element. It's highly recommended to set a content
+ *   description using [contentDescription]. If [LayoutModifier.background] modifier is used and the
+ *   the background image is also specified, the image will be laid out on top of this color. In
+ *   case of the fully opaque background image, then the background color will not be shown.
+ * @param backgroundContent The background object to be used behind the content in the button. It is
+ *   recommended to use the default styling that is automatically provided by only calling
+ *   [backgroundImage] with the content. It can be combined with the specified
+ *   [LayoutModifier.background] behind it.
+ * @param width The width of this button. It's highly recommended to set this to [expand] or
+ *   [weight]
+ * @param height The height of this button. It's highly recommended to set this to [expand] or
+ *   [weight]
+ * @sample androidx.wear.protolayout.material3.samples.imageButtonSample
+ */
+public fun MaterialScope.imageButton(
+    onClick: Clickable,
+    backgroundContent: (MaterialScope.() -> LayoutElement),
+    modifier: LayoutModifier = LayoutModifier,
+    width: ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp(),
+    height: ContainerDimension = IMAGE_BUTTON_DEFAULT_SIZE_DP.toDp()
+): LayoutElement =
+    buttonContainer(
+        onClick = onClick,
+        modifier = modifier,
+        width = width,
+        height = height,
+        backgroundContent = backgroundContent
+    )
+
+/**
  * ProtoLayout Material3 clickable component button that offers a single slot to take any content.
  *
  * The button is usually stadium or circle shaped with fully rounded corners by default. It is
@@ -175,9 +323,6 @@
  *
  * It can be used for displaying any clickable container with additional data, text or images.
  *
- * This button can also be used to create image button that only has a background image and no inner
- * content, see [androidx.wear.protolayout.material3.samples.imageButtonSample]
- *
  * @param onClick Associated [Clickable] for click events. When the button is clicked it will fire
  *   the associated action.
  * @param modifier Modifiers to set to this element. It's highly recommended to set a content
@@ -195,12 +340,8 @@
  * @param contentPadding The inner padding used to prevent inner content from being too close to the
  *   button's edge. It's highly recommended to keep the default.
  * @param content The inner content to be put inside of this button.
- * @sample androidx.wear.protolayout.material3.samples.buttonSample
- * @sample androidx.wear.protolayout.material3.samples.imageButtonSample
  */
-// TODO: b/346958146 - Link Button visuals in DAC
-// TODO: b/373578620 - Add how corners affects margins in the layout.
-public fun MaterialScope.button(
+internal fun MaterialScope.buttonContainer(
     onClick: Clickable,
     modifier: LayoutModifier = LayoutModifier,
     content: (MaterialScope.() -> LayoutElement)? = null,
diff --git a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt
index f105a4b..b2d21fd 100644
--- a/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt
+++ b/wear/protolayout/protolayout-material3/src/main/java/androidx/wear/protolayout/material3/ButtonDefaults.kt
@@ -19,6 +19,11 @@
 import android.graphics.Color
 import androidx.annotation.Dimension
 import androidx.annotation.Dimension.Companion.DP
+import androidx.wear.protolayout.DimensionBuilders.expand
+import androidx.wear.protolayout.LayoutElementBuilders.Column
+import androidx.wear.protolayout.LayoutElementBuilders.HorizontalAlignment
+import androidx.wear.protolayout.LayoutElementBuilders.LayoutElement
+import androidx.wear.protolayout.LayoutElementBuilders.Row
 import androidx.wear.protolayout.ModifiersBuilders.Padding
 import androidx.wear.protolayout.material3.ButtonDefaults.DEFAULT_CONTENT_PADDING
 import androidx.wear.protolayout.material3.Typography.TypographyToken
@@ -37,10 +42,41 @@
     public val icon: LayoutColor = Color.BLACK.argb,
     /** The label color to be used for a button. */
     public val label: LayoutColor = Color.BLACK.argb,
+    /** The secondary label color to be used for a button. */
+    public val secondaryLabel: LayoutColor = Color.BLACK.argb,
 )
 
 public object ButtonDefaults {
     /**
+     * Returns [LayoutElement] describing the inner content for the pill shape button.
+     *
+     * This is a [Row] containing the following:
+     * * icon
+     * * spacing if icon is present
+     * * labels that are in [Column]
+     */
+    internal fun buildContentForPillShapeButton(
+        label: LayoutElement,
+        secondaryLabel: LayoutElement?,
+        icon: LayoutElement?,
+        @HorizontalAlignment horizontalAlignment: Int,
+        style: ButtonStyle
+    ): LayoutElement {
+        val labels: Column.Builder =
+            Column.Builder().setWidth(expand()).setHorizontalAlignment(horizontalAlignment)
+
+        val row: Row.Builder = Row.Builder()
+
+        ContainerWithSpacersBuilder<LayoutElement>(labels::addContent, label)
+            .addElement(secondaryLabel, horizontalSpacer(style.labelsSpaceDp))
+
+        ContainerWithSpacersBuilder<LayoutElement>(row::addContent, icon)
+            .addElement(labels.build(), verticalSpacer(style.iconToLabelsSpaceDp))
+
+        return row.build()
+    }
+
+    /**
      * [ButtonColors] for the high-emphasis button representing the primary, most important or most
      * common action on a screen.
      *
@@ -51,7 +87,8 @@
         ButtonColors(
             container = theme.colorScheme.primary,
             icon = theme.colorScheme.onPrimary,
-            label = theme.colorScheme.onPrimary
+            label = theme.colorScheme.onPrimary,
+            secondaryLabel = theme.colorScheme.onPrimary.withOpacity(0.8f)
         )
 
     /**
@@ -64,7 +101,8 @@
         ButtonColors(
             container = theme.colorScheme.surfaceContainer,
             icon = theme.colorScheme.primary,
-            label = theme.colorScheme.onSurface
+            label = theme.colorScheme.onSurface,
+            secondaryLabel = theme.colorScheme.onSurfaceVariant
         )
 
     /**
@@ -77,7 +115,8 @@
         ButtonColors(
             container = theme.colorScheme.primaryContainer,
             icon = theme.colorScheme.onPrimaryContainer,
-            label = theme.colorScheme.onPrimaryContainer
+            label = theme.colorScheme.onPrimaryContainer,
+            secondaryLabel = theme.colorScheme.onPrimaryContainer.withOpacity(0.9f)
         )
 
     internal const val METADATA_TAG_BUTTON: String = "BTN"
@@ -88,7 +127,7 @@
 /** Provides style values for the icon button component. */
 public class IconButtonStyle
 internal constructor(
-    @Dimension(unit = DP) internal val iconSize: Int,
+    @Dimension(unit = DP) internal val iconSize: Float,
     internal val innerPadding: Padding = DEFAULT_CONTENT_PADDING
 ) {
     public companion object {
@@ -96,13 +135,13 @@
          * Default style variation for the [iconButton] where all opinionated inner content is
          * displayed in a medium size.
          */
-        public fun defaultIconButtonStyle(): IconButtonStyle = IconButtonStyle(26)
+        public fun defaultIconButtonStyle(): IconButtonStyle = IconButtonStyle(26f)
 
         /**
          * Default style variation for the [iconButton] where all opinionated inner content is
          * displayed in a large size.
          */
-        public fun largeIconButtonStyle(): IconButtonStyle = IconButtonStyle(32)
+        public fun largeIconButtonStyle(): IconButtonStyle = IconButtonStyle(32f)
     }
 }
 
@@ -142,3 +181,58 @@
             TextButtonStyle(Typography.DISPLAY_MEDIUM)
     }
 }
+
+/** Provides style values for the pill shape button component. */
+public class ButtonStyle
+internal constructor(
+    @TypographyToken internal val labelTypography: Int,
+    @TypographyToken internal val secondaryLabelTypography: Int,
+    @Dimension(DP) internal val iconSize: Float,
+    internal val innerPadding: Padding,
+    @Dimension(DP) internal val labelsSpaceDp: Int,
+    @Dimension(DP) internal val iconToLabelsSpaceDp: Int,
+) {
+    public companion object {
+        /**
+         * Default style variation for the [button] where all opinionated inner content is displayed
+         * in a small size.
+         */
+        public fun smallButtonStyle(): ButtonStyle =
+            ButtonStyle(
+                labelTypography = Typography.LABEL_MEDIUM,
+                secondaryLabelTypography = Typography.BODY_SMALL,
+                iconSize = 24f,
+                innerPadding = padding(horizontal = 14f, vertical = 10f),
+                labelsSpaceDp = 2,
+                iconToLabelsSpaceDp = 6
+            )
+
+        /**
+         * Default style variation for the [button] where all opinionated inner content is displayed
+         * in a medium size.
+         */
+        public fun defaultButtonStyle(): ButtonStyle =
+            ButtonStyle(
+                labelTypography = Typography.TITLE_MEDIUM,
+                secondaryLabelTypography = Typography.LABEL_SMALL,
+                iconSize = 26f,
+                innerPadding = padding(horizontal = 14f, vertical = 6f),
+                labelsSpaceDp = 0,
+                iconToLabelsSpaceDp = 8
+            )
+
+        /**
+         * Default style variation for the [button] where all opinionated inner content is displayed
+         * in a large size.
+         */
+        public fun largeButtonStyle(): ButtonStyle =
+            ButtonStyle(
+                labelTypography = Typography.LABEL_LARGE,
+                secondaryLabelTypography = Typography.LABEL_SMALL,
+                iconSize = 32f,
+                innerPadding = padding(horizontal = 14f, vertical = 8f),
+                labelsSpaceDp = 0,
+                iconToLabelsSpaceDp = 10
+            )
+    }
+}
diff --git a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt
index e56e836..e2967af 100644
--- a/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt
+++ b/wear/protolayout/protolayout-material3/src/test/java/androidx/wear/protolayout/material3/ButtonTest.kt
@@ -72,12 +72,22 @@
     }
 
     @Test
+    fun pillButton_size_default() {
+        LayoutElementAssertionsProvider(DEFAULT_BUTTON)
+            .onRoot()
+            .assert(hasWidth(wrapWithMinTapTargetDimension()))
+            .assert(hasHeight(wrapWithMinTapTargetDimension()))
+            .assert(hasTag(ButtonDefaults.METADATA_TAG_BUTTON))
+    }
+
+    @Test
     fun imageButton_size_default() {
         LayoutElementAssertionsProvider(
                 materialScope(CONTEXT, DEVICE_CONFIGURATION) {
-                    button(
+                    imageButton(
                         onClick = CLICKABLE,
-                        modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION)
+                        modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION),
+                        backgroundContent = { backgroundImage(IMAGE_ID) }
                     )
                 }
             )
@@ -122,10 +132,25 @@
     }
 
     @Test
-    fun containerButton_hasBackgroundImage() {
+    fun pillButton_hasLabel_asText() {
+        LayoutElementAssertionsProvider(DEFAULT_BUTTON).onElement(hasText(TEXT)).assertExists()
+    }
+
+    @Test
+    fun pillButton_hasSecondaryLabel_asText() {
+        LayoutElementAssertionsProvider(DEFAULT_BUTTON).onElement(hasText(TEXT2)).assertExists()
+    }
+
+    @Test
+    fun pillButton_hasIcon_asIcon() {
+        LayoutElementAssertionsProvider(DEFAULT_BUTTON).onElement(hasImage(ICON_ID)).assertExists()
+    }
+
+    @Test
+    fun imageButton_hasBackgroundImage() {
         val button =
             materialScope(CONTEXT, DEVICE_CONFIGURATION) {
-                button(
+                imageButton(
                     onClick = CLICKABLE,
                     modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION),
                     backgroundContent = { backgroundImage(IMAGE_ID) }
@@ -143,7 +168,7 @@
         val color = Color.YELLOW
         val button =
             materialScope(CONTEXT, DEVICE_CONFIGURATION) {
-                button(
+                buttonContainer(
                     onClick = CLICKABLE,
                     modifier =
                         LayoutModifier.contentDescription(CONTENT_DESCRIPTION)
@@ -165,7 +190,7 @@
         val height = 12
         val button =
             materialScope(CONTEXT, DEVICE_CONFIGURATION) {
-                button(
+                buttonContainer(
                     onClick = CLICKABLE,
                     modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION),
                     width = expand(),
@@ -199,10 +224,11 @@
         private const val ICON_ID = "id"
 
         private const val TEXT = "Container button"
+        private const val TEXT2 = "Secondary label"
 
         private val DEFAULT_CONTAINER_BUTTON_WITH_TEXT =
             materialScope(CONTEXT, DEVICE_CONFIGURATION) {
-                button(
+                buttonContainer(
                     onClick = CLICKABLE,
                     modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION),
                     content = { text(TEXT.layoutString) }
@@ -226,5 +252,16 @@
                     labelContent = { text(TEXT.layoutString) }
                 )
             }
+
+        private val DEFAULT_BUTTON =
+            materialScope(CONTEXT, DEVICE_CONFIGURATION) {
+                button(
+                    onClick = CLICKABLE,
+                    modifier = LayoutModifier.contentDescription(CONTENT_DESCRIPTION),
+                    labelContent = { text(TEXT.layoutString) },
+                    secondaryLabelContent = { text(TEXT2.layoutString) },
+                    iconContent = { icon(ICON_ID) }
+                )
+            }
     }
 }
diff --git a/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt b/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt
index 7e18422..f13f469 100644
--- a/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt
+++ b/wear/tiles/tiles-samples/src/main/java/androidx/wear/tiles/samples/tile/PlaygroundTileService.kt
@@ -37,6 +37,7 @@
 import androidx.wear.protolayout.material3.TextButtonStyle.Companion.smallTextButtonStyle
 import androidx.wear.protolayout.material3.appCard
 import androidx.wear.protolayout.material3.avatarImage
+import androidx.wear.protolayout.material3.button
 import androidx.wear.protolayout.material3.buttonGroup
 import androidx.wear.protolayout.material3.graphicDataCard
 import androidx.wear.protolayout.material3.icon
@@ -133,6 +134,16 @@
         )
     }
 
+private fun MaterialScope.pillShapeButton() =
+    button(
+        onClick = clickable(),
+        modifier = LayoutModifier.contentDescription("Pill button"),
+        width = expand(),
+        iconContent = { icon(ICON_ID) },
+        labelContent = { text("Primary label".layoutString) },
+        secondaryLabelContent = { text("Secondary label".layoutString) },
+    )
+
 private fun MaterialScope.oneSlotButtons() = buttonGroup {
     buttonGroupItem {
         iconButton(