Add dashed arcline proto and builder
Bug: 360312549
Change-Id: Ia8404e23fadc5630e268e3aeac91183f9361d004
diff --git a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
index 540382b..b235c5a 100644
--- a/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
+++ b/wear/protolayout/protolayout-proto/src/main/proto/layout.proto
@@ -736,6 +736,45 @@
Shadow shadow = 2;
}
+// A dashed arc line that can be placed in an Arc container. It is an arc line made up of arc line
+// segments separated by gaps.
+message DashedArcLine {
+ // The length of this line in degrees, including gaps. <setter> If not defined,
+ // defaults to 0.</setter>
+ //
+ // When using a dynamic value, make sure to specify the bounding constraints
+ // for the affected layout element through {@code
+ // setLayoutConstraintsForDynamicLength(AngularLayoutConstraint)} otherwise
+ // {@code build()} fails.
+ DegreesProp length = 1;
+
+ // The thickness of this line. <setter> If not defined, defaults to 0.</setter>
+ DpProp thickness = 2;
+
+ // The color of this line.
+ ColorProp color = 3;
+
+ // Modifiers for this element.
+ ArcModifiers modifiers = 4;
+
+ // The direction in which this line is drawn.<setter> If not set, defaults to
+ // ARC_DIRECTION_CLOCKWISE.</setter>
+ ArcDirectionProp arc_direction = 5;
+
+ // The dashed line pattern which describes how the arc line is segmented by gaps.
+ DashedLinePattern line_pattern = 6;
+}
+
+// A dashed line pattern which describes how the dashed arc line is segmented by gaps.
+message DashedLinePattern {
+ // The size in dp of the gap between the line segments.<setter> If not
+ // defined, defaults to 0.</setter>
+ DpProp gap_size = 1;
+
+ // The list of each gap's center location in degrees.
+ repeated DegreesProp gap_locations = 2;
+}
+
// A simple spacer used to provide padding between adjacent elements in an Arc.
message ArcSpacer {
// The length of this spacer, in degrees. If not defined, defaults to 0.
@@ -837,6 +876,7 @@
ArcLine line = 2;
ArcSpacer spacer = 3;
ArcAdapter adapter = 4;
+ DashedArcLine dashed_line = 5;
}
}
diff --git a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
index 3be0537..d8ed179 100644
--- a/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
+++ b/wear/protolayout/protolayout-renderer/src/main/java/androidx/wear/protolayout/renderer/inflater/ProtoLayoutInflater.java
@@ -3961,6 +3961,10 @@
parentViewWrapper, element.getText(), nodePosId, pipelineMaker);
break;
+ case DASHED_LINE:
+ // TODO: b/360314390 - inflate a dashed arc here with WearDashedArcLineView
+ break;
+
case INNER_NOT_SET:
break;
}
diff --git a/wear/protolayout/protolayout/api/current.txt b/wear/protolayout/protolayout/api/current.txt
index 7ef6729..034cbf0 100644
--- a/wear/protolayout/protolayout/api/current.txt
+++ b/wear/protolayout/protolayout/api/current.txt
@@ -558,6 +558,42 @@
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp.Builder setValue(int);
}
+ @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public static final class LayoutElementBuilders.DashedArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcDirectionProp? getArcDirection();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.AngularLayoutConstraint? getLayoutConstraintsForDynamicLength();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern? getLinePattern();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public float getThickness();
+ }
+
+ public static final class LayoutElementBuilders.DashedArcLine.Builder {
+ ctor @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public LayoutElementBuilders.DashedArcLine.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine build();
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setArcDirection(androidx.wear.protolayout.LayoutElementBuilders.ArcDirectionProp);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setArcDirection(int);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setLayoutConstraintsForDynamicLength(androidx.wear.protolayout.DimensionBuilders.AngularLayoutConstraint);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setLinePattern(androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setThickness(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
+ @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public static final class LayoutElementBuilders.DashedLinePattern {
+ method public java.util.List<androidx.wear.protolayout.DimensionBuilders.DegreesProp!> getGapLocations();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getGapSize();
+ }
+
+ public static final class LayoutElementBuilders.DashedLinePattern.Builder {
+ ctor @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public LayoutElementBuilders.DashedLinePattern.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern build();
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern.Builder setGapInterval(float);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern.Builder setGapLocations(float...);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern.Builder setGapSize(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
@SuppressCompatibility @androidx.wear.protolayout.expression.ExperimentalProtoLayoutExtensionApi @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class LayoutElementBuilders.ExtensionLayoutElement implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
method public String getExtensionId();
method public androidx.wear.protolayout.DimensionBuilders.ExtensionDimension? getHeight();
diff --git a/wear/protolayout/protolayout/api/restricted_current.txt b/wear/protolayout/protolayout/api/restricted_current.txt
index 7ef6729..034cbf0 100644
--- a/wear/protolayout/protolayout/api/restricted_current.txt
+++ b/wear/protolayout/protolayout/api/restricted_current.txt
@@ -558,6 +558,42 @@
method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=0) public androidx.wear.protolayout.LayoutElementBuilders.ContentScaleModeProp.Builder setValue(int);
}
+ @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public static final class LayoutElementBuilders.DashedArcLine implements androidx.wear.protolayout.LayoutElementBuilders.ArcLayoutElement {
+ method public androidx.wear.protolayout.LayoutElementBuilders.ArcDirectionProp? getArcDirection();
+ method public androidx.wear.protolayout.ColorBuilders.ColorProp? getColor();
+ method public androidx.wear.protolayout.DimensionBuilders.AngularLayoutConstraint? getLayoutConstraintsForDynamicLength();
+ method public androidx.wear.protolayout.DimensionBuilders.DegreesProp? getLength();
+ method public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern? getLinePattern();
+ method public androidx.wear.protolayout.ModifiersBuilders.ArcModifiers? getModifiers();
+ method @Dimension(unit=androidx.annotation.Dimension.DP) public float getThickness();
+ }
+
+ public static final class LayoutElementBuilders.DashedArcLine.Builder {
+ ctor @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public LayoutElementBuilders.DashedArcLine.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine build();
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setArcDirection(androidx.wear.protolayout.LayoutElementBuilders.ArcDirectionProp);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setArcDirection(int);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setColor(androidx.wear.protolayout.ColorBuilders.ColorProp);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setLayoutConstraintsForDynamicLength(androidx.wear.protolayout.DimensionBuilders.AngularLayoutConstraint);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setLength(androidx.wear.protolayout.DimensionBuilders.DegreesProp);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setLinePattern(androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setModifiers(androidx.wear.protolayout.ModifiersBuilders.ArcModifiers);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine.Builder setThickness(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
+ @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public static final class LayoutElementBuilders.DashedLinePattern {
+ method public java.util.List<androidx.wear.protolayout.DimensionBuilders.DegreesProp!> getGapLocations();
+ method public androidx.wear.protolayout.DimensionBuilders.DpProp? getGapSize();
+ }
+
+ public static final class LayoutElementBuilders.DashedLinePattern.Builder {
+ ctor @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public LayoutElementBuilders.DashedLinePattern.Builder();
+ method public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern build();
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern.Builder setGapInterval(float);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern.Builder setGapLocations(float...);
+ method @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=500) public androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern.Builder setGapSize(@Dimension(unit=androidx.annotation.Dimension.DP) float);
+ }
+
@SuppressCompatibility @androidx.wear.protolayout.expression.ExperimentalProtoLayoutExtensionApi @androidx.wear.protolayout.expression.RequiresSchemaVersion(major=1, minor=200) public static final class LayoutElementBuilders.ExtensionLayoutElement implements androidx.wear.protolayout.LayoutElementBuilders.LayoutElement {
method public String getExtensionId();
method public androidx.wear.protolayout.DimensionBuilders.ExtensionDimension? getHeight();
diff --git a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
index 7c4af90..8fbf8f0 100644
--- a/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
+++ b/wear/protolayout/protolayout/src/main/java/androidx/wear/protolayout/LayoutElementBuilders.java
@@ -16,6 +16,9 @@
package androidx.wear.protolayout;
+import static androidx.annotation.Dimension.DP;
+import static androidx.wear.protolayout.DimensionBuilders.degrees;
+import static androidx.wear.protolayout.DimensionBuilders.dp;
import static androidx.wear.protolayout.DimensionBuilders.sp;
import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
@@ -5170,6 +5173,457 @@
}
}
+ /**
+ * A dashed arc line that can be placed in an {@link Arc} container. It is an arc line made up
+ * of arc line segments separated by gaps.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ public static final class DashedArcLine implements ArcLayoutElement {
+ private final LayoutElementProto.DashedArcLine mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ DashedArcLine(LayoutElementProto.DashedArcLine impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /**
+ * Gets the length of this line in degrees, including gaps.
+ *
+ * <p>When using a dynamic value, make sure to specify the bounding constraints for the
+ * affected layout element through {@code setLayoutConstraintsForDynamicLength
+ * (AngularLayoutConstraint)}, otherwise {@code build()} fails.
+ */
+ @Nullable
+ public DegreesProp getLength() {
+ if (mImpl.hasLength()) {
+ return DegreesProp.fromProto(mImpl.getLength());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the thickness of this line. */
+ @Dimension(unit = DP)
+ public float getThickness() {
+ if (mImpl.hasThickness()) {
+ return DpProp.fromProto(mImpl.getThickness()).getValue();
+ } else {
+ return 0;
+ }
+ }
+
+ /** Gets the color of this line. */
+ @Nullable
+ public ColorProp getColor() {
+ if (mImpl.hasColor()) {
+ return ColorProp.fromProto(mImpl.getColor());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element. */
+ @Nullable
+ public ArcModifiers getModifiers() {
+ if (mImpl.hasModifiers()) {
+ return ArcModifiers.fromProto(mImpl.getModifiers());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the direction in which this line is drawn. */
+ @Nullable
+ public ArcDirectionProp getArcDirection() {
+ if (mImpl.hasArcDirection()) {
+ return ArcDirectionProp.fromProto(mImpl.getArcDirection());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the dashed line pattern which describes how the arc line is segmented by gaps. */
+ @Nullable
+ public DashedLinePattern getLinePattern() {
+ if (mImpl.hasLinePattern()) {
+ return DashedLinePattern.fromProto(mImpl.getLinePattern());
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the bounding constraints for the layout affected by the dynamic value from {@link
+ * #getLength()}.
+ */
+ @Nullable
+ public AngularLayoutConstraint getLayoutConstraintsForDynamicLength() {
+ if (mImpl.hasLength()) {
+ return AngularLayoutConstraint.fromProto(mImpl.getLength());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static DashedArcLine fromProto(
+ @NonNull LayoutElementProto.DashedArcLine proto,
+ @Nullable Fingerprint fingerprint) {
+ return new DashedArcLine(proto, fingerprint);
+ }
+
+ @NonNull
+ static DashedArcLine fromProto(@NonNull LayoutElementProto.DashedArcLine proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @NonNull
+ LayoutElementProto.DashedArcLine toProto() {
+ return mImpl;
+ }
+
+ @Override
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.ArcLayoutElement toArcLayoutElementProto() {
+ return LayoutElementProto.ArcLayoutElement.newBuilder().setDashedLine(mImpl).build();
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return "DashedArcLine{"
+ + "length="
+ + getLength()
+ + ", thickness="
+ + getThickness()
+ + ", color="
+ + getColor()
+ + ", modifiers="
+ + getModifiers()
+ + ", arcDirection="
+ + getArcDirection()
+ + ", linePattern="
+ + getLinePattern()
+ + "}";
+ }
+
+ /** Builder for {@link DashedArcLine}. */
+ @SuppressWarnings("HiddenSuperclass")
+ public static final class Builder implements ArcLayoutElement.Builder {
+ private final LayoutElementProto.DashedArcLine.Builder mImpl =
+ LayoutElementProto.DashedArcLine.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(-1152963772);
+
+ /** Creates an instance of {@link Builder}. */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ public Builder() {}
+
+ /**
+ * Sets the length of this line, in degrees. If not defined, defaults to 0.
+ *
+ * <p>When using a dynamic value, make sure to specify the bounding constraints for the
+ * affected layout element through {@code setLayoutConstraintsForDynamicLength
+ * (AngularLayoutConstraint)} otherwise {@code build()} fails.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setLength(@NonNull DegreesProp length) {
+ mImpl.mergeLength(length.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(length.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the thickness of this line. If not defined, defaults to 0.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setThickness(@Dimension(unit = DP) float thickness) {
+ DpProp thicknessProp = dp(thickness);
+ mImpl.setThickness(thicknessProp.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(thicknessProp.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the color of this line.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setColor(@NonNull ColorProp color) {
+ mImpl.setColor(color.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 3, checkNotNull(color.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets {@link androidx.wear.protolayout.ModifiersBuilders.Modifiers} for this element.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setModifiers(@NonNull ArcModifiers modifiers) {
+ mImpl.setModifiers(modifiers.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 4, checkNotNull(modifiers.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the direction in which this line is drawn. If not set, defaults to
+ * ARC_DIRECTION_CLOCKWISE.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setArcDirection(@NonNull ArcDirectionProp arcDirection) {
+ mImpl.setArcDirection(arcDirection.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 5, checkNotNull(arcDirection.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the direction in which this line is drawn. If not set, defaults to
+ * ARC_DIRECTION_CLOCKWISE.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setArcDirection(@ArcDirection int arcDirection) {
+ return setArcDirection(
+ new ArcDirectionProp.Builder().setValue(arcDirection).build());
+ }
+
+ /**
+ * Sets the dashed line pattern which describes how the arc line is segmented by gaps.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setLinePattern(@NonNull DashedLinePattern linePattern) {
+ mImpl.setLinePattern(linePattern.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 6, checkNotNull(linePattern.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+ /**
+ * Sets the bounding constraints for the layout affected by the dynamic value from
+ * {@link #setLength(DegreesProp)}.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setLayoutConstraintsForDynamicLength(
+ @NonNull AngularLayoutConstraint angularLayoutConstraint) {
+ mImpl.mergeLength(angularLayoutConstraint.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1,
+ checkNotNull(angularLayoutConstraint.getFingerprint())
+ .aggregateValueAsInt());
+ return this;
+ }
+
+ /** Builds an instance with the values accumulated in this Builder. */
+ @SuppressLint("ProtoLayoutMinSchema")
+ @Override
+ @NonNull
+ public DashedArcLine build() {
+ DimensionProto.DegreesProp length = mImpl.getLength();
+ if (length.hasDynamicValue() && !length.hasValueForLayout()) {
+ throw new IllegalStateException(
+ "length with dynamic value requires "
+ + "layoutConstraintsForDynamicLength to be present.");
+ }
+
+ return new DashedArcLine(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+ /** A dashed line pattern which describes how the dashed arc line is segmented by gaps. */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ public static final class DashedLinePattern {
+ private final LayoutElementProto.DashedLinePattern mImpl;
+ @Nullable private final Fingerprint mFingerprint;
+
+ DashedLinePattern(
+ LayoutElementProto.DashedLinePattern impl, @Nullable Fingerprint fingerprint) {
+ this.mImpl = impl;
+ this.mFingerprint = fingerprint;
+ }
+
+ /** Gets the size in dp of the gap between the arc line segments. */
+ @Nullable
+ public DpProp getGapSize() {
+ if (mImpl.hasGapSize()) {
+ return DpProp.fromProto(mImpl.getGapSize());
+ } else {
+ return null;
+ }
+ }
+
+ /** Gets the list of each gap's center location in degrees. */
+ @NonNull
+ public List<DegreesProp> getGapLocations() {
+ List<DegreesProp> list = new ArrayList<>();
+ for (DimensionProto.DegreesProp item : mImpl.getGapLocationsList()) {
+ list.add(DegreesProp.fromProto(item));
+ }
+ return Collections.unmodifiableList(list);
+ }
+
+ /** Get the fingerprint for this object, or null if unknown. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @Nullable
+ public Fingerprint getFingerprint() {
+ return mFingerprint;
+ }
+
+ /** Creates a new wrapper instance from the proto. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public static DashedLinePattern fromProto(
+ @NonNull LayoutElementProto.DashedLinePattern proto,
+ @Nullable Fingerprint fingerprint) {
+ return new DashedLinePattern(proto, fingerprint);
+ }
+
+ @NonNull
+ static DashedLinePattern fromProto(@NonNull LayoutElementProto.DashedLinePattern proto) {
+ return fromProto(proto, null);
+ }
+
+ /** Returns the internal proto instance. */
+ @RestrictTo(Scope.LIBRARY_GROUP)
+ @NonNull
+ public LayoutElementProto.DashedLinePattern toProto() {
+ return mImpl;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return "DashedLinePattern{"
+ + "gapSize="
+ + getGapSize()
+ + ", gapLocations="
+ + getGapLocations()
+ + "}";
+ }
+
+ /** Builder for {@link DashedLinePattern} */
+ public static final class Builder {
+ private final LayoutElementProto.DashedLinePattern.Builder mImpl =
+ LayoutElementProto.DashedLinePattern.newBuilder();
+ private final Fingerprint mFingerprint = new Fingerprint(1050989205);
+
+ /** Creates an instance of {@link Builder}. */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ public Builder() {}
+
+ /**
+ * Sets the size in dp of the gap between the segments. If not defined, defaults to 0.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setGapSize(@Dimension(unit = DP) float gapSizeInDp) {
+ DpProp gapSizeProp = dp(gapSizeInDp);
+ mImpl.setGapSize(gapSizeProp.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 1, checkNotNull(gapSizeProp.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Adds one item to the list of each gap's center location in degrees.
+ *
+ * <p>Note that this field only supports static values.
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ private Builder addGapLocation(@NonNull DegreesProp gapLocation) {
+ if (gapLocation.getDynamicValue() != null) {
+ throw new IllegalArgumentException(
+ "DashedLinePattern.Builder.addGapLocation doesn't support dynamic "
+ + "values.");
+ }
+ mImpl.addGapLocations(gapLocation.toProto());
+ mFingerprint.recordPropertyUpdate(
+ 2, checkNotNull(gapLocation.getFingerprint()).aggregateValueAsInt());
+ return this;
+ }
+
+ /**
+ * Sets the list of each gap's center location in degrees.
+ *
+ * <p>The interval between any two locations could not be shorter than thickness plus
+ * gap size.
+ *
+ * <p>Note that calling this method will invalidate the previous call of {@link
+ * #setGapInterval}
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ public Builder setGapLocations(@NonNull float... gapLocationsInDegrees) {
+ mImpl.clearGapLocations();
+
+ for (float gapLocation: gapLocationsInDegrees) {
+ addGapLocation(degrees(gapLocation));
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the interval length in degrees between two consecutive gap center locations. The
+ * arc line will have arc line segments with equal length.
+ *
+ * <p>The interval could not be shorter than thickness plus gap size.
+ *
+ * <p>Note that calling this method will remove all the gap locations set previously
+ * with {@link #setGapLocations}
+ */
+ @RequiresSchemaVersion(major = 1, minor = 500)
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setGapInterval(float gapIntervalInDegrees) {
+ mImpl.clearGapLocations();
+
+ float gapLocation = gapIntervalInDegrees;
+ while (gapLocation <= 360F) {
+ addGapLocation(degrees(gapLocation));
+ gapLocation += gapIntervalInDegrees;
+ }
+
+ return this;
+ }
+
+ private static final int GAP_COUNTS_LIMIT = 100;
+
+ /** Builds an instance from accumulated values. */
+ @NonNull
+ public DashedLinePattern build() {
+ if (mImpl.getGapLocationsList().size() > GAP_COUNTS_LIMIT) {
+ throw new IllegalArgumentException(
+ "Number of gaps can't be larger than " + GAP_COUNTS_LIMIT + ".");
+ }
+ return new DashedLinePattern(mImpl.build(), mFingerprint);
+ }
+ }
+ }
+
+
/** A simple spacer used to provide padding between adjacent elements in an {@link Arc}. */
@RequiresSchemaVersion(major = 1, minor = 0)
public static final class ArcSpacer implements ArcLayoutElement {
@@ -5871,6 +6325,9 @@
if (proto.hasAdapter()) {
return ArcAdapter.fromProto(proto.getAdapter(), fingerprint);
}
+ if (proto.hasDashedLine()) {
+ return DashedArcLine.fromProto(proto.getDashedLine(), fingerprint);
+ }
throw new IllegalStateException("Proto was not a recognised instance of ArcLayoutElement");
}
diff --git a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java
index 1653411..5605c8b 100644
--- a/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java
+++ b/wear/protolayout/protolayout/src/test/java/androidx/wear/protolayout/LayoutElementBuildersTest.java
@@ -21,6 +21,8 @@
import static androidx.wear.protolayout.DimensionBuilders.expand;
import static androidx.wear.protolayout.DimensionBuilders.sp;
import static androidx.wear.protolayout.DimensionBuilders.weight;
+import static androidx.wear.protolayout.LayoutElementBuilders.ARC_DIRECTION_COUNTER_CLOCKWISE;
+import static androidx.wear.protolayout.LayoutElementBuilders.ARC_DIRECTION_NORMAL;
import static androidx.wear.protolayout.LayoutElementBuilders.FontStyle.ROBOTO_FLEX_FONT;
import static androidx.wear.protolayout.LayoutElementBuilders.TABULAR_OPTION_TAG;
import static androidx.wear.protolayout.LayoutElementBuilders.WEIGHT_AXIS_TAG;
@@ -35,6 +37,9 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.wear.protolayout.expression.AppDataKey;
import androidx.wear.protolayout.expression.DynamicBuilders;
+import androidx.wear.protolayout.LayoutElementBuilders.DashedArcLine;
+import androidx.wear.protolayout.LayoutElementBuilders.DashedLinePattern;
+import androidx.wear.protolayout.proto.ColorProto;
import androidx.wear.protolayout.proto.DimensionProto;
import androidx.wear.protolayout.proto.LayoutElementProto;
import androidx.wear.protolayout.proto.TypesProto;
@@ -467,7 +472,7 @@
@Test
public void testArcs_withSetDirection_correctlySetsValues() {
- int arcLineDirection = LayoutElementBuilders.ARC_DIRECTION_COUNTER_CLOCKWISE;
+ int arcLineDirection = ARC_DIRECTION_COUNTER_CLOCKWISE;
int arcTextDirection = LayoutElementBuilders.ARC_DIRECTION_NORMAL;
int arcDirection = LayoutElementBuilders.ARC_DIRECTION_CLOCKWISE;
@@ -712,4 +717,113 @@
assertThat(fontStyleProto.getPreferredFontFamilies(0)).isEqualTo(expectedFontFamily);
assertThat(fontStyleProto.getPreferredFontFamilies(1)).isEqualTo(fallbackFontFamily);
}
+
+ @Test
+ public void dashedArcLine_length() {
+ DashedArcLine dashedArcLine =
+ new DashedArcLine.Builder()
+ .setLength(DEGREES_PROP)
+ .setLayoutConstraintsForDynamicLength(DEGREES_PROP_CONSTRAINT)
+ .build();
+
+ DimensionProto.DegreesProp lengthProto = dashedArcLine.toProto().getLength();
+
+ assertThat(lengthProto.getValue()).isEqualTo(DEGREES_PROP.getValue());
+ assertThat(lengthProto.getDynamicValue().getStateSource().getSourceKey())
+ .isEqualTo(STATE_KEY);
+ assertThat(lengthProto.getValueForLayout()).isEqualTo(DEGREES_PROP_CONSTRAINT.getValue());
+ assertThat(lengthProto.getAngularAlignmentForLayoutValue())
+ .isEqualTo(DEGREES_PROP_CONSTRAINT.getAngularAlignment());
+ }
+
+ @Test
+ public void dashedArcLine_length_withoutLayoutConstraint_throws() {
+ assertThrows(
+ IllegalStateException.class,
+ () -> new DashedArcLine.Builder().setLength(DEGREES_PROP).build());
+ }
+
+ @Test
+ public void dashedArcLine_thickness() {
+ float thickness = 5F;
+ DashedArcLine dashedArcLine =
+ new DashedArcLine.Builder()
+ .setThickness(thickness)
+ .build();
+
+ assertThat(dashedArcLine.toProto().getThickness().getValue())
+ .isEqualTo(thickness);
+ }
+
+ @Test
+ public void dashedArcLine_color() {
+ String stateKey = "color-key";
+ ColorBuilders.ColorProp color =
+ new ColorBuilders.ColorProp.Builder(Color.BLUE)
+ .setDynamicValue(DynamicBuilders.DynamicColor.from(
+ new AppDataKey<>(stateKey)
+ )).build();
+ DashedArcLine dashedArcLine =
+ new DashedArcLine.Builder()
+ .setColor(color)
+ .build();
+
+ ColorProto.ColorProp colorProto = dashedArcLine.toProto().getColor();
+ assertThat(colorProto.getArgb()).isEqualTo(Color.BLUE);
+ assertThat(colorProto.getDynamicValue().getStateSource().getSourceKey())
+ .isEqualTo(stateKey);
+ }
+
+ @Test
+ public void dashedArcLine_arcDirection() {
+ DashedArcLine dashedArcLine1 =
+ new DashedArcLine.Builder().build();
+ DashedArcLine dashedArcLine2 =
+ new DashedArcLine.Builder()
+ .setArcDirection(ARC_DIRECTION_COUNTER_CLOCKWISE)
+ .build();
+
+ assertThat(dashedArcLine1.toProto().getArcDirection().getValue().getNumber())
+ .isEqualTo(ARC_DIRECTION_NORMAL);
+ assertThat(dashedArcLine2.toProto().getArcDirection().getValue().getNumber())
+ .isEqualTo(ARC_DIRECTION_COUNTER_CLOCKWISE);
+ }
+
+ @Test
+ public void dashedArcLine_brushWithEqualSegments() {
+ DashedArcLine dashedArcLine =
+ new DashedArcLine.Builder()
+ .setLinePattern(
+ new DashedLinePattern.Builder()
+ .setGapSize(4.5F)
+ .setGapInterval(111)
+ .build())
+ .build();
+
+ LayoutElementProto.DashedLinePattern brush = dashedArcLine.getLinePattern().toProto();
+ assertThat(brush.getGapSize().getValue()).isEqualTo(4.5F);
+ List<DimensionProto.DegreesProp> gapLocations =brush.getGapLocationsList();
+ assertThat(gapLocations.get(0).getValue()).isEqualTo(111F);
+ assertThat(gapLocations.get(1).getValue()).isEqualTo(222F);
+ assertThat(gapLocations.get(2).getValue()).isEqualTo(333F);
+ }
+
+ @Test
+ public void dashedArcLine_brushWithNonEqualSegments() {
+ DashedArcLine dashedArcLine =
+ new DashedArcLine.Builder()
+ .setLinePattern(
+ new DashedLinePattern.Builder()
+ .setGapSize(4.5F)
+ .setGapLocations(66F, 111F, 321F, 212F).build())
+ .build();
+
+ LayoutElementProto.DashedLinePattern brush = dashedArcLine.getLinePattern().toProto();
+ assertThat(brush.getGapSize().getValue()).isEqualTo(4.5F);
+ List<DimensionProto.DegreesProp> gapLocations =brush.getGapLocationsList();
+ assertThat(gapLocations.get(0).getValue()).isEqualTo(66F);
+ assertThat(gapLocations.get(1).getValue()).isEqualTo(111F);
+ assertThat(gapLocations.get(2).getValue()).isEqualTo(321F);
+ assertThat(gapLocations.get(3).getValue()).isEqualTo(212F);
+ }
}