public final class

LayoutElementBuilders

extends java.lang.Object

 java.lang.Object

↳androidx.wear.tiles.builders.LayoutElementBuilders

Gradle dependencies

compile group: 'androidx.wear', name: 'wear-tiles', version: '1.0.0-alpha01'

  • groupId: androidx.wear
  • artifactId: wear-tiles
  • version: 1.0.0-alpha01

Artifact androidx.wear:wear-tiles:1.0.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

Builders for composable layout elements that can be combined together to create renderable UI layouts.

Summary

Fields
public static final intARC_ANCHOR_CENTER

Anchor at the center of the elements.

public static final intARC_ANCHOR_END

Anchor at the end of the elements.

public static final intARC_ANCHOR_START

Anchor at the start of the elements.

public static final intARC_ANCHOR_UNDEFINED

Anchor position is undefined.

public static final intCONTENT_SCALE_MODE_CROP

Content will be resized proportionally so it completely fills its bounds, and anything outside of the bounds will be cropped.

public static final intCONTENT_SCALE_MODE_FILL_BOUNDS

Content will be resized to fill its bounds, without taking into account the aspect ratio.

public static final intCONTENT_SCALE_MODE_FIT

Content will be scaled to fit inside its bounds, proportionally.

public static final intCONTENT_SCALE_MODE_UNDEFINED

Content scaling is undefined.

public static final intFONT_WEIGHT_BOLD

Bold font weight.

public static final intFONT_WEIGHT_NORMAL

Normal font weight.

public static final intFONT_WEIGHT_UNDEFINED

Font weight is undefined.

public static final intHALIGN_CENTER

Horizontally align to center.

public static final intHALIGN_END

Horizontally align to the content end (right in LTR layouts, left in RTL layouts).

public static final intHALIGN_LEFT

Horizontally align to the left.

public static final intHALIGN_RIGHT

Horizontally align to the right.

public static final intHALIGN_START

Horizontally align to the content start (left in LTR layouts, right in RTL layouts).

public static final intHALIGN_UNDEFINED

Horizontal alignment is undefined.

public static final intTEXT_ALIGN_CENTER

Align to the center of the LayoutElementBuilders.Text element.

public static final intTEXT_ALIGN_END

Align to the "end" of the LayoutElementBuilders.Text element (right in LTR layouts, left in RTL layouts).

public static final intTEXT_ALIGN_START

Align to the "start" of the LayoutElementBuilders.Text element (left in LTR layouts, right in RTL layouts).

public static final intTEXT_ALIGN_UNDEFINED

Alignment is undefined.

public static final intTEXT_OVERFLOW_ELLIPSIZE_END

Truncate the text to fit in the LayoutElementBuilders.Text element's bounds, but add an ellipsis (i.e.

public static final intTEXT_OVERFLOW_TRUNCATE

Truncate the text to fit inside of the LayoutElementBuilders.Text element's bounds.

public static final intTEXT_OVERFLOW_UNDEFINED

Overflow behavior is undefined.

public static final intVALIGN_BOTTOM

Vertically align to the bottom.

public static final intVALIGN_CENTER

Vertically align to center.

public static final intVALIGN_TOP

Vertically align to the top.

public static final intVALIGN_UNDEFINED

Vertical alignment is undefined.

Methods
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Fields

public static final int HALIGN_UNDEFINED

Horizontal alignment is undefined.

public static final int HALIGN_LEFT

Horizontally align to the left.

public static final int HALIGN_CENTER

Horizontally align to center.

public static final int HALIGN_RIGHT

Horizontally align to the right.

public static final int HALIGN_START

Horizontally align to the content start (left in LTR layouts, right in RTL layouts).

public static final int HALIGN_END

Horizontally align to the content end (right in LTR layouts, left in RTL layouts).

public static final int VALIGN_UNDEFINED

Vertical alignment is undefined.

public static final int VALIGN_TOP

Vertically align to the top.

public static final int VALIGN_CENTER

Vertically align to center.

public static final int VALIGN_BOTTOM

Vertically align to the bottom.

public static final int FONT_WEIGHT_UNDEFINED

Font weight is undefined.

public static final int FONT_WEIGHT_NORMAL

Normal font weight.

public static final int FONT_WEIGHT_BOLD

Bold font weight.

public static final int TEXT_ALIGN_UNDEFINED

Alignment is undefined.

public static final int TEXT_ALIGN_START

Align to the "start" of the LayoutElementBuilders.Text element (left in LTR layouts, right in RTL layouts).

public static final int TEXT_ALIGN_CENTER

Align to the center of the LayoutElementBuilders.Text element.

public static final int TEXT_ALIGN_END

Align to the "end" of the LayoutElementBuilders.Text element (right in LTR layouts, left in RTL layouts).

public static final int TEXT_OVERFLOW_UNDEFINED

Overflow behavior is undefined.

public static final int TEXT_OVERFLOW_TRUNCATE

Truncate the text to fit inside of the LayoutElementBuilders.Text element's bounds. If text is truncated, it will be truncated on a word boundary.

public static final int TEXT_OVERFLOW_ELLIPSIZE_END

Truncate the text to fit in the LayoutElementBuilders.Text element's bounds, but add an ellipsis (i.e. ...) to the end of the text if it has been truncated.

public static final int ARC_ANCHOR_UNDEFINED

Anchor position is undefined.

public static final int ARC_ANCHOR_START

Anchor at the start of the elements. This will cause elements added to an arc to begin at the given anchor_angle, and sweep around to the right.

public static final int ARC_ANCHOR_CENTER

Anchor at the center of the elements. This will cause the center of the whole set of elements added to an arc to be pinned at the given anchor_angle.

public static final int ARC_ANCHOR_END

Anchor at the end of the elements. This will cause the set of elements inside the arc to end at the specified anchor_angle, i.e. all elements should be to the left of anchor_angle.

public static final int CONTENT_SCALE_MODE_UNDEFINED

Content scaling is undefined.

public static final int CONTENT_SCALE_MODE_FIT

Content will be scaled to fit inside its bounds, proportionally. As an example, If a 10x5 image was going to be drawn inside a 50x50 LayoutElementBuilders.Image element, the actual image resource would be drawn as a 50x25 image, centered within the 50x50 bounds.

public static final int CONTENT_SCALE_MODE_CROP

Content will be resized proportionally so it completely fills its bounds, and anything outside of the bounds will be cropped. As an example, if a 10x5 image was going to be drawn inside a 50x50 LayoutElementBuilders.Image element, the image resource would be drawn as a 100x50 image, centered within its bounds (and with 25px cropped from both the left and right sides).

public static final int CONTENT_SCALE_MODE_FILL_BOUNDS

Content will be resized to fill its bounds, without taking into account the aspect ratio. If a 10x5 image was going to be drawn inside a 50x50 LayoutElementBuilders.Image element, the image would be drawn as a 50x50 image, stretched vertically.

Source

/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.wear.tiles.builders;

import android.annotation.SuppressLint;

import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.tiles.builders.ColorBuilders.ColorProp;
import androidx.wear.tiles.builders.DimensionBuilders.ContainerDimension;
import androidx.wear.tiles.builders.DimensionBuilders.DegreesProp;
import androidx.wear.tiles.builders.DimensionBuilders.DpProp;
import androidx.wear.tiles.builders.DimensionBuilders.EmProp;
import androidx.wear.tiles.builders.DimensionBuilders.ImageDimension;
import androidx.wear.tiles.builders.DimensionBuilders.SpProp;
import androidx.wear.tiles.builders.DimensionBuilders.SpacerDimension;
import androidx.wear.tiles.builders.ModifiersBuilders.ArcModifiers;
import androidx.wear.tiles.builders.ModifiersBuilders.Modifiers;
import androidx.wear.tiles.builders.ModifiersBuilders.SpanModifiers;
import androidx.wear.tiles.proto.LayoutElementProto;
import androidx.wear.tiles.proto.TypesProto;
import androidx.wear.tiles.readers.DeviceParametersReaders.DeviceParameters;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Builders for composable layout elements that can be combined together to create renderable UI
 * layouts.
 */
public final class LayoutElementBuilders {
    private LayoutElementBuilders() {}

    /**
     * The horizontal alignment of an element within its container.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({HALIGN_UNDEFINED, HALIGN_LEFT, HALIGN_CENTER, HALIGN_RIGHT, HALIGN_START, HALIGN_END})
    @Retention(RetentionPolicy.SOURCE)
    public @interface HorizontalAlignment {}

    /** Horizontal alignment is undefined. */
    public static final int HALIGN_UNDEFINED = 0;

    /** Horizontally align to the left. */
    public static final int HALIGN_LEFT = 1;

    /** Horizontally align to center. */
    public static final int HALIGN_CENTER = 2;

    /** Horizontally align to the right. */
    public static final int HALIGN_RIGHT = 3;

    /** Horizontally align to the content start (left in LTR layouts, right in RTL layouts). */
    public static final int HALIGN_START = 4;

    /** Horizontally align to the content end (right in LTR layouts, left in RTL layouts). */
    public static final int HALIGN_END = 5;

    /**
     * The vertical alignment of an element within its container.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({VALIGN_UNDEFINED, VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM})
    @Retention(RetentionPolicy.SOURCE)
    public @interface VerticalAlignment {}

    /** Vertical alignment is undefined. */
    public static final int VALIGN_UNDEFINED = 0;

    /** Vertically align to the top. */
    public static final int VALIGN_TOP = 1;

    /** Vertically align to center. */
    public static final int VALIGN_CENTER = 2;

    /** Vertically align to the bottom. */
    public static final int VALIGN_BOTTOM = 3;

    /**
     * The weight to be applied to the font.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({FONT_WEIGHT_UNDEFINED, FONT_WEIGHT_NORMAL, FONT_WEIGHT_BOLD})
    @Retention(RetentionPolicy.SOURCE)
    public @interface FontWeight {}

    /** Font weight is undefined. */
    public static final int FONT_WEIGHT_UNDEFINED = 0;

    /** Normal font weight. */
    public static final int FONT_WEIGHT_NORMAL = 400;

    /** Bold font weight. */
    public static final int FONT_WEIGHT_BOLD = 700;

    /**
     * Alignment of a text element.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({TEXT_ALIGN_UNDEFINED, TEXT_ALIGN_START, TEXT_ALIGN_CENTER, TEXT_ALIGN_END})
    @Retention(RetentionPolicy.SOURCE)
    public @interface TextAlignment {}

    /** Alignment is undefined. */
    public static final int TEXT_ALIGN_UNDEFINED = 0;

    /**
     * Align to the "start" of the {@link Text} element (left in LTR layouts, right in RTL layouts).
     */
    public static final int TEXT_ALIGN_START = 1;

    /** Align to the center of the {@link Text} element. */
    public static final int TEXT_ALIGN_CENTER = 2;

    /**
     * Align to the "end" of the {@link Text} element (right in LTR layouts, left in RTL layouts).
     */
    public static final int TEXT_ALIGN_END = 3;

    /**
     * How text that will not fit inside the bounds of a {@link Text} element will be handled.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({TEXT_OVERFLOW_UNDEFINED, TEXT_OVERFLOW_TRUNCATE, TEXT_OVERFLOW_ELLIPSIZE_END})
    @Retention(RetentionPolicy.SOURCE)
    public @interface TextOverflow {}

    /** Overflow behavior is undefined. */
    public static final int TEXT_OVERFLOW_UNDEFINED = 0;

    /**
     * Truncate the text to fit inside of the {@link Text} element's bounds. If text is truncated,
     * it will be truncated on a word boundary.
     */
    public static final int TEXT_OVERFLOW_TRUNCATE = 1;

    /**
     * Truncate the text to fit in the {@link Text} element's bounds, but add an ellipsis (i.e. ...)
     * to the end of the text if it has been truncated.
     */
    public static final int TEXT_OVERFLOW_ELLIPSIZE_END = 2;

    /**
     * The anchor position of an {@link Arc}'s elements. This is used to specify how elements added
     * to an {@link Arc} should be laid out with respect to anchor_angle.
     *
     * <p>As an example, assume that the following diagrams are wrapped to an arc, and each
     * represents an {@link Arc} element containing a single {@link Text} element. The {@link Text}
     * element's anchor_angle is "0" for all cases.
     *
     * <pre>{@code
     * ARC_ANCHOR_START:
     * -180                                0                                    180
     *                                     Hello World!
     *
     *
     * ARC_ANCHOR_CENTER:
     * -180                                0                                    180
     *                                Hello World!
     *
     * ARC_ANCHOR_END:
     * -180                                0                                    180
     *                          Hello World!
     *
     * }</pre>
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({ARC_ANCHOR_UNDEFINED, ARC_ANCHOR_START, ARC_ANCHOR_CENTER, ARC_ANCHOR_END})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ArcAnchorType {}

    /** Anchor position is undefined. */
    public static final int ARC_ANCHOR_UNDEFINED = 0;

    /**
     * Anchor at the start of the elements. This will cause elements added to an arc to begin at the
     * given anchor_angle, and sweep around to the right.
     */
    public static final int ARC_ANCHOR_START = 1;

    /**
     * Anchor at the center of the elements. This will cause the center of the whole set of elements
     * added to an arc to be pinned at the given anchor_angle.
     */
    public static final int ARC_ANCHOR_CENTER = 2;

    /**
     * Anchor at the end of the elements. This will cause the set of elements inside the arc to end
     * at the specified anchor_angle, i.e. all elements should be to the left of anchor_angle.
     */
    public static final int ARC_ANCHOR_END = 3;

    /**
     * How content which does not match the dimensions of its bounds (e.g. an image resource being
     * drawn inside an {@link Image}) will be resized to fit its bounds.
     *
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY)
    @IntDef({
        CONTENT_SCALE_MODE_UNDEFINED,
        CONTENT_SCALE_MODE_FIT,
        CONTENT_SCALE_MODE_CROP,
        CONTENT_SCALE_MODE_FILL_BOUNDS
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ContentScaleMode {}

    /** Content scaling is undefined. */
    public static final int CONTENT_SCALE_MODE_UNDEFINED = 0;

    /**
     * Content will be scaled to fit inside its bounds, proportionally. As an example, If a 10x5
     * image was going to be drawn inside a 50x50 {@link Image} element, the actual image resource
     * would be drawn as a 50x25 image, centered within the 50x50 bounds.
     */
    public static final int CONTENT_SCALE_MODE_FIT = 1;

    /**
     * Content will be resized proportionally so it completely fills its bounds, and anything
     * outside of the bounds will be cropped. As an example, if a 10x5 image was going to be drawn
     * inside a 50x50 {@link Image} element, the image resource would be drawn as a 100x50 image,
     * centered within its bounds (and with 25px cropped from both the left and right sides).
     */
    public static final int CONTENT_SCALE_MODE_CROP = 2;

    /**
     * Content will be resized to fill its bounds, without taking into account the aspect ratio. If
     * a 10x5 image was going to be drawn inside a 50x50 {@link Image} element, the image would be
     * drawn as a 50x50 image, stretched vertically.
     */
    public static final int CONTENT_SCALE_MODE_FILL_BOUNDS = 3;

    /** The styling of a font (e.g. font size, and metrics). */
    public static final class FontStyle {
        private final LayoutElementProto.FontStyle mImpl;

        private FontStyle(LayoutElementProto.FontStyle impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static FontStyle fromProto(@NonNull LayoutElementProto.FontStyle proto) {
            return new FontStyle(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.FontStyle toProto() {
            return mImpl;
        }

        /** Builder for {@link FontStyle} */
        public static final class Builder {
            private final LayoutElementProto.FontStyle.Builder mImpl =
                    LayoutElementProto.FontStyle.newBuilder();

            Builder() {}

            /**
             * Sets the size of the font, in scaled pixels (sp). If not specified, defaults to the
             * size of the system's "body" font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setSize(@NonNull SpProp size) {
                mImpl.setSize(size.toProto());
                return this;
            }

            /**
             * Sets the size of the font, in scaled pixels (sp). If not specified, defaults to the
             * size of the system's "body" font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setSize(@NonNull SpProp.Builder sizeBuilder) {
                mImpl.setSize(sizeBuilder.build().toProto());
                return this;
            }

            /**
             * Sets whether the text should be rendered in a italic typeface. If not specified,
             * defaults to "false".
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setItalic(boolean italic) {
                mImpl.setItalic(TypesProto.BoolProp.newBuilder().setValue(italic));
                return this;
            }

            /**
             * Sets whether the text should be rendered with an underline. If not specified,
             * defaults to "false".
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setUnderline(boolean underline) {
                mImpl.setUnderline(TypesProto.BoolProp.newBuilder().setValue(underline));
                return this;
            }

            /** Sets the text color. If not defined, defaults to white. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setColor(@NonNull ColorProp color) {
                mImpl.setColor(color.toProto());
                return this;
            }

            /** Sets the text color. If not defined, defaults to white. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setColor(@NonNull ColorProp.Builder colorBuilder) {
                mImpl.setColor(colorBuilder.build().toProto());
                return this;
            }

            /**
             * Sets the weight of the font. If the provided value is not supported on a platform,
             * the nearest supported value will be used. If not defined, or when set to an invalid
             * value, defaults to "normal".
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWeight(@FontWeight int weight) {
                mImpl.setWeight(
                        LayoutElementProto.FontWeightProp.newBuilder()
                                .setValue(LayoutElementProto.FontWeight.forNumber(weight)));
                return this;
            }

            /**
             * Sets the text letter-spacing. Positive numbers increase the space between letters
             * while negative numbers tighten the space. If not specified, defaults to 0.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLetterSpacing(@NonNull EmProp letterSpacing) {
                mImpl.setLetterSpacing(letterSpacing.toProto());
                return this;
            }

            /**
             * Sets the text letter-spacing. Positive numbers increase the space between letters
             * while negative numbers tighten the space. If not specified, defaults to 0.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLetterSpacing(@NonNull EmProp.Builder letterSpacingBuilder) {
                mImpl.setLetterSpacing(letterSpacingBuilder.build().toProto());
                return this;
            }

            /** Builds an instance from accumulated values. */
            @NonNull
            public FontStyle build() {
                return FontStyle.fromProto(mImpl.build());
            }
        }
    }

    /** A text string. */
    public static final class Text implements LayoutElement {
        private final LayoutElementProto.Text mImpl;

        private Text(LayoutElementProto.Text impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Text fromProto(@NonNull LayoutElementProto.Text proto) {
            return new Text(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Text toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setText(mImpl).build();
        }

        /** Builder for {@link Text}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Text.Builder mImpl =
                    LayoutElementProto.Text.newBuilder();

            Builder() {}

            /** Sets the text to render. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setText(@NonNull String text) {
                mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
                return this;
            }

            /**
             * Sets the style of font to use (size, bold etc). If not specified, defaults to the
             * platform's default body font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setFontStyle(@NonNull FontStyle fontStyle) {
                mImpl.setFontStyle(fontStyle.toProto());
                return this;
            }

            /**
             * Sets the style of font to use (size, bold etc). If not specified, defaults to the
             * platform's default body font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setFontStyle(@NonNull FontStyle.Builder fontStyleBuilder) {
                mImpl.setFontStyle(fontStyleBuilder.build().toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            /**
             * Sets the maximum number of lines that can be represented by the {@link Text} element.
             * If not defined, the {@link Text} element will be treated as a single-line element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
                mImpl.setMaxLines(TypesProto.Int32Prop.newBuilder().setValue(maxLines));
                return this;
            }

            /**
             * Sets alignment of the text within its bounds. Note that a {@link Text} element will
             * size itself to wrap its contents, so this option is meaningless for single-line text
             * (for that, use alignment of the outer container). For multi-line text, however, this
             * will set the alignment of lines relative to the {@link Text} element bounds. If not
             * defined, defaults to TEXT_ALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setMultilineAlignment(@TextAlignment int multilineAlignment) {
                mImpl.setMultilineAlignment(
                        LayoutElementProto.TextAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.TextAlignment.forNumber(
                                                multilineAlignment)));
                return this;
            }

            /**
             * Sets how to handle text which overflows the bound of the {@link Text} element. A
             * {@link Text} element will grow as large as possible inside its parent container
             * (while still respecting max_lines); if it cannot grow large enough to render all of
             * its text, the text which cannot fit inside its container will be truncated. If not
             * defined, defaults to TEXT_OVERFLOW_TRUNCATE.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setOverflow(@TextOverflow int overflow) {
                mImpl.setOverflow(
                        LayoutElementProto.TextOverflowProp.newBuilder()
                                .setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
                return this;
            }

            /**
             * Sets the explicit height between lines of text. This is equivalent to the vertical
             * distance between subsequent baselines. If not specified, defaults the font's
             * recommended interline spacing.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLineHeight(@NonNull SpProp lineHeight) {
                mImpl.setLineHeight(lineHeight.toProto());
                return this;
            }

            /**
             * Sets the explicit height between lines of text. This is equivalent to the vertical
             * distance between subsequent baselines. If not specified, defaults the font's
             * recommended interline spacing.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLineHeight(@NonNull SpProp.Builder lineHeightBuilder) {
                mImpl.setLineHeight(lineHeightBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Text build() {
                return Text.fromProto(mImpl.build());
            }
        }
    }

    /**
     * An image.
     *
     * <p>Images used in this element must exist in the resource bundle that corresponds to this
     * layout. Images must have their dimension specified, and will be rendered at this width and
     * height, regardless of their native dimension.
     */
    public static final class Image implements LayoutElement {
        private final LayoutElementProto.Image mImpl;

        private Image(LayoutElementProto.Image impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Image fromProto(@NonNull LayoutElementProto.Image proto) {
            return new Image(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Image toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setImage(mImpl).build();
        }

        /** Builder for {@link Image}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Image.Builder mImpl =
                    LayoutElementProto.Image.newBuilder();

            Builder() {}

            /**
             * Sets the resource_id of the image to render. This must exist in the supplied resource
             * bundle.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setResourceId(@NonNull String resourceId) {
                mImpl.setResourceId(TypesProto.StringProp.newBuilder().setValue(resourceId));
                return this;
            }

            /** Sets the width of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ImageDimension width) {
                mImpl.setWidth(width.toImageDimensionProto());
                return this;
            }

            /** Sets the width of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ImageDimension.Builder widthBuilder) {
                mImpl.setWidth(widthBuilder.build().toImageDimensionProto());
                return this;
            }

            /** Sets the height of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ImageDimension height) {
                mImpl.setHeight(height.toImageDimensionProto());
                return this;
            }

            /** Sets the height of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ImageDimension.Builder heightBuilder) {
                mImpl.setHeight(heightBuilder.build().toImageDimensionProto());
                return this;
            }

            /**
             * Sets how to scale the image resource inside the bounds specified by width/height if
             * its size does not match those bounds. Defaults to CONTENT_SCALE_MODE_FIT.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setContentScaleMode(@ContentScaleMode int contentScaleMode) {
                mImpl.setContentScaleMode(
                        LayoutElementProto.ContentScaleModeProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.ContentScaleMode.forNumber(
                                                contentScaleMode)));
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Image build() {
                return Image.fromProto(mImpl.build());
            }
        }
    }

    /** A simple spacer, typically used to provide padding between adjacent elements. */
    public static final class Spacer implements LayoutElement {
        private final LayoutElementProto.Spacer mImpl;

        private Spacer(LayoutElementProto.Spacer impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Spacer fromProto(@NonNull LayoutElementProto.Spacer proto) {
            return new Spacer(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Spacer toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setSpacer(mImpl).build();
        }

        /** Builder for {@link Spacer}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Spacer.Builder mImpl =
                    LayoutElementProto.Spacer.newBuilder();

            Builder() {}

            /**
             * Sets the width of this {@link Spacer}. When this is added as the direct child of an
             * {@link Arc}, this must be specified as an angular dimension, otherwise a linear
             * dimension must be used. If not defined, defaults to 0.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull SpacerDimension width) {
                mImpl.setWidth(width.toSpacerDimensionProto());
                return this;
            }

            /**
             * Sets the width of this {@link Spacer}. When this is added as the direct child of an
             * {@link Arc}, this must be specified as an angular dimension, otherwise a linear
             * dimension must be used. If not defined, defaults to 0.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull SpacerDimension.Builder widthBuilder) {
                mImpl.setWidth(widthBuilder.build().toSpacerDimensionProto());
                return this;
            }

            /** Sets the height of this spacer. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull SpacerDimension height) {
                mImpl.setHeight(height.toSpacerDimensionProto());
                return this;
            }

            /** Sets the height of this spacer. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull SpacerDimension.Builder heightBuilder) {
                mImpl.setHeight(heightBuilder.build().toSpacerDimensionProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Spacer build() {
                return Spacer.fromProto(mImpl.build());
            }
        }
    }

    /**
     * A container which stacks all of its children on top of one another. This also allows to add a
     * background color, or to have a border around them with some padding.
     */
    public static final class Box implements LayoutElement {
        private final LayoutElementProto.Box mImpl;

        private Box(LayoutElementProto.Box impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Box fromProto(@NonNull LayoutElementProto.Box proto) {
            return new Box(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Box toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setBox(mImpl).build();
        }

        /** Builder for {@link Box}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Box.Builder mImpl =
                    LayoutElementProto.Box.newBuilder();

            Builder() {}

            /** Adds one item to the child element(s) to wrap. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull LayoutElement content) {
                mImpl.addContents(content.toLayoutElementProto());
                return this;
            }

            /** Adds one item to the child element(s) to wrap. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull LayoutElement.Builder contentBuilder) {
                mImpl.addContents(contentBuilder.build().toLayoutElementProto());
                return this;
            }

            /**
             * Sets the height of this {@link Box}. If not defined, this will size itself to fit all
             * of its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ContainerDimension height) {
                mImpl.setHeight(height.toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the height of this {@link Box}. If not defined, this will size itself to fit all
             * of its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ContainerDimension.Builder heightBuilder) {
                mImpl.setHeight(heightBuilder.build().toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the width of this {@link Box}. If not defined, this will size itself to fit all
             * of its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ContainerDimension width) {
                mImpl.setWidth(width.toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the width of this {@link Box}. If not defined, this will size itself to fit all
             * of its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ContainerDimension.Builder widthBuilder) {
                mImpl.setWidth(widthBuilder.build().toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the horizontal alignment of the element inside this {@link Box}. If not defined,
             * defaults to HALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
                mImpl.setHorizontalAlignment(
                        LayoutElementProto.HorizontalAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.HorizontalAlignment.forNumber(
                                                horizontalAlignment)));
                return this;
            }

            /**
             * Sets the vertical alignment of the element inside this {@link Box}. If not defined,
             * defaults to VALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
                mImpl.setVerticalAlignment(
                        LayoutElementProto.VerticalAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.VerticalAlignment.forNumber(
                                                verticalAlignment)));
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Box build() {
                return Box.fromProto(mImpl.build());
            }
        }
    }

    /**
     * A portion of text which can be added to a {@link Span}. Two different {@link SpanText}
     * elements on the same line will be aligned to the same baseline, regardless of the size of
     * each {@link SpanText}.
     */
    public static final class SpanText implements Span {
        private final LayoutElementProto.SpanText mImpl;

        private SpanText(LayoutElementProto.SpanText impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static SpanText fromProto(@NonNull LayoutElementProto.SpanText proto) {
            return new SpanText(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.SpanText toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.Span toSpanProto() {
            return LayoutElementProto.Span.newBuilder().setText(mImpl).build();
        }

        /** Builder for {@link SpanText}. */
        public static final class Builder implements Span.Builder {
            private final LayoutElementProto.SpanText.Builder mImpl =
                    LayoutElementProto.SpanText.newBuilder();

            Builder() {}

            /** Sets the text to render. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setText(@NonNull String text) {
                mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
                return this;
            }

            /**
             * Sets the style of font to use (size, bold etc). If not specified, defaults to the
             * platform's default body font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setFontStyle(@NonNull FontStyle fontStyle) {
                mImpl.setFontStyle(fontStyle.toProto());
                return this;
            }

            /**
             * Sets the style of font to use (size, bold etc). If not specified, defaults to the
             * platform's default body font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setFontStyle(@NonNull FontStyle.Builder fontStyleBuilder) {
                mImpl.setFontStyle(fontStyleBuilder.build().toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull SpanModifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull SpanModifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public SpanText build() {
                return SpanText.fromProto(mImpl.build());
            }
        }
    }

    /** An image which can be added to a {@link Span}. */
    public static final class SpanImage implements Span {
        private final LayoutElementProto.SpanImage mImpl;

        private SpanImage(LayoutElementProto.SpanImage impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static SpanImage fromProto(@NonNull LayoutElementProto.SpanImage proto) {
            return new SpanImage(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.SpanImage toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.Span toSpanProto() {
            return LayoutElementProto.Span.newBuilder().setImage(mImpl).build();
        }

        /** Builder for {@link SpanImage}. */
        public static final class Builder implements Span.Builder {
            private final LayoutElementProto.SpanImage.Builder mImpl =
                    LayoutElementProto.SpanImage.newBuilder();

            Builder() {}

            /**
             * Sets the resource_id of the image to render. This must exist in the supplied resource
             * bundle.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setResourceId(@NonNull String resourceId) {
                mImpl.setResourceId(TypesProto.StringProp.newBuilder().setValue(resourceId));
                return this;
            }

            /** Sets the width of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull DpProp width) {
                mImpl.setWidth(width.toProto());
                return this;
            }

            /** Sets the width of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull DpProp.Builder widthBuilder) {
                mImpl.setWidth(widthBuilder.build().toProto());
                return this;
            }

            /** Sets the height of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull DpProp height) {
                mImpl.setHeight(height.toProto());
                return this;
            }

            /** Sets the height of this image. If not defined, the image will not be rendered. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull DpProp.Builder heightBuilder) {
                mImpl.setHeight(heightBuilder.build().toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull SpanModifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull SpanModifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public SpanImage build() {
                return SpanImage.fromProto(mImpl.build());
            }
        }
    }

    /**
     * Interface defining a single {@link Span}. Each {@link Span} forms part of a larger {@link
     * Spannable} widget. At the moment, the only widgets which can be added to {@link Spannable}
     * containers are {@link SpanText} and {@link SpanImage} elements.
     */
    public interface Span {
        /**
         * Get the protocol buffer representation of this object.
         *
         * @hide
         */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Span toSpanProto();

        /** Builder to create {@link Span} objects. */
        @SuppressLint("StaticFinalBuilder")
        interface Builder {

            /** Builds an instance with values accumulated in this Builder. */
            @NonNull
            Span build();
        }
    }

    /**
     * A container of {@link Span} elements. Currently, this only supports {@link Text} elements,
     * where each individual {@link Span} can have different styling applied to it but the resulting
     * text will flow naturally. This allows sections of a paragraph of text to have different
     * styling applied to it, for example, making one or two words bold or italic.
     */
    public static final class Spannable implements LayoutElement {
        private final LayoutElementProto.Spannable mImpl;

        private Spannable(LayoutElementProto.Spannable impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Spannable fromProto(@NonNull LayoutElementProto.Spannable proto) {
            return new Spannable(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Spannable toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setSpannable(mImpl).build();
        }

        /** Builder for {@link Spannable}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Spannable.Builder mImpl =
                    LayoutElementProto.Spannable.newBuilder();

            Builder() {}

            /** Adds one item to the {@link Span} elements that form this {@link Spannable}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addSpan(@NonNull Span span) {
                mImpl.addSpans(span.toSpanProto());
                return this;
            }

            /** Adds one item to the {@link Span} elements that form this {@link Spannable}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addSpan(@NonNull Span.Builder spanBuilder) {
                mImpl.addSpans(spanBuilder.build().toSpanProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            /**
             * Sets the maximum number of lines that can be represented by the {@link Spannable}
             * element. If not defined, the {@link Spannable} element will be treated as a
             * single-line element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setMaxLines(@IntRange(from = 1) int maxLines) {
                mImpl.setMaxLines(TypesProto.Int32Prop.newBuilder().setValue(maxLines));
                return this;
            }

            /**
             * Sets alignment of the {@link Spannable} content within its bounds. Note that a {@link
             * Spannable} element will size itself to wrap its contents, so this option is
             * meaningless for single-line content (for that, use alignment of the outer container).
             * For multi-line content, however, this will set the alignment of lines relative to the
             * {@link Spannable} element bounds. If not defined, defaults to TEXT_ALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setMultilineAlignment(@HorizontalAlignment int multilineAlignment) {
                mImpl.setMultilineAlignment(
                        LayoutElementProto.HorizontalAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.HorizontalAlignment.forNumber(
                                                multilineAlignment)));
                return this;
            }

            /**
             * Sets how to handle content which overflows the bound of the {@link Spannable}
             * element. A {@link Spannable} element will grow as large as possible inside its parent
             * container (while still respecting max_lines); if it cannot grow large enough to
             * render all of its content, the content which cannot fit inside its container will be
             * truncated. If not defined, defaults to TEXT_OVERFLOW_TRUNCATE.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setOverflow(@TextOverflow int overflow) {
                mImpl.setOverflow(
                        LayoutElementProto.TextOverflowProp.newBuilder()
                                .setValue(LayoutElementProto.TextOverflow.forNumber(overflow)));
                return this;
            }

            /**
             * Sets extra spacing to add between each line. This will apply to all spans regardless
             * of their font size. This is in addition to original line heights. Note that this
             * won't add any additional space before the first line or after the last line. The
             * default value is zero and negative values will decrease the interline spacing.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLineSpacing(@NonNull SpProp lineSpacing) {
                mImpl.setLineSpacing(lineSpacing.toProto());
                return this;
            }

            /**
             * Sets extra spacing to add between each line. This will apply to all spans regardless
             * of their font size. This is in addition to original line heights. Note that this
             * won't add any additional space before the first line or after the last line. The
             * default value is zero and negative values will decrease the interline spacing.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLineSpacing(@NonNull SpProp.Builder lineSpacingBuilder) {
                mImpl.setLineSpacing(lineSpacingBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Spannable build() {
                return Spannable.fromProto(mImpl.build());
            }
        }
    }

    /**
     * A column of elements. Each child element will be laid out vertically, one after another (i.e.
     * stacking down). This element will size itself to the smallest size required to hold all of
     * its children (e.g. if it contains three elements sized 10x10, 20x20 and 30x30, the resulting
     * column will be 30x60).
     *
     * <p>If specified, horizontal_alignment can be used to control the gravity inside the
     * container, affecting the horizontal placement of children whose width are smaller than the
     * resulting column width.
     */
    public static final class Column implements LayoutElement {
        private final LayoutElementProto.Column mImpl;

        private Column(LayoutElementProto.Column impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Column fromProto(@NonNull LayoutElementProto.Column proto) {
            return new Column(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Column toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setColumn(mImpl).build();
        }

        /** Builder for {@link Column}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Column.Builder mImpl =
                    LayoutElementProto.Column.newBuilder();

            Builder() {}

            /** Adds one item to the list of child elements to place inside this {@link Column}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull LayoutElement content) {
                mImpl.addContents(content.toLayoutElementProto());
                return this;
            }

            /** Adds one item to the list of child elements to place inside this {@link Column}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull LayoutElement.Builder contentBuilder) {
                mImpl.addContents(contentBuilder.build().toLayoutElementProto());
                return this;
            }

            /**
             * Sets the horizontal alignment of elements inside this column, if they are narrower
             * than the resulting width of the column. If not defined, defaults to HALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHorizontalAlignment(@HorizontalAlignment int horizontalAlignment) {
                mImpl.setHorizontalAlignment(
                        LayoutElementProto.HorizontalAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.HorizontalAlignment.forNumber(
                                                horizontalAlignment)));
                return this;
            }

            /**
             * Sets the width of this column. If not defined, this will size itself to fit all of
             * its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ContainerDimension width) {
                mImpl.setWidth(width.toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the width of this column. If not defined, this will size itself to fit all of
             * its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ContainerDimension.Builder widthBuilder) {
                mImpl.setWidth(widthBuilder.build().toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the height of this column. If not defined, this will size itself to fit all of
             * its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ContainerDimension height) {
                mImpl.setHeight(height.toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the height of this column. If not defined, this will size itself to fit all of
             * its children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ContainerDimension.Builder heightBuilder) {
                mImpl.setHeight(heightBuilder.build().toContainerDimensionProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Column build() {
                return Column.fromProto(mImpl.build());
            }
        }
    }

    /**
     * A row of elements. Each child will be laid out horizontally, one after another (i.e. stacking
     * to the right). This element will size itself to the smallest size required to hold all of its
     * children (e.g. if it contains three elements sized 10x10, 20x20 and 30x30, the resulting row
     * will be 60x30).
     *
     * <p>If specified, vertical_alignment can be used to control the gravity inside the container,
     * affecting the vertical placement of children whose width are smaller than the resulting row
     * height.
     */
    public static final class Row implements LayoutElement {
        private final LayoutElementProto.Row mImpl;

        private Row(LayoutElementProto.Row impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Row fromProto(@NonNull LayoutElementProto.Row proto) {
            return new Row(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Row toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setRow(mImpl).build();
        }

        /** Builder for {@link Row}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Row.Builder mImpl =
                    LayoutElementProto.Row.newBuilder();

            Builder() {}

            /** Adds one item to the list of child elements to place inside this {@link Row}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull LayoutElement content) {
                mImpl.addContents(content.toLayoutElementProto());
                return this;
            }

            /** Adds one item to the list of child elements to place inside this {@link Row}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull LayoutElement.Builder contentBuilder) {
                mImpl.addContents(contentBuilder.build().toLayoutElementProto());
                return this;
            }

            /**
             * Sets the vertical alignment of elements inside this row, if they are narrower than
             * the resulting height of the row. If not defined, defaults to VALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setVerticalAlignment(@VerticalAlignment int verticalAlignment) {
                mImpl.setVerticalAlignment(
                        LayoutElementProto.VerticalAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.VerticalAlignment.forNumber(
                                                verticalAlignment)));
                return this;
            }

            /**
             * Sets the width of this row. If not defined, this will size itself to fit all of its
             * children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ContainerDimension width) {
                mImpl.setWidth(width.toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the width of this row. If not defined, this will size itself to fit all of its
             * children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setWidth(@NonNull ContainerDimension.Builder widthBuilder) {
                mImpl.setWidth(widthBuilder.build().toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the height of this row. If not defined, this will size itself to fit all of its
             * children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ContainerDimension height) {
                mImpl.setHeight(height.toContainerDimensionProto());
                return this;
            }

            /**
             * Sets the height of this row. If not defined, this will size itself to fit all of its
             * children (i.e. a WrappedDimension).
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setHeight(@NonNull ContainerDimension.Builder heightBuilder) {
                mImpl.setHeight(heightBuilder.build().toContainerDimensionProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Row build() {
                return Row.fromProto(mImpl.build());
            }
        }
    }

    /**
     * An arc container. This container will fill itself to a circle, which fits inside its parent
     * container, and all of its children will be placed on that circle. The fields anchor_angle and
     * anchor_type can be used to specify where to draw children within this circle.
     */
    public static final class Arc implements LayoutElement {
        private final LayoutElementProto.Arc mImpl;

        private Arc(LayoutElementProto.Arc impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Arc fromProto(@NonNull LayoutElementProto.Arc proto) {
            return new Arc(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.Arc toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.LayoutElement toLayoutElementProto() {
            return LayoutElementProto.LayoutElement.newBuilder().setArc(mImpl).build();
        }

        /** Builder for {@link Arc}. */
        public static final class Builder implements LayoutElement.Builder {
            private final LayoutElementProto.Arc.Builder mImpl =
                    LayoutElementProto.Arc.newBuilder();

            Builder() {}

            /** Adds one item to contents of this container. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull ArcLayoutElement content) {
                mImpl.addContents(content.toArcLayoutElementProto());
                return this;
            }

            /** Adds one item to contents of this container. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder addContent(@NonNull ArcLayoutElement.Builder contentBuilder) {
                mImpl.addContents(contentBuilder.build().toArcLayoutElementProto());
                return this;
            }

            /**
             * Sets the angle for the anchor, used with anchor_type to determine where to draw
             * children. Note that 0 degrees is the 12 o clock position on a device, and the angle
             * sweeps clockwise. If not defined, defaults to 0 degrees.
             *
             * <p>Values do not have to be clamped to the range 0-360; values less than 0 degrees
             * will sweep anti-clockwise (i.e. -90 degrees is equivalent to 270 degrees), and values
             * >360 will be be placed at X mod 360 degrees.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setAnchorAngle(@NonNull DegreesProp anchorAngle) {
                mImpl.setAnchorAngle(anchorAngle.toProto());
                return this;
            }

            /**
             * Sets the angle for the anchor, used with anchor_type to determine where to draw
             * children. Note that 0 degrees is the 12 o clock position on a device, and the angle
             * sweeps clockwise. If not defined, defaults to 0 degrees.
             *
             * <p>Values do not have to be clamped to the range 0-360; values less than 0 degrees
             * will sweep anti-clockwise (i.e. -90 degrees is equivalent to 270 degrees), and values
             * >360 will be be placed at X mod 360 degrees.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setAnchorAngle(@NonNull DegreesProp.Builder anchorAngleBuilder) {
                mImpl.setAnchorAngle(anchorAngleBuilder.build().toProto());
                return this;
            }

            /**
             * Sets how to align the contents of this container relative to anchor_angle. See the
             * descriptions of options in {@link ArcAnchorType} for more information. If not
             * defined, defaults to ARC_ANCHOR_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setAnchorType(@ArcAnchorType int anchorType) {
                mImpl.setAnchorType(
                        LayoutElementProto.ArcAnchorTypeProp.newBuilder()
                                .setValue(LayoutElementProto.ArcAnchorType.forNumber(anchorType)));
                return this;
            }

            /**
             * Sets vertical alignment of elements within the arc. If the {@link Arc}'s thickness is
             * larger than the thickness of the element being drawn, this controls whether the
             * element should be drawn towards the inner or outer edge of the arc, or drawn in the
             * center. If not defined, defaults to VALIGN_CENTER.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setVerticalAlign(@VerticalAlignment int verticalAlign) {
                mImpl.setVerticalAlign(
                        LayoutElementProto.VerticalAlignmentProp.newBuilder()
                                .setValue(
                                        LayoutElementProto.VerticalAlignment.forNumber(
                                                verticalAlign)));
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull Modifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public Arc build() {
                return Arc.fromProto(mImpl.build());
            }
        }
    }

    /** A text element that can be used in an {@link Arc}. */
    public static final class ArcText implements ArcLayoutElement {
        private final LayoutElementProto.ArcText mImpl;

        private ArcText(LayoutElementProto.ArcText impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static ArcText fromProto(@NonNull LayoutElementProto.ArcText proto) {
            return new ArcText(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.ArcText toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
            return LayoutElementProto.ArcLayoutElement.newBuilder().setText(mImpl).build();
        }

        /** Builder for {@link ArcText}. */
        public static final class Builder implements ArcLayoutElement.Builder {
            private final LayoutElementProto.ArcText.Builder mImpl =
                    LayoutElementProto.ArcText.newBuilder();

            Builder() {}

            /** Sets the text to render. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setText(@NonNull String text) {
                mImpl.setText(TypesProto.StringProp.newBuilder().setValue(text));
                return this;
            }

            /**
             * Sets the style of font to use (size, bold etc). If not specified, defaults to the
             * platform's default body font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setFontStyle(@NonNull FontStyle fontStyle) {
                mImpl.setFontStyle(fontStyle.toProto());
                return this;
            }

            /**
             * Sets the style of font to use (size, bold etc). If not specified, defaults to the
             * platform's default body font.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setFontStyle(@NonNull FontStyle.Builder fontStyleBuilder) {
                mImpl.setFontStyle(fontStyleBuilder.build().toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull ArcModifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull ArcModifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public ArcText build() {
                return ArcText.fromProto(mImpl.build());
            }
        }
    }

    /** A line that can be used in an {@link Arc} and renders as a round progress bar. */
    public static final class ArcLine implements ArcLayoutElement {
        private final LayoutElementProto.ArcLine mImpl;

        private ArcLine(LayoutElementProto.ArcLine impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static ArcLine fromProto(@NonNull LayoutElementProto.ArcLine proto) {
            return new ArcLine(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.ArcLine toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
            return LayoutElementProto.ArcLayoutElement.newBuilder().setLine(mImpl).build();
        }

        /** Builder for {@link ArcLine}. */
        public static final class Builder implements ArcLayoutElement.Builder {
            private final LayoutElementProto.ArcLine.Builder mImpl =
                    LayoutElementProto.ArcLine.newBuilder();

            Builder() {}

            /** Sets the length of this line, in degrees. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLength(@NonNull DegreesProp length) {
                mImpl.setLength(length.toProto());
                return this;
            }

            /** Sets the length of this line, in degrees. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLength(@NonNull DegreesProp.Builder lengthBuilder) {
                mImpl.setLength(lengthBuilder.build().toProto());
                return this;
            }

            /** Sets the thickness of this line. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setThickness(@NonNull DpProp thickness) {
                mImpl.setThickness(thickness.toProto());
                return this;
            }

            /** Sets the thickness of this line. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setThickness(@NonNull DpProp.Builder thicknessBuilder) {
                mImpl.setThickness(thicknessBuilder.build().toProto());
                return this;
            }

            /** Sets the color of this line. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setColor(@NonNull ColorProp color) {
                mImpl.setColor(color.toProto());
                return this;
            }

            /** Sets the color of this line. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setColor(@NonNull ColorProp.Builder colorBuilder) {
                mImpl.setColor(colorBuilder.build().toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull ArcModifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull ArcModifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public ArcLine build() {
                return ArcLine.fromProto(mImpl.build());
            }
        }
    }

    /** A simple spacer used to provide padding between adjacent elements in an {@link Arc}. */
    public static final class ArcSpacer implements ArcLayoutElement {
        private final LayoutElementProto.ArcSpacer mImpl;

        private ArcSpacer(LayoutElementProto.ArcSpacer impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static ArcSpacer fromProto(@NonNull LayoutElementProto.ArcSpacer proto) {
            return new ArcSpacer(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.ArcSpacer toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
            return LayoutElementProto.ArcLayoutElement.newBuilder().setSpacer(mImpl).build();
        }

        /** Builder for {@link ArcSpacer}. */
        public static final class Builder implements ArcLayoutElement.Builder {
            private final LayoutElementProto.ArcSpacer.Builder mImpl =
                    LayoutElementProto.ArcSpacer.newBuilder();

            Builder() {}

            /** Sets the length of this spacer, in degrees. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLength(@NonNull DegreesProp length) {
                mImpl.setLength(length.toProto());
                return this;
            }

            /** Sets the length of this spacer, in degrees. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setLength(@NonNull DegreesProp.Builder lengthBuilder) {
                mImpl.setLength(lengthBuilder.build().toProto());
                return this;
            }

            /** Sets the thickness of this spacer, in DP. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setThickness(@NonNull DpProp thickness) {
                mImpl.setThickness(thickness.toProto());
                return this;
            }

            /** Sets the thickness of this spacer, in DP. If not defined, defaults to 0. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setThickness(@NonNull DpProp.Builder thicknessBuilder) {
                mImpl.setThickness(thicknessBuilder.build().toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull ArcModifiers modifiers) {
                mImpl.setModifiers(modifiers.toProto());
                return this;
            }

            /**
             * Sets {@link androidx.wear.tiles.builders.ModifiersBuilders.Modifiers} for this
             * element.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setModifiers(@NonNull ArcModifiers.Builder modifiersBuilder) {
                mImpl.setModifiers(modifiersBuilder.build().toProto());
                return this;
            }

            @Override
            @NonNull
            public ArcSpacer build() {
                return ArcSpacer.fromProto(mImpl.build());
            }
        }
    }

    /** A container that allows a standard {@link LayoutElement} to be added to an {@link Arc}. */
    public static final class ArcAdapter implements ArcLayoutElement {
        private final LayoutElementProto.ArcAdapter mImpl;

        private ArcAdapter(LayoutElementProto.ArcAdapter impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static ArcAdapter fromProto(@NonNull LayoutElementProto.ArcAdapter proto) {
            return new ArcAdapter(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.ArcAdapter toProto() {
            return mImpl;
        }

        /** @hide */
        @Override
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
            return LayoutElementProto.ArcLayoutElement.newBuilder().setAdapter(mImpl).build();
        }

        /** Builder for {@link ArcAdapter}. */
        public static final class Builder implements ArcLayoutElement.Builder {
            private final LayoutElementProto.ArcAdapter.Builder mImpl =
                    LayoutElementProto.ArcAdapter.newBuilder();

            Builder() {}

            /** Sets the element to adapt to an {@link Arc}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setContent(@NonNull LayoutElement content) {
                mImpl.setContent(content.toLayoutElementProto());
                return this;
            }

            /** Sets the element to adapt to an {@link Arc}. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setContent(@NonNull LayoutElement.Builder contentBuilder) {
                mImpl.setContent(contentBuilder.build().toLayoutElementProto());
                return this;
            }

            /**
             * Sets whether this adapter's contents should be rotated, according to its position in
             * the arc or not. As an example, assume that an {@link Image} has been added to the
             * arc, and ends up at the 3 o clock position. If rotate_contents = true, the image will
             * be placed at the 3 o clock position, and will be rotated clockwise through 90
             * degrees. If rotate_contents = false, the image will be placed at the 3 o clock
             * position, but itself will not be rotated. If not defined, defaults to false.
             */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setRotateContents(boolean rotateContents) {
                mImpl.setRotateContents(TypesProto.BoolProp.newBuilder().setValue(rotateContents));
                return this;
            }

            @Override
            @NonNull
            public ArcAdapter build() {
                return ArcAdapter.fromProto(mImpl.build());
            }
        }
    }

    /**
     * Interface defining the root of all layout elements. This exists to act as a holder for all of
     * the actual layout elements above.
     */
    public interface LayoutElement {
        /**
         * Get the protocol buffer representation of this object.
         *
         * @hide
         */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.LayoutElement toLayoutElementProto();

        /** Builder to create {@link LayoutElement} objects. */
        @SuppressLint("StaticFinalBuilder")
        interface Builder {

            /** Builds an instance with values accumulated in this Builder. */
            @NonNull
            LayoutElement build();
        }
    }

    /**
     * Interface defining the root of all elements that can be used in an {@link Arc}. This exists
     * to act as a holder for all of the actual arc layout elements above.
     */
    public interface ArcLayoutElement {
        /**
         * Get the protocol buffer representation of this object.
         *
         * @hide
         */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        LayoutElementProto.ArcLayoutElement toArcLayoutElementProto();

        /** Builder to create {@link ArcLayoutElement} objects. */
        @SuppressLint("StaticFinalBuilder")
        interface Builder {

            /** Builds an instance with values accumulated in this Builder. */
            @NonNull
            ArcLayoutElement build();
        }
    }

    /** A complete layout. */
    public static final class Layout {
        private final LayoutElementProto.Layout mImpl;

        private Layout(LayoutElementProto.Layout impl) {
            this.mImpl = impl;
        }

        /** Returns a new {@link Builder}. */
        @NonNull
        public static Builder builder() {
            return new Builder();
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public static Layout fromProto(@NonNull LayoutElementProto.Layout proto) {
            return new Layout(proto);
        }

        /** @hide */
        @RestrictTo(Scope.LIBRARY_GROUP)
        @NonNull
        public LayoutElementProto.Layout toProto() {
            return mImpl;
        }

        /** Builder for {@link Layout} */
        public static final class Builder {
            private final LayoutElementProto.Layout.Builder mImpl =
                    LayoutElementProto.Layout.newBuilder();

            Builder() {}

            /** Sets the root element in the layout. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setRoot(@NonNull LayoutElement root) {
                mImpl.setRoot(root.toLayoutElementProto());
                return this;
            }

            /** Sets the root element in the layout. */
            @SuppressLint("MissingGetterMatchingBuilder")
            @NonNull
            public Builder setRoot(@NonNull LayoutElement.Builder rootBuilder) {
                mImpl.setRoot(rootBuilder.build().toLayoutElementProto());
                return this;
            }

            /** Builds an instance from accumulated values. */
            @NonNull
            public Layout build() {
                return Layout.fromProto(mImpl.build());
            }
        }
    }

    /** Font styles, currently set up to match Wear's font styling. */
    public static class FontStyles {
        private static final int LARGE_SCREEN_WIDTH_DP = 210;

        private final int mScreenWidthDp;

        private FontStyles(int screenWidthDp) {
            this.mScreenWidthDp = screenWidthDp;
        }

        private boolean isLargeScreen() {
            return mScreenWidthDp >= LARGE_SCREEN_WIDTH_DP;
        }

        /**
         * Create a FontStyles instance, using the given device parameters to determine font sizes.
         */
        @NonNull
        public static FontStyles withDeviceParameters(@NonNull DeviceParameters deviceParameters) {
            return new FontStyles(deviceParameters.getScreenWidthDp());
        }

        /** Font style for large display text. */
        @NonNull
        public FontStyle.Builder display1() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 54 : 50));
        }

        /** Font style for medium display text. */
        @NonNull
        public FontStyle.Builder display2() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 44 : 40));
        }

        /** Font style for small display text. */
        @NonNull
        public FontStyle.Builder display3() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 34 : 30));
        }

        /** Font style for large title text. */
        @NonNull
        public FontStyle.Builder title1() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 26 : 24));
        }

        /** Font style for medium title text. */
        @NonNull
        public FontStyle.Builder title2() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 22 : 20));
        }

        /** Font style for small title text. */
        @NonNull
        public FontStyle.Builder title3() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 18 : 16));
        }

        /** Font style for large body text. */
        @NonNull
        public FontStyle.Builder body1() {
            return FontStyle.builder().setSize(DimensionBuilders.sp(isLargeScreen() ? 18 : 16));
        }

        /** Font style for medium body text. */
        @NonNull
        public FontStyle.Builder body2() {
            return FontStyle.builder().setSize(DimensionBuilders.sp(isLargeScreen() ? 16 : 14));
        }

        /** Font style for button text. */
        @NonNull
        public FontStyle.Builder button() {
            return FontStyle.builder()
                    .setWeight(FONT_WEIGHT_BOLD)
                    .setSize(DimensionBuilders.sp(isLargeScreen() ? 16 : 14));
        }

        /** Font style for large caption text. */
        @NonNull
        public FontStyle.Builder caption1() {
            return FontStyle.builder().setSize(DimensionBuilders.sp(isLargeScreen() ? 16 : 14));
        }

        /** Font style for medium caption text. */
        @NonNull
        public FontStyle.Builder caption2() {
            return FontStyle.builder().setSize(DimensionBuilders.sp(isLargeScreen() ? 14 : 12));
        }
    }
}