blob: 05d9c21e704df59fd7573f937810e9545cda8827 [file] [log] [blame]
/*
* Copyright 2022 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.protolayout.expression;
import static androidx.wear.protolayout.expression.Preconditions.checkNotNull;
import android.annotation.SuppressLint;
import androidx.annotation.ColorInt;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.wear.protolayout.expression.AnimationParameterBuilders.AnimationSpec;
import androidx.wear.protolayout.expression.ConditionScopes.ConditionScope;
import androidx.wear.protolayout.expression.FixedValueBuilders.FixedBool;
import androidx.wear.protolayout.expression.FixedValueBuilders.FixedColor;
import androidx.wear.protolayout.expression.FixedValueBuilders.FixedFloat;
import androidx.wear.protolayout.expression.FixedValueBuilders.FixedInstant;
import androidx.wear.protolayout.expression.FixedValueBuilders.FixedInt32;
import androidx.wear.protolayout.expression.FixedValueBuilders.FixedString;
import androidx.wear.protolayout.expression.StateEntryBuilders.StateEntryValue;
import androidx.wear.protolayout.expression.proto.DynamicProto;
import androidx.wear.protolayout.protobuf.ExtensionRegistryLite;
import androidx.wear.protolayout.protobuf.InvalidProtocolBufferException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Instant;
/** Builders for dynamic primitive types used by layout elements. */
public final class DynamicBuilders {
private DynamicBuilders() {}
/**
* The type of data to provide to a {@link PlatformInt32Source}.
*
* @since 1.2
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
PLATFORM_INT32_SOURCE_TYPE_UNDEFINED,
PLATFORM_INT32_SOURCE_TYPE_CURRENT_HEART_RATE,
PLATFORM_INT32_SOURCE_TYPE_DAILY_STEP_COUNT
})
@Retention(RetentionPolicy.SOURCE)
@ProtoLayoutExperimental
@interface PlatformInt32SourceType {}
/**
* Undefined source.
*
* @since 1.2
*/
@ProtoLayoutExperimental static final int PLATFORM_INT32_SOURCE_TYPE_UNDEFINED = 0;
/**
* The user's current heart rate. Note that to use this data source, your app must already have
* the "BODY_SENSORS" permission granted to it. If this permission is not present, this source
* type will never yield any data.
*
* @since 1.2
*/
@ProtoLayoutExperimental static final int PLATFORM_INT32_SOURCE_TYPE_CURRENT_HEART_RATE = 1;
/**
* The user's current daily steps. This is the number of steps they have taken since midnight,
* and will reset to zero at midnight. Note that to use this data source, your app must already
* have the "ACTIVITY_RECOGNITION" permission granted to it. If this permission is not present,
* this source type will never yield any data.
*
* @since 1.2
*/
@ProtoLayoutExperimental static final int PLATFORM_INT32_SOURCE_TYPE_DAILY_STEP_COUNT = 2;
/**
* The type of arithmetic operation used in {@link ArithmeticInt32Op} and {@link
* ArithmeticFloatOp}.
*
* @since 1.2
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
ARITHMETIC_OP_TYPE_UNDEFINED,
ARITHMETIC_OP_TYPE_ADD,
ARITHMETIC_OP_TYPE_SUBTRACT,
ARITHMETIC_OP_TYPE_MULTIPLY,
ARITHMETIC_OP_TYPE_DIVIDE,
ARITHMETIC_OP_TYPE_MODULO
})
@Retention(RetentionPolicy.SOURCE)
@interface ArithmeticOpType {}
/**
* Undefined operation type.
*
* @since 1.2
*/
static final int ARITHMETIC_OP_TYPE_UNDEFINED = 0;
/**
* Addition.
*
* @since 1.2
*/
static final int ARITHMETIC_OP_TYPE_ADD = 1;
/**
* Subtraction.
*
* @since 1.2
*/
static final int ARITHMETIC_OP_TYPE_SUBTRACT = 2;
/**
* Multiplication.
*
* @since 1.2
*/
static final int ARITHMETIC_OP_TYPE_MULTIPLY = 3;
/**
* Division.
*
* @since 1.2
*/
static final int ARITHMETIC_OP_TYPE_DIVIDE = 4;
/**
* Modulus.
*
* @since 1.2
*/
static final int ARITHMETIC_OP_TYPE_MODULO = 5;
/**
* Rounding mode to use when converting a float to an int32. If the value is larger than {@link
* Integer#MAX_VALUE} or smaller than {@link Integer#MIN_VALUE}, the result of this operation
* will be invalid and will have an invalid value delivered via
* {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
*
* @since 1.2
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({ROUND_MODE_UNDEFINED, ROUND_MODE_FLOOR, ROUND_MODE_ROUND, ROUND_MODE_CEILING})
@Retention(RetentionPolicy.SOURCE)
@interface FloatToInt32RoundMode {}
/**
* An undefined rounding mode.
*
* @since 1.2
*/
static final int ROUND_MODE_UNDEFINED = 0;
/**
* Use floor(x) when rounding.
*
* @since 1.2
*/
static final int ROUND_MODE_FLOOR = 1;
/**
* Use round(x) when rounding (i.e. rounds to the closest int).
*
* @since 1.2
*/
static final int ROUND_MODE_ROUND = 2;
/**
* Use ceil(x) when rounding.
*
* @since 1.2
*/
static final int ROUND_MODE_CEILING = 3;
/**
* The type of comparison used in {@link ComparisonInt32Op} and {@link ComparisonFloatOp}.
*
* @since 1.2
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
COMPARISON_OP_TYPE_UNDEFINED,
COMPARISON_OP_TYPE_EQUALS,
COMPARISON_OP_TYPE_NOT_EQUALS,
COMPARISON_OP_TYPE_LESS_THAN,
COMPARISON_OP_TYPE_LESS_THAN_OR_EQUAL_TO,
COMPARISON_OP_TYPE_GREATER_THAN,
COMPARISON_OP_TYPE_GREATER_THAN_OR_EQUAL_TO
})
@Retention(RetentionPolicy.SOURCE)
@interface ComparisonOpType {}
/**
* Undefined operation type.
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_UNDEFINED = 0;
/**
* Equality check (result = LHS == RHS). For floats, for equality check, small epsilon is used,
* i.e.: (result = abs(LHS - RHS) < epsilon).
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_EQUALS = 1;
/**
* Not equal check (result = LHS != RHS).
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_NOT_EQUALS = 2;
/**
* Strictly less than (result = LHS < RHS).
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_LESS_THAN = 3;
/**
* Less than or equal to (result = LHS <= RHS).
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_LESS_THAN_OR_EQUAL_TO = 4;
/**
* Strictly greater than (result = LHS > RHS).
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_GREATER_THAN = 5;
/**
* Greater than or equal to (result = LHS >= RHS).
*
* @since 1.2
*/
static final int COMPARISON_OP_TYPE_GREATER_THAN_OR_EQUAL_TO = 6;
/**
* The type of logical operation to carry out in a {@link LogicalBoolOp} operation.
*
* @since 1.2
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({LOGICAL_OP_TYPE_UNDEFINED, LOGICAL_OP_TYPE_AND, LOGICAL_OP_TYPE_OR})
@Retention(RetentionPolicy.SOURCE)
@interface LogicalOpType {}
/**
* Undefined operation type.
*
* @since 1.2
*/
static final int LOGICAL_OP_TYPE_UNDEFINED = 0;
/**
* Logical AND.
*
* @since 1.2
*/
static final int LOGICAL_OP_TYPE_AND = 1;
/**
* Logical OR.
*
* @since 1.2
*/
static final int LOGICAL_OP_TYPE_OR = 2;
/**
* The duration part to retrieve using {@link GetDurationPartOp}.
*
* @since 1.2
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@IntDef({
DURATION_PART_TYPE_UNDEFINED,
DURATION_PART_TYPE_TOTAL_DAYS,
DURATION_PART_TYPE_TOTAL_HOURS,
DURATION_PART_TYPE_TOTAL_MINUTES,
DURATION_PART_TYPE_TOTAL_SECONDS,
DURATION_PART_TYPE_DAYS,
DURATION_PART_TYPE_HOURS,
DURATION_PART_TYPE_MINUTES,
DURATION_PART_TYPE_SECONDS
})
@Retention(RetentionPolicy.SOURCE)
@interface DurationPartType {}
/**
* Undefined duration part type.
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_UNDEFINED = 0;
/**
* Total number of days in a duration. The fraction part of the result will be truncated. This
* is based on the standard definition of a day as 24 hours. Notice that the duration can be
* negative, in which case total number of days will be also negative.
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_TOTAL_DAYS = 1;
/**
* Total number of hours in a duration. The fraction part of the result will be truncated.
* Notice that the duration can be negative, in which case total number of hours will be also
* negative.
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_TOTAL_HOURS = 2;
/**
* Total number of minutes in a duration. The fraction part of the result will be truncated.
* Notice that the duration can be negative, in which case total number of minutes will be also
* negative.
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_TOTAL_MINUTES = 3;
/**
* Total number of seconds in a duration. Notice that the duration can be negative, in which
* case total number of seconds will be also negative.
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_TOTAL_SECONDS = 4;
/**
* Number of days part in the duration. This represents the absolute value of the total number
* of days in the duration based on the 24 hours day definition. The fraction part of the result
* will be truncated.
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_DAYS = 5;
/**
* Number of hours part in the duration. This represents the absolute value of remaining hours
* when dividing total hours by hours in a day (24 hours).
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_HOURS = 6;
/**
* Number of minutes part in the duration. This represents the absolute value of remaining
* minutes when dividing total minutes by minutes in an hour (60 minutes).
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_MINUTES = 7;
/**
* Number of seconds part in the duration. This represents the absolute value of remaining
* seconds when dividing total seconds by seconds in a minute (60 seconds).
*
* @since 1.2
*/
static final int DURATION_PART_TYPE_SECONDS = 8;
/**
* A dynamic Int32 which sources its data from some platform data source, e.g. from sensors, or
* the current time.
*
* @since 1.2
*/
@ProtoLayoutExperimental
static final class PlatformInt32Source implements DynamicInt32 {
private final DynamicProto.PlatformInt32Source mImpl;
@Nullable private final Fingerprint mFingerprint;
PlatformInt32Source(
DynamicProto.PlatformInt32Source impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the source to load data from.
*
* @since 1.2
*/
@PlatformInt32SourceType
public int getSourceType() {
return mImpl.getSourceType().getNumber();
}
/** @hide */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
/**
* Creates a new wrapper instance from the proto.
*
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static PlatformInt32Source fromProto(
@NonNull DynamicProto.PlatformInt32Source proto,
@Nullable Fingerprint fingerprint) {
return new PlatformInt32Source(proto, fingerprint);
}
@NonNull
static PlatformInt32Source fromProto(@NonNull DynamicProto.PlatformInt32Source proto) {
return fromProto(proto, null);
}
/**
* Returns the internal proto instance.
*
* @hide
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.PlatformInt32Source toProto() {
return mImpl;
}
/** @hide */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setPlatformSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "PlatformInt32Source{" + "sourceType=" + getSourceType() + "}";
}
/** Builder for {@link PlatformInt32Source}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.PlatformInt32Source.Builder mImpl =
DynamicProto.PlatformInt32Source.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1355180718);
public Builder() {}
/**
* Sets the source to load data from.
*
* @since 1.2
*/
@NonNull
public Builder setSourceType(@PlatformInt32SourceType int sourceType) {
mImpl.setSourceType(DynamicProto.PlatformInt32SourceType.forNumber(sourceType));
mFingerprint.recordPropertyUpdate(1, sourceType);
return this;
}
@Override
@NonNull
public PlatformInt32Source build() {
return new PlatformInt32Source(mImpl.build(), mFingerprint);
}
}
}
/**
* An arithmetic operation, operating on two Int32 instances. This implements simple binary
* operations of the form "result = LHS <op> RHS", where the available operation types are
* described in {@code ArithmeticOpType}.
*
* @since 1.2
*/
static final class ArithmeticInt32Op implements DynamicInt32 {
private final DynamicProto.ArithmeticInt32Op mImpl;
@Nullable private final Fingerprint mFingerprint;
ArithmeticInt32Op(DynamicProto.ArithmeticInt32Op impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets left hand side of the arithmetic operation.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInputLhs() {
if (mImpl.hasInputLhs()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getInputLhs());
} else {
return null;
}
}
/**
* Gets right hand side of the arithmetic operation.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInputRhs() {
if (mImpl.hasInputRhs()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getInputRhs());
} else {
return null;
}
}
/**
* Gets the type of operation to carry out.
*
* @since 1.2
*/
@ArithmeticOpType
public int getOperationType() {
return mImpl.getOperationType().getNumber();
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ArithmeticInt32Op fromProto(@NonNull DynamicProto.ArithmeticInt32Op proto) {
return new ArithmeticInt32Op(proto, null);
}
@NonNull
DynamicProto.ArithmeticInt32Op toProto() {
return mImpl;
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setArithmeticOperation(mImpl).build();
}
/** Builder for {@link ArithmeticInt32Op}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.ArithmeticInt32Op.Builder mImpl =
DynamicProto.ArithmeticInt32Op.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-2012727925);
public Builder() {}
/**
* Sets left hand side of the arithmetic operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputLhs(@NonNull DynamicInt32 inputLhs) {
mImpl.setInputLhs(inputLhs.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(inputLhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets right hand side of the arithmetic operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputRhs(@NonNull DynamicInt32 inputRhs) {
mImpl.setInputRhs(inputRhs.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(inputRhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the type of operation to carry out.
*
* @since 1.2
*/
@NonNull
public Builder setOperationType(@ArithmeticOpType int operationType) {
mImpl.setOperationType(DynamicProto.ArithmeticOpType.forNumber(operationType));
mFingerprint.recordPropertyUpdate(3, operationType);
return this;
}
@Override
@NonNull
public ArithmeticInt32Op build() {
return new ArithmeticInt32Op(mImpl.build(), mFingerprint);
}
}
}
/**
* A dynamic Int32 which sources its data from the tile's state.
*
* @since 1.2
*/
static final class StateInt32Source implements DynamicInt32 {
private final DynamicProto.StateInt32Source mImpl;
@Nullable private final Fingerprint mFingerprint;
StateInt32Source(DynamicProto.StateInt32Source impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public String getSourceKey() {
return mImpl.getSourceKey();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static StateInt32Source fromProto(@NonNull DynamicProto.StateInt32Source proto) {
return new StateInt32Source(proto, null);
}
@NonNull
DynamicProto.StateInt32Source toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setStateSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "StateInt32Source{" + "sourceKey=" + getSourceKey() + "}";
}
/** Builder for {@link StateInt32Source}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.StateInt32Source.Builder mImpl =
DynamicProto.StateInt32Source.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(58614749);
public Builder() {}
/**
* Sets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public Builder setSourceKey(@NonNull String sourceKey) {
mImpl.setSourceKey(sourceKey);
mFingerprint.recordPropertyUpdate(1, sourceKey.hashCode());
return this;
}
@Override
@NonNull
public StateInt32Source build() {
return new StateInt32Source(mImpl.build(), mFingerprint);
}
}
}
/**
* A conditional operator which yields an integer depending on the boolean operand. This
* implements "int result = condition ? value_if_true : value_if_false".
*
* @since 1.2
*/
static final class ConditionalInt32Op implements DynamicInt32 {
private final DynamicProto.ConditionalInt32Op mImpl;
@Nullable private final Fingerprint mFingerprint;
ConditionalInt32Op(
DynamicProto.ConditionalInt32Op impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the condition to use.
*
* @since 1.2
*/
@Nullable
public DynamicBool getCondition() {
if (mImpl.hasCondition()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getCondition());
} else {
return null;
}
}
/**
* Gets the integer to yield if condition is true.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getValueIfTrue() {
if (mImpl.hasValueIfTrue()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getValueIfTrue());
} else {
return null;
}
}
/**
* Gets the integer to yield if condition is false.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getValueIfFalse() {
if (mImpl.hasValueIfFalse()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getValueIfFalse());
} else {
return null;
}
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ConditionalInt32Op fromProto(@NonNull DynamicProto.ConditionalInt32Op proto) {
return new ConditionalInt32Op(proto, null);
}
@NonNull
DynamicProto.ConditionalInt32Op toProto() {
return mImpl;
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setConditionalOp(mImpl).build();
}
/** Builder for {@link ConditionalInt32Op}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.ConditionalInt32Op.Builder mImpl =
DynamicProto.ConditionalInt32Op.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1444834226);
public Builder() {}
/**
* Sets the condition to use.
*
* @since 1.2
*/
@NonNull
public Builder setCondition(@NonNull DynamicBool condition) {
mImpl.setCondition(condition.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(condition.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the integer to yield if condition is true.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfTrue(@NonNull DynamicInt32 valueIfTrue) {
mImpl.setValueIfTrue(valueIfTrue.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(valueIfTrue.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the integer to yield if condition is false.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfFalse(@NonNull DynamicInt32 valueIfFalse) {
mImpl.setValueIfFalse(valueIfFalse.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(valueIfFalse.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ConditionalInt32Op build() {
return new ConditionalInt32Op(mImpl.build(), mFingerprint);
}
}
}
/**
* A conditional operator which yields a float depending on the boolean operand. This implements
* "float result = condition ? value_if_true : value_if_false".
*
* @since 1.2
*/
static final class ConditionalFloatOp implements DynamicFloat {
private final DynamicProto.ConditionalFloatOp mImpl;
@Nullable private final Fingerprint mFingerprint;
ConditionalFloatOp(
DynamicProto.ConditionalFloatOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the condition to use.
*
* @since 1.2
*/
@Nullable
public DynamicBool getCondition() {
if (mImpl.hasCondition()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getCondition());
} else {
return null;
}
}
/**
* Gets the float to yield if condition is true.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getValueIfTrue() {
if (mImpl.hasValueIfTrue()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getValueIfTrue());
} else {
return null;
}
}
/**
* Gets the float to yield if condition is false.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getValueIfFalse() {
if (mImpl.hasValueIfFalse()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getValueIfFalse());
} else {
return null;
}
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ConditionalFloatOp fromProto(@NonNull DynamicProto.ConditionalFloatOp proto) {
return new ConditionalFloatOp(proto, null);
}
@NonNull
DynamicProto.ConditionalFloatOp toProto() {
return mImpl;
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicFloat toDynamicFloatProto() {
return DynamicProto.DynamicFloat.newBuilder().setConditionalOp(mImpl).build();
}
/** Builder for {@link ConditionalFloatOp}. */
public static final class Builder implements DynamicFloat.Builder {
private final DynamicProto.ConditionalFloatOp.Builder mImpl =
DynamicProto.ConditionalFloatOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1968171153);
public Builder() {}
/**
* Sets the condition to use.
*
* @since 1.2
*/
@NonNull
public Builder setCondition(@NonNull DynamicBool condition) {
mImpl.setCondition(condition.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(condition.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the float to yield if condition is true.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfTrue(@NonNull DynamicFloat valueIfTrue) {
mImpl.setValueIfTrue(valueIfTrue.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(valueIfTrue.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the float to yield if condition is false.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfFalse(@NonNull DynamicFloat valueIfFalse) {
mImpl.setValueIfFalse(valueIfFalse.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(valueIfFalse.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ConditionalFloatOp build() {
return new ConditionalFloatOp(mImpl.build(), mFingerprint);
}
}
}
/**
* Converts a Float to an Int32, with a customizable rounding mode.
*
* @since 1.2
*/
static final class FloatToInt32Op implements DynamicInt32 {
private final DynamicProto.FloatToInt32Op mImpl;
@Nullable private final Fingerprint mFingerprint;
FloatToInt32Op(DynamicProto.FloatToInt32Op impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the float to round.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets the rounding mode to use. Defaults to ROUND_MODE_FLOOR if not specified.
*
* @since 1.2
*/
@FloatToInt32RoundMode
public int getRoundMode() {
return mImpl.getRoundMode().getNumber();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static FloatToInt32Op fromProto(@NonNull DynamicProto.FloatToInt32Op proto) {
return new FloatToInt32Op(proto, null);
}
@NonNull
DynamicProto.FloatToInt32Op toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setFloatToInt(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "FloatToInt32Op{"
+ "input="
+ getInput()
+ ", roundMode="
+ getRoundMode()
+ "}";
}
/** Builder for {@link FloatToInt32Op}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.FloatToInt32Op.Builder mImpl =
DynamicProto.FloatToInt32Op.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1272973414);
public Builder() {}
/**
* Sets the float to round.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicFloat input) {
mImpl.setInput(input.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the rounding mode to use. Defaults to ROUND_MODE_FLOOR if not specified.
*
* @since 1.2
*/
@NonNull
public Builder setRoundMode(@FloatToInt32RoundMode int roundMode) {
mImpl.setRoundMode(DynamicProto.FloatToInt32RoundMode.forNumber(roundMode));
mFingerprint.recordPropertyUpdate(2, roundMode);
return this;
}
@Override
@NonNull
public FloatToInt32Op build() {
return new FloatToInt32Op(mImpl.build(), mFingerprint);
}
}
}
/**
* A static interpolation node, between two fixed int32 values.
*
* @since 1.2
*/
static final class AnimatableFixedInt32 implements DynamicInt32 {
private final DynamicProto.AnimatableFixedInt32 mImpl;
@Nullable private final Fingerprint mFingerprint;
AnimatableFixedInt32(
DynamicProto.AnimatableFixedInt32 impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the value to start animating from.
*
* @since 1.2
*/
public int getFromValue() {
return mImpl.getFromValue();
}
/**
* Gets the value to animate to.
*
* @since 1.2
*/
public int getToValue() {
return mImpl.getToValue();
}
/**
* Gets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@Nullable
public AnimationSpec getAnimationSpec() {
if (mImpl.hasAnimationSpec()) {
return AnimationSpec.fromProto(mImpl.getAnimationSpec());
} 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 AnimatableFixedInt32 fromProto(
@NonNull DynamicProto.AnimatableFixedInt32 proto,
@Nullable Fingerprint fingerprint) {
return new AnimatableFixedInt32(proto, fingerprint);
}
@NonNull
static AnimatableFixedInt32 fromProto(@NonNull DynamicProto.AnimatableFixedInt32 proto) {
return fromProto(proto, null);
}
/** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.AnimatableFixedInt32 toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setAnimatableFixed(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "AnimatableFixedInt32{"
+ "fromValue="
+ getFromValue()
+ ", toValue="
+ getToValue()
+ ", animationSpec="
+ getAnimationSpec()
+ "}";
}
/** Builder for {@link AnimatableFixedInt32}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.AnimatableFixedInt32.Builder mImpl =
DynamicProto.AnimatableFixedInt32.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1831435966);
public Builder() {}
/**
* Sets the value to start animating from.
*
* @since 1.2
*/
@NonNull
public AnimatableFixedInt32.Builder setFromValue(int fromValue) {
mImpl.setFromValue(fromValue);
mFingerprint.recordPropertyUpdate(1, fromValue);
return this;
}
/**
* Sets the value to animate to.
*
* @since 1.2
*/
@NonNull
public AnimatableFixedInt32.Builder setToValue(int toValue) {
mImpl.setToValue(toValue);
mFingerprint.recordPropertyUpdate(2, toValue);
return this;
}
/**
* Sets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@NonNull
public Builder setAnimationSpec(@NonNull AnimationSpec animationSpec) {
mImpl.setAnimationSpec(animationSpec.toProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(animationSpec.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public AnimatableFixedInt32 build() {
return new AnimatableFixedInt32(mImpl.build(), mFingerprint);
}
}
}
/**
* A dynamic interpolation node. This will watch the value of its input and, when the first
* update arrives, immediately emit that value. On subsequent updates, it will animate between
* the old and new values.
*
* <p>If this node receives an invalid value (e.g. as a result of an upstream node having no
* value), then it will emit a single invalid value, and forget its "stored" value. The next
* valid value that arrives is then used as the "first" value again.
*
* @since 1.2
*/
static final class AnimatableDynamicInt32 implements DynamicInt32 {
private final DynamicProto.AnimatableDynamicInt32 mImpl;
@Nullable private final Fingerprint mFingerprint;
AnimatableDynamicInt32(
DynamicProto.AnimatableDynamicInt32 impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the value to watch, and animate when it changes.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInput() {
if (mImpl.hasInput()) {
return dynamicInt32FromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@Nullable
public AnimationSpec getAnimationSpec() {
if (mImpl.hasAnimationSpec()) {
return AnimationSpec.fromProto(mImpl.getAnimationSpec());
} 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 AnimatableDynamicInt32 fromProto(
@NonNull DynamicProto.AnimatableDynamicInt32 proto,
@Nullable Fingerprint fingerprint) {
return new AnimatableDynamicInt32(proto, fingerprint);
}
@NonNull
static AnimatableDynamicInt32 fromProto(
@NonNull DynamicProto.AnimatableDynamicInt32 proto) {
return fromProto(proto, null);
}
/** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.AnimatableDynamicInt32 toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setAnimatableDynamic(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "AnimatableDynamicInt32{"
+ "input="
+ getInput()
+ ", animationSpec="
+ getAnimationSpec()
+ "}";
}
/** Builder for {@link AnimatableDynamicInt32}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.AnimatableDynamicInt32.Builder mImpl =
DynamicProto.AnimatableDynamicInt32.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1554674954);
public Builder() {}
/**
* Sets the value to watch, and animate when it changes.
*
* @since 1.2
*/
@NonNull
public AnimatableDynamicInt32.Builder setInput(@NonNull DynamicInt32 input) {
mImpl.setInput(input.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@NonNull
public Builder setAnimationSpec(@NonNull AnimationSpec animationSpec) {
mImpl.setAnimationSpec(animationSpec.toProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(animationSpec.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public AnimatableDynamicInt32 build() {
return new AnimatableDynamicInt32(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic int32 type.
*
* <p>It offers a set of helper methods for creating arithmetic and logical expressions, e.g.
* {@link #plus(int)}, {@link #times(int)}, {@link #eq(int)}, etc. These helper methods produce
* expression trees based on the order in which they were called in an expression. Thus, no
* operator precedence rules are applied.
*
* <p>For example the following expression is equivalent to {@code result = ((a + b)*c)/d }:
*
* <pre>{@code
* a.plus(b).times(c).div(d);
* }</pre>
*
* More complex expressions can be created by nesting expressions. For example the following
* expression is equivalent to {@code result = (a + b)*(c - d) }:
*
* <pre>{@code
* (a.plus(b)).times(c.minus(d));
* }</pre>
*
* @since 1.2
*/
public interface DynamicInt32 extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicInt32 toDynamicInt32Proto();
/**
* Creates a {@link DynamicInt32} from a byte array generated by {@link
* #toDynamicInt32ByteArray()}.
*/
@NonNull
static DynamicInt32 fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicInt32FromProto(
DynamicProto.DynamicInt32.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicInt32", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicInt32ByteArray() {
return toDynamicInt32Proto().toByteArray();
}
/** Creates a constant-valued {@link DynamicInt32}. */
@NonNull
static DynamicInt32 constant(int constant) {
return new FixedInt32.Builder().setValue(constant).build();
}
/**
* Creates a {@link DynamicInt32} that is bound to the value of an item of the State.
*
* @param stateKey The key to a {@link StateEntryValue} with an int value from the
* provider's state.
*/
@NonNull
static DynamicInt32 fromState(@NonNull String stateKey) {
return new StateInt32Source.Builder().setSourceKey(stateKey).build();
}
/**
* Creates a {@link DynamicInt32} which will animate from {@code start} to {@code end}.
*
* @param start The start value of the range.
* @param end The end value of the range.
*/
@NonNull
static DynamicInt32 animate(int start, int end) {
return new AnimatableFixedInt32.Builder().setFromValue(start).setToValue(end).build();
}
/**
* Creates a {@link DynamicInt32} which will animate from {@code start} to {@code end} with
* the given animation parameters.
*
* @param start The start value of the range.
* @param end The end value of the range.
* @param animationSpec The animation parameters.
*/
@NonNull
static DynamicInt32 animate(int start, int end, @NonNull AnimationSpec animationSpec) {
return new AnimatableFixedInt32.Builder()
.setFromValue(start)
.setToValue(end)
.setAnimationSpec(animationSpec)
.build();
}
/**
* Creates a {@link DynamicInt32} that is bound to the value of an item of the State. Every
* time the state value changes, this {@link DynamicInt32} will animate from its current
* value to the new value (from the state).
*
* @param stateKey The key to a {@link StateEntryValue} with an int value from the
* provider's state.
*/
@NonNull
static DynamicInt32 animate(@NonNull String stateKey) {
return new AnimatableDynamicInt32.Builder().setInput(fromState(stateKey)).build();
}
/**
* Creates a {@link DynamicInt32} that is bound to the value of an item of the State. Every
* time the state value changes, this {@link DynamicInt32} will animate from its current
* value to the new value (from the state).
*
* @param stateKey The key to a {@link StateEntryValue} with an int value from the
* provider's state.
* @param animationSpec The animation parameters.
*/
@NonNull
static DynamicInt32 animate(
@NonNull String stateKey, @NonNull AnimationSpec animationSpec) {
return new AnimatableDynamicInt32.Builder()
.setInput(fromState(stateKey))
.setAnimationSpec(animationSpec)
.build();
}
/**
* Returns a {@link DynamicInt32} that is bound to the value of this {@link DynamicInt32}
* and every time its value is changing, it animates from its current value to the new
* value.
*
* @param animationSpec The animation parameters.
*/
@NonNull
default DynamicInt32 animate(@NonNull AnimationSpec animationSpec) {
return new AnimatableDynamicInt32.Builder()
.setInput(this)
.setAnimationSpec(animationSpec)
.build();
}
/**
* Returns a {@link DynamicInt32} that is bound to the value of this {@link DynamicInt32}
* and every time its value is changing, it animates from its current value to the new
* value.
*/
@NonNull
default DynamicInt32 animate() {
return new AnimatableDynamicInt32.Builder().setInput(this).build();
}
/**
* Convert the value represented by this {@link DynamicInt32} into a {@link DynamicFloat}.
*/
@NonNull
default DynamicFloat asFloat() {
return new Int32ToFloatOp.Builder().setInput(this).build();
}
/**
* Bind the value of this {@link DynamicInt32} to the result of a conditional expression.
* This will use the value given in either {@link ConditionScope#use} or {@link
* ConditionScopes.IfTrueScope#elseUse} depending on the value yielded from {@code
* condition}.
*/
@NonNull
static ConditionScope<DynamicInt32, Integer> onCondition(@NonNull DynamicBool condition) {
return new ConditionScopes.ConditionScope<>(
(trueValue, falseValue) ->
new ConditionalInt32Op.Builder()
.setCondition(condition)
.setValueIfTrue(trueValue)
.setValueIfFalse(falseValue)
.build(),
DynamicInt32::constant);
}
/**
* Creates a {@link DynamicInt32} containing the result of adding another {@link
* DynamicInt32} to this {@link DynamicInt32}; As an example, the following is equal to
* {@code DynamicInt32.constant(13)}
*
* <pre>
* DynamicInt32.constant(7).plus(DynamicInt32.constant(6));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 plus(@NonNull DynamicInt32 other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicFlaot} containing the result of adding a {@link DynamicFloat} to
* this {@link DynamicInt32}; As an example, the following is equal to {@code
* DynamicFloat.constant(13.5f)}
*
* <pre>
* DynamicInt32.constant(7).plus(DynamicFloat.constant(6.5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat plus(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of adding an integer to this {@link
* DynamicInt32}; As an example, the following is equal to {@code DynamicInt32.constant(13)}
*
* <pre>
* DynamicInt32.constant(7).plus(6);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 plus(int other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicFlaot} containing the result of adding a float to this {@link
* DynamicInt32}; As an example, the following is equal to {@code
* DynamicFloat.constant(13.5f)}
*
* <pre>
* DynamicInt32.constant(7).plus(6.5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat plus(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(DynamicFloat.constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of subtracting another {@link
* DynamicInt32} from this {@link DynamicInt32}; As an example, the following is equal to
* {@code DynamicInt32.constant(2)}
*
* <pre>
* DynamicInt32.constant(7).minus(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 minus(@NonNull DynamicInt32 other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of subtracting a {@link
* DynamicFloat} from this {@link DynamicInt32}; As an example, the following is equal to
* {@code DynamicFloat.constant(1.5f)}
*
* <pre>
* DynamicInt32.constant(7).minus(DynamicFloat.constant(5.5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat minus(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of subtracting an integer from this
* {@link DynamicInt32}; As an example, the following is equal to {@code
* DynamicInt32.constant(2)}
*
* <pre>
* DynamicInt32.constant(7).minus(5);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 minus(int other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of subtracting a float from this
* {@link DynamicInt32}; As an example, the following is equal to {@code
* DynamicFloat.constant(1.5f)}
*
* <pre>
* DynamicInt32.constant(7).minus(5.5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat minus(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(DynamicFloat.constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of multiplying this {@link
* DynamicInt32} by another {@link DynamicInt32}; As an example, the following is equal to
* {@code DynamicInt32.constant(35)}
*
* <pre>
* DynamicInt32.constant(7).times(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 times(@NonNull DynamicInt32 other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of multiplying this {@link
* DynamicInt32} by a {@link DynamicFloat}; As an example, the following is equal to {@code
* DynamicFloat.constant(38.5f)}
*
* <pre>
* DynamicInt32.constant(7).times(DynamicFloat.constant(5.5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat times(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of multiplying this {@link
* DynamicInt32} by an integer; As an example, the following is equal to {@code
* DynamicInt32.constant(35)}
*
* <pre>
* DynamicInt32.constant(7).times(5);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 times(int other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of multiplying this {@link
* DynamicInt32} by a float; As an example, the following is equal to {@code
* DynamicFloat.constant(38.5f)}
*
* <pre>
* DynamicInt32.constant(7).times(5.5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat times(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(DynamicFloat.constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of dividing this {@link
* DynamicInt32} by another {@link DynamicInt32}; As an example, the following is equal to
* {@code DynamicInt32.constant(1)}
*
* <pre>
* DynamicInt32.constant(7).div(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 div(@NonNull DynamicInt32 other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of dividing this {@link
* DynamicInt32} by a {@link DynamicFloat}; As an example, the following is equal to {@code
* DynamicFloat.constant(1.4f)}
*
* <pre>
* DynamicInt32.constant(7).div(DynamicFloat.constant(5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat div(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the result of dividing this {@link
* DynamicInt32} by an integer; As an example, the following is equal to {@code
* DynamicInt32.constant(1)}
*
* <pre>
* DynamicInt32.constant(7).div(5);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 div(int other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of dividing this {@link
* DynamicInt32} by a float; As an example, the following is equal to {@code
* DynamicFloat.constant(1.4f)}
*
* <pre>
* DynamicInt32.constant(7).div(5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat div(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(DynamicFloat.constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the reminder of dividing this {@link
* DynamicInt32} by another {@link DynamicInt32}; As an example, the following is equal to
* {@code DynamicInt32.constant(2)}
*
* <pre>
* DynamicInt32.constant(7).rem(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 rem(@NonNull DynamicInt32 other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the reminder of dividing this {@link
* DynamicInt32} by a {@link DynamicFloat}; As an example, the following is equal to {@code
* DynamicFloat.constant(1.5f)}
*
* <pre>
* DynamicInt32.constant(7).rem(DynamicInt32.constant(5.5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat rem(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the reminder of dividing this {@link
* DynamicInt32} by an integer; As an example, the following is equal to {@code
* DynamicInt32.constant(2)}
*
* <pre>
* DynamicInt32.constant(7).rem(5);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicInt32} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicInt32 rem(int other) {
return new ArithmeticInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Creates a {@link DynamicInt32} containing the reminder of dividing this {@link
* DynamicInt32} by a float; As an example, the following is equal to {@code
* DynamicFloat.constant(1.5f)}
*
* <pre>
* DynamicInt32.constant(7).rem(5.5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat rem(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this.asFloat())
.setInputRhs(DynamicFloat.constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} and
* {@code other} are equal, otherwise it's false.
*/
@NonNull
default DynamicBool eq(@NonNull DynamicInt32 other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} and
* {@code other} are equal, otherwise it's false.
*/
@NonNull
default DynamicBool eq(int other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} and
* {@code other} are not equal, otherwise it's false.
*/
@NonNull
default DynamicBool ne(@NonNull DynamicInt32 other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_NOT_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} and
* {@code other} are not equal, otherwise it's false.
*/
@NonNull
default DynamicBool ne(int other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_NOT_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* less than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lt(@NonNull DynamicInt32 other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* less than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lt(int other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* less than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lte(@NonNull DynamicInt32 other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* less than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lte(int other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* greater than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gt(@NonNull DynamicInt32 other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* greater than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gt(int other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* greater than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gte(@NonNull DynamicInt32 other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicInt32} is
* greater than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gte(int other) {
return new ComparisonInt32Op.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicString} that contains the formatted value of this {@link
* DynamicInt32} (with default formatting parameters). As an example, for locale en_US, the
* following is equal to {@code DynamicString.constant("12")}
*
* <pre>
* DynamicInt32.constant(12).format()
* </pre>
*
* The resulted {@link DynamicString} is subject to being truncated if it's too long.
*/
@NonNull
default DynamicString format() {
return new IntFormatter.Builder().build().getInt32FormatOp(this);
}
/**
* Returns a {@link DynamicString} that contains the formatted value of this {@link
* DynamicInt32}. As an example, for locale en_US, the following is equal to {@code
* DynamicString.constant("0,012")}
*
* <pre>
* DynamicInt32.constant(12)
* .format(
* new IntFormatter.Builder()
* .setMinIntegerDigits(4)
* .setGroupingUsed(true)
* .build());
* </pre>
*
* @param formatter The formatting parameter.
*/
@NonNull
default DynamicString format(@NonNull IntFormatter formatter) {
return formatter.getInt32FormatOp(this);
}
/** Allows formatting {@link DynamicInt32} into a {@link DynamicString}. */
class IntFormatter {
private final Int32FormatOp.Builder mInt32FormatOpBuilder;
private final Int32FormatOp mInt32FormatOp;
IntFormatter(@NonNull Int32FormatOp.Builder int32FormatOpBuilder) {
mInt32FormatOpBuilder = int32FormatOpBuilder;
mInt32FormatOp = int32FormatOpBuilder.build();
}
@NonNull
Int32FormatOp getInt32FormatOp(@NonNull DynamicInt32 dynamicInt32) {
return mInt32FormatOpBuilder.setInput(dynamicInt32).build();
}
/** Returns the minimum number of digits allowed in the integer portion of a number. */
@IntRange(from = 0)
public int getMinIntegerDigits() {
return mInt32FormatOp.getMinIntegerDigits();
}
/** Returns whether digit grouping is used or not. */
public boolean isGroupingUsed() {
return mInt32FormatOp.getGroupingUsed();
}
/** Builder to create {@link IntFormatter} objects. */
public static final class Builder {
private static final int MAX_INTEGER_PART_LENGTH = 15;
final Int32FormatOp.Builder mBuilder;
public Builder() {
mBuilder = new Int32FormatOp.Builder();
}
/**
* Sets minimum number of integer digits for the formatter. Defaults to one if not
* specified. If minIntegerDigits is zero and the -1 < input < 1, the Integer
* part will not appear.
*/
@NonNull
public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
mBuilder.setMinIntegerDigits(minIntegerDigits);
return this;
}
/**
* Sets whether grouping is used for the formatter. Defaults to false if not
* specified. If grouping is used, digits will be grouped into digit groups using a
* separator. Digit group size and used separator can vary in different
* countries/regions. As an example, for locale en_US, the following is equal to
* {@code * DynamicString.constant("1,234")}
*
* <pre>
* DynamicInt32.constant(1234)
* .format(
* new IntFormatter.Builder()
* .setGroupingUsed(true).build());
* </pre>
*/
@NonNull
public Builder setGroupingUsed(boolean groupingUsed) {
mBuilder.setGroupingUsed(groupingUsed);
return this;
}
/** Builds an instance with values accumulated in this Builder. */
@NonNull
public IntFormatter build() {
throwIfExceedingMaxValue(
"MinIntegerDigits",
mBuilder.build().getMinIntegerDigits(),
MAX_INTEGER_PART_LENGTH);
return new IntFormatter(mBuilder);
}
private static void throwIfExceedingMaxValue(
String paramName, int value, int maxValue) {
if (value > maxValue) {
throw new IllegalArgumentException(
String.format(
"%s (%d) is too large. Maximum value for %s is %d",
paramName, value, paramName, maxValue));
}
}
}
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicInt32} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicInt32 build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicInt32 dynamicInt32FromProto(@NonNull DynamicProto.DynamicInt32 proto) {
if (proto.hasFixed()) {
return FixedInt32.fromProto(proto.getFixed());
}
if (proto.hasPlatformSource()) {
return PlatformInt32Source.fromProto(proto.getPlatformSource());
}
if (proto.hasArithmeticOperation()) {
return ArithmeticInt32Op.fromProto(proto.getArithmeticOperation());
}
if (proto.hasStateSource()) {
return StateInt32Source.fromProto(proto.getStateSource());
}
if (proto.hasConditionalOp()) {
return ConditionalInt32Op.fromProto(proto.getConditionalOp());
}
if (proto.hasFloatToInt()) {
return FloatToInt32Op.fromProto(proto.getFloatToInt());
}
if (proto.hasDurationPart()) {
return GetDurationPartOp.fromProto(proto.getDurationPart());
}
if (proto.hasAnimatableFixed()) {
return AnimatableFixedInt32.fromProto(proto.getAnimatableFixed());
}
if (proto.hasAnimatableDynamic()) {
return AnimatableDynamicInt32.fromProto(proto.getAnimatableDynamic());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicInt32");
}
/**
* Simple formatting for dynamic int32.
*
* @since 1.2
*/
static final class Int32FormatOp implements DynamicString {
private final DynamicProto.Int32FormatOp mImpl;
@Nullable private final Fingerprint mFingerprint;
Int32FormatOp(DynamicProto.Int32FormatOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the source of Int32 data to convert to a string.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets minimum integer digits. Sign and grouping characters are not considered when
* applying minIntegerDigits constraint. If not defined, defaults to one. For example, for
* locale en_US, applying minIntegerDigit=4 to 12 would yield "0012".
*
* @since 1.2
*/
@IntRange(from = 0)
public int getMinIntegerDigits() {
return mImpl.getMinIntegerDigits();
}
/**
* Gets digit grouping used. Grouping size and grouping character depend on the current
* locale. If not defined, defaults to false. For example, for locale en_US, using grouping
* with 1234 would yield "1,234".
*
* @since 1.2
*/
public boolean getGroupingUsed() {
return mImpl.getGroupingUsed();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static Int32FormatOp fromProto(@NonNull DynamicProto.Int32FormatOp proto) {
return new Int32FormatOp(proto, null);
}
@NonNull
DynamicProto.Int32FormatOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicString toDynamicStringProto() {
return DynamicProto.DynamicString.newBuilder().setInt32FormatOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "Int32FormatOp{"
+ "input="
+ getInput()
+ ", minIntegerDigits="
+ getMinIntegerDigits()
+ ", groupingUsed="
+ getGroupingUsed()
+ "}";
}
/** Builder for {@link Int32FormatOp}. */
public static final class Builder implements DynamicString.Builder {
final DynamicProto.Int32FormatOp.Builder mImpl =
DynamicProto.Int32FormatOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(196209833);
public Builder() {}
/**
* Sets the source of Int32 data to convert to a string.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicInt32 input) {
mImpl.setInput(input.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets minimum integer digits. Sign and grouping characters are not considered when
* applying minIntegerDigits constraint. If not defined, defaults to one. For example,
* for locale en_US, applying minIntegerDigit=4 to 12 would yield "0012".
*
* @since 1.2
*/
@NonNull
public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
mImpl.setMinIntegerDigits(minIntegerDigits);
mFingerprint.recordPropertyUpdate(4, minIntegerDigits);
return this;
}
/**
* Sets digit grouping used. Grouping size and grouping character depend on the current
* locale. If not defined, defaults to false. For example, for locale en_US, using
* grouping with 1234 would yield "1,234".
*
* @since 1.2
*/
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setGroupingUsed(boolean groupingUsed) {
mImpl.setGroupingUsed(groupingUsed);
mFingerprint.recordPropertyUpdate(5, Boolean.hashCode(groupingUsed));
return this;
}
@Override
@NonNull
public Int32FormatOp build() {
return new Int32FormatOp(mImpl.build(), mFingerprint);
}
}
}
/**
* A dynamic String which sources its data from the tile's state.
*
* @since 1.2
*/
static final class StateStringSource implements DynamicString {
private final DynamicProto.StateStringSource mImpl;
@Nullable private final Fingerprint mFingerprint;
StateStringSource(DynamicProto.StateStringSource impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public String getSourceKey() {
return mImpl.getSourceKey();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static StateStringSource fromProto(@NonNull DynamicProto.StateStringSource proto) {
return new StateStringSource(proto, null);
}
@NonNull
DynamicProto.StateStringSource toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicString toDynamicStringProto() {
return DynamicProto.DynamicString.newBuilder().setStateSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "StateStringSource{" + "sourceKey=" + getSourceKey() + "}";
}
/** Builder for {@link StateStringSource}. */
public static final class Builder implements DynamicString.Builder {
private final DynamicProto.StateStringSource.Builder mImpl =
DynamicProto.StateStringSource.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1261652090);
public Builder() {}
/**
* Sets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public Builder setSourceKey(@NonNull String sourceKey) {
mImpl.setSourceKey(sourceKey);
mFingerprint.recordPropertyUpdate(1, sourceKey.hashCode());
return this;
}
@Override
@NonNull
public StateStringSource build() {
return new StateStringSource(mImpl.build(), mFingerprint);
}
}
}
/**
* A conditional operator which yields an string depending on the boolean operand. This
* implements "string result = condition ? value_if_true : value_if_false".
*
* @since 1.2
*/
static final class ConditionalStringOp implements DynamicString {
private final DynamicProto.ConditionalStringOp mImpl;
@Nullable private final Fingerprint mFingerprint;
ConditionalStringOp(
DynamicProto.ConditionalStringOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the condition to use.
*
* @since 1.2
*/
@Nullable
public DynamicBool getCondition() {
if (mImpl.hasCondition()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getCondition());
} else {
return null;
}
}
/**
* Gets the string to yield if condition is true.
*
* @since 1.2
*/
@Nullable
public DynamicString getValueIfTrue() {
if (mImpl.hasValueIfTrue()) {
return DynamicBuilders.dynamicStringFromProto(mImpl.getValueIfTrue());
} else {
return null;
}
}
/**
* Gets the string to yield if condition is false.
*
* @since 1.2
*/
@Nullable
public DynamicString getValueIfFalse() {
if (mImpl.hasValueIfFalse()) {
return DynamicBuilders.dynamicStringFromProto(mImpl.getValueIfFalse());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ConditionalStringOp fromProto(@NonNull DynamicProto.ConditionalStringOp proto) {
return new ConditionalStringOp(proto, null);
}
@NonNull
DynamicProto.ConditionalStringOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicString toDynamicStringProto() {
return DynamicProto.DynamicString.newBuilder().setConditionalOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "ConditionalStringOp{"
+ "condition="
+ getCondition()
+ ", valueIfTrue="
+ getValueIfTrue()
+ ", valueIfFalse="
+ getValueIfFalse()
+ "}";
}
/** Builder for {@link ConditionalStringOp}. */
public static final class Builder implements DynamicString.Builder {
private final DynamicProto.ConditionalStringOp.Builder mImpl =
DynamicProto.ConditionalStringOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1535849633);
public Builder() {}
/**
* Sets the condition to use.
*
* @since 1.2
*/
@NonNull
public Builder setCondition(@NonNull DynamicBool condition) {
mImpl.setCondition(condition.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(condition.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the string to yield if condition is true.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfTrue(@NonNull DynamicString valueIfTrue) {
mImpl.setValueIfTrue(valueIfTrue.toDynamicStringProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(valueIfTrue.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the string to yield if condition is false.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfFalse(@NonNull DynamicString valueIfFalse) {
mImpl.setValueIfFalse(valueIfFalse.toDynamicStringProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(valueIfFalse.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ConditionalStringOp build() {
return new ConditionalStringOp(mImpl.build(), mFingerprint);
}
}
}
/**
* This implements simple string concatenation "result = LHS+RHS".
*
* @since 1.2
*/
static final class ConcatStringOp implements DynamicString {
private final DynamicProto.ConcatStringOp mImpl;
@Nullable private final Fingerprint mFingerprint;
ConcatStringOp(DynamicProto.ConcatStringOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets left hand side of the concatenation operation.
*
* @since 1.2
*/
@Nullable
public DynamicString getInputLhs() {
if (mImpl.hasInputLhs()) {
return DynamicBuilders.dynamicStringFromProto(mImpl.getInputLhs());
} else {
return null;
}
}
/**
* Gets right hand side of the concatenation operation.
*
* @since 1.2
*/
@Nullable
public DynamicString getInputRhs() {
if (mImpl.hasInputRhs()) {
return DynamicBuilders.dynamicStringFromProto(mImpl.getInputRhs());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ConcatStringOp fromProto(@NonNull DynamicProto.ConcatStringOp proto) {
return new ConcatStringOp(proto, null);
}
@NonNull
DynamicProto.ConcatStringOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicString toDynamicStringProto() {
return DynamicProto.DynamicString.newBuilder().setConcatOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "ConcatStringOp{"
+ "inputLhs="
+ getInputLhs()
+ ", inputRhs="
+ getInputRhs()
+ "}";
}
/** Builder for {@link ConcatStringOp}. */
public static final class Builder implements DynamicString.Builder {
private final DynamicProto.ConcatStringOp.Builder mImpl =
DynamicProto.ConcatStringOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1516620377);
public Builder() {}
/**
* Sets left hand side of the concatenation operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputLhs(@NonNull DynamicString inputLhs) {
mImpl.setInputLhs(inputLhs.toDynamicStringProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(inputLhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets right hand side of the concatenation operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputRhs(@NonNull DynamicString inputRhs) {
mImpl.setInputRhs(inputRhs.toDynamicStringProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(inputRhs.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ConcatStringOp build() {
return new ConcatStringOp(mImpl.build(), mFingerprint);
}
}
}
/**
* Simple formatting for dynamic floats.
*
* @since 1.2
*/
static final class FloatFormatOp implements DynamicString {
private final DynamicProto.FloatFormatOp mImpl;
@Nullable private final Fingerprint mFingerprint;
FloatFormatOp(DynamicProto.FloatFormatOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the source of Float data to convert to a string.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets maximum fraction digits. Rounding will be applied if maxFractionDigits is smaller
* than number of fraction digits. If not defined, defaults to three. minimumFractionDigits
* must be <= maximumFractionDigits. If the condition is not satisfied, then
* minimumFractionDigits will be used for both fields.
*
* @since 1.2
*/
@IntRange(from = 0)
public int getMaxFractionDigits() {
return mImpl.getMaxFractionDigits();
}
/**
* Gets minimum fraction digits. Zeros will be appended to the end to satisfy this
* constraint. If not defined, defaults to zero. minimumFractionDigits must be <=
* maximumFractionDigits. If the condition is not satisfied, then minimumFractionDigits will
* be used for both fields.
*
* @since 1.2
*/
@IntRange(from = 0)
public int getMinFractionDigits() {
return mImpl.getMinFractionDigits();
}
/**
* Gets minimum integer digits. Sign and grouping characters are not considered when
* applying minIntegerDigits constraint. If not defined, defaults to one. For example, for
* locale en_US, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
*
* @since 1.2
*/
@IntRange(from = 0)
public int getMinIntegerDigits() {
return mImpl.getMinIntegerDigits();
}
/**
* Gets digit grouping used. Grouping size and grouping character depend on the current
* locale. If not defined, defaults to false. For example, for locale en_US, using grouping
* with 1234.56 would yield "1,234.56".
*
* @since 1.2
*/
public boolean getGroupingUsed() {
return mImpl.getGroupingUsed();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static FloatFormatOp fromProto(@NonNull DynamicProto.FloatFormatOp proto) {
return new FloatFormatOp(proto, null);
}
@NonNull
DynamicProto.FloatFormatOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicString toDynamicStringProto() {
return DynamicProto.DynamicString.newBuilder().setFloatFormatOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "FloatFormatOp{"
+ "input="
+ getInput()
+ ", maxFractionDigits="
+ getMaxFractionDigits()
+ ", minFractionDigits="
+ getMinFractionDigits()
+ ", minIntegerDigits="
+ getMinIntegerDigits()
+ ", groupingUsed="
+ getGroupingUsed()
+ "}";
}
/** Builder for {@link FloatFormatOp}. */
public static final class Builder implements DynamicString.Builder {
private final DynamicProto.FloatFormatOp.Builder mImpl =
DynamicProto.FloatFormatOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-5150153);
public Builder() {}
/**
* Sets the source of Float data to convert to a string.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicFloat input) {
mImpl.setInput(input.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets maximum fraction digits. Rounding will be applied if maxFractionDigits is
* smaller than number of fraction digits. If not defined, defaults to three.
* minimumFractionDigits must be <= maximumFractionDigits. If the condition is not
* satisfied, then minimumFractionDigits will be used for both fields.
*
* @since 1.2
*/
@NonNull
public Builder setMaxFractionDigits(@IntRange(from = 0) int maxFractionDigits) {
mImpl.setMaxFractionDigits(maxFractionDigits);
mFingerprint.recordPropertyUpdate(2, maxFractionDigits);
return this;
}
/**
* Sets minimum fraction digits. Zeros will be appended to the end to satisfy this
* constraint. If not defined, defaults to zero. minimumFractionDigits must be <=
* maximumFractionDigits. If the condition is not satisfied, then minimumFractionDigits
* will be used for both fields.
*
* @since 1.2
*/
@NonNull
public Builder setMinFractionDigits(@IntRange(from = 0) int minFractionDigits) {
mImpl.setMinFractionDigits(minFractionDigits);
mFingerprint.recordPropertyUpdate(3, minFractionDigits);
return this;
}
/**
* Sets minimum integer digits. Sign and grouping characters are not considered when
* applying minIntegerDigits constraint. If not defined, defaults to one. For example,
* for locale en_US, applying minIntegerDigit=4 to 12.34 would yield "0012.34".
*
* @since 1.2
*/
@NonNull
public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
mImpl.setMinIntegerDigits(minIntegerDigits);
mFingerprint.recordPropertyUpdate(4, minIntegerDigits);
return this;
}
/**
* Sets digit grouping used. Grouping size and grouping character depend on the current
* locale. If not defined, defaults to false. For example, for locale en_US, using
* grouping with 1234.56 would yield "1,234.56".
*
* @since 1.2
*/
@SuppressLint("MissingGetterMatchingBuilder")
@NonNull
public Builder setGroupingUsed(boolean groupingUsed) {
mImpl.setGroupingUsed(groupingUsed);
mFingerprint.recordPropertyUpdate(5, Boolean.hashCode(groupingUsed));
return this;
}
@Override
@NonNull
public FloatFormatOp build() {
return new FloatFormatOp(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic string type.
*
* <p>{@link DynamicString} string value is subject to being truncated if it's too long.
*
* @since 1.2
*/
public interface DynamicString extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicString toDynamicStringProto();
/**
* Creates a {@link DynamicString} from a byte array generated by {@link
* #toDynamicStringByteArray()}.
*/
@NonNull
static DynamicString fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicStringFromProto(
DynamicProto.DynamicString.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicString", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicStringByteArray() {
return toDynamicStringProto().toByteArray();
}
/**
* Creates a constant-valued {@link DynamicString}. The resulted {@link DynamicString} is
* subject to being truncated if it's too long.
*/
@NonNull
static DynamicString constant(@NonNull String constant) {
return new FixedString.Builder().setValue(constant).build();
}
/**
* Creates a {@link DynamicString} that is bound to the value of an item of the State. The
* resulted {@link DynamicString} is subject to being truncated if it's too long.
*
* @param stateKey The key to a {@link StateEntryValue} with a string value from the
* provider's state.
*/
@NonNull
static DynamicString fromState(@NonNull String stateKey) {
return new StateStringSource.Builder().setSourceKey(stateKey).build();
}
/**
* Creates a {@link DynamicString} that is bound to the result of a conditional expression.
* It will use the value given in either {@link ConditionScope#use} or {@link
* ConditionScopes.IfTrueScope#elseUse} depending on the value yielded from {@code
* condition}.
*
* @param condition The value used for evaluting this condition.
*/
@NonNull
static ConditionScope<DynamicString, String> onCondition(@NonNull DynamicBool condition) {
return new ConditionScopes.ConditionScope<>(
(trueValue, falseValue) ->
new ConditionalStringOp.Builder()
.setCondition(condition)
.setValueIfTrue(trueValue)
.setValueIfFalse(falseValue)
.build(),
DynamicString::constant);
}
/**
* Returns a new {@link DynamicString} that has the result of concatenating this {@link
* DynamicString} with {@code other}. i.e. {@code result = this + other} The resulted {@link
* DynamicString} is subject to being truncated if it's too long.
*
* @param other The right hand side operand of the concatenation.
*/
@NonNull
default DynamicString concat(@NonNull DynamicString other) {
return new DynamicBuilders.ConcatStringOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.build();
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicString} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicString build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicString dynamicStringFromProto(@NonNull DynamicProto.DynamicString proto) {
if (proto.hasFixed()) {
return FixedString.fromProto(proto.getFixed());
}
if (proto.hasInt32FormatOp()) {
return Int32FormatOp.fromProto(proto.getInt32FormatOp());
}
if (proto.hasStateSource()) {
return StateStringSource.fromProto(proto.getStateSource());
}
if (proto.hasConditionalOp()) {
return ConditionalStringOp.fromProto(proto.getConditionalOp());
}
if (proto.hasConcatOp()) {
return ConcatStringOp.fromProto(proto.getConcatOp());
}
if (proto.hasFloatFormatOp()) {
return FloatFormatOp.fromProto(proto.getFloatFormatOp());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicString");
}
/**
* An arithmetic operation, operating on two Float instances. This implements simple binary
* operations of the form "result = LHS <op> RHS", where the available operation types are
* described in {@code ArithmeticOpType}.
*
* @since 1.2
*/
static final class ArithmeticFloatOp implements DynamicFloat {
private final DynamicProto.ArithmeticFloatOp mImpl;
@Nullable private final Fingerprint mFingerprint;
ArithmeticFloatOp(DynamicProto.ArithmeticFloatOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets left hand side of the arithmetic operation.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInputLhs() {
if (mImpl.hasInputLhs()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInputLhs());
} else {
return null;
}
}
/**
* Gets right hand side of the arithmetic operation.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInputRhs() {
if (mImpl.hasInputRhs()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInputRhs());
} else {
return null;
}
}
/**
* Gets the type of operation to carry out.
*
* @since 1.2
*/
@ArithmeticOpType
public int getOperationType() {
return mImpl.getOperationType().getNumber();
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ArithmeticFloatOp fromProto(@NonNull DynamicProto.ArithmeticFloatOp proto) {
return new ArithmeticFloatOp(proto, null);
}
@NonNull
DynamicProto.ArithmeticFloatOp toProto() {
return mImpl;
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicFloat toDynamicFloatProto() {
return DynamicProto.DynamicFloat.newBuilder().setArithmeticOperation(mImpl).build();
}
/** Builder for {@link ArithmeticFloatOp}. */
public static final class Builder implements DynamicFloat.Builder {
private final DynamicProto.ArithmeticFloatOp.Builder mImpl =
DynamicProto.ArithmeticFloatOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1818249334);
public Builder() {}
/**
* Sets left hand side of the arithmetic operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputLhs(@NonNull DynamicFloat inputLhs) {
mImpl.setInputLhs(inputLhs.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(inputLhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets right hand side of the arithmetic operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputRhs(@NonNull DynamicFloat inputRhs) {
mImpl.setInputRhs(inputRhs.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(inputRhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the type of operation to carry out.
*
* @since 1.2
*/
@NonNull
public Builder setOperationType(@ArithmeticOpType int operationType) {
mImpl.setOperationType(DynamicProto.ArithmeticOpType.forNumber(operationType));
mFingerprint.recordPropertyUpdate(3, operationType);
return this;
}
@Override
@NonNull
public ArithmeticFloatOp build() {
return new ArithmeticFloatOp(mImpl.build(), mFingerprint);
}
}
}
/**
* A dynamic Float which sources its data from the tile's state.
*
* @since 1.2
*/
static final class StateFloatSource implements DynamicFloat {
private final DynamicProto.StateFloatSource mImpl;
@Nullable private final Fingerprint mFingerprint;
StateFloatSource(DynamicProto.StateFloatSource impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public String getSourceKey() {
return mImpl.getSourceKey();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static StateFloatSource fromProto(@NonNull DynamicProto.StateFloatSource proto) {
return new StateFloatSource(proto, null);
}
@NonNull
DynamicProto.StateFloatSource toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicFloat toDynamicFloatProto() {
return DynamicProto.DynamicFloat.newBuilder().setStateSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "StateFloatSource{" + "sourceKey=" + getSourceKey() + "}";
}
/** Builder for {@link StateFloatSource}. */
public static final class Builder implements DynamicFloat.Builder {
private final DynamicProto.StateFloatSource.Builder mImpl =
DynamicProto.StateFloatSource.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(384370154);
public Builder() {}
/**
* Sets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public Builder setSourceKey(@NonNull String sourceKey) {
mImpl.setSourceKey(sourceKey);
mFingerprint.recordPropertyUpdate(1, sourceKey.hashCode());
return this;
}
@Override
@NonNull
public StateFloatSource build() {
return new StateFloatSource(mImpl.build(), mFingerprint);
}
}
}
/**
* An operation to convert an Int32 value in the dynamic data pipeline to a Float value.
*
* @since 1.2
*/
static final class Int32ToFloatOp implements DynamicFloat {
private final DynamicProto.Int32ToFloatOp mImpl;
@Nullable private final Fingerprint mFingerprint;
Int32ToFloatOp(DynamicProto.Int32ToFloatOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the input Int32 to convert to a Float.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getInput());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static Int32ToFloatOp fromProto(@NonNull DynamicProto.Int32ToFloatOp proto) {
return new Int32ToFloatOp(proto, null);
}
@NonNull
DynamicProto.Int32ToFloatOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicFloat toDynamicFloatProto() {
return DynamicProto.DynamicFloat.newBuilder().setInt32ToFloatOperation(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "Int32ToFloatOp{" + "input=" + getInput() + "}";
}
/** Builder for {@link Int32ToFloatOp}. */
public static final class Builder implements DynamicFloat.Builder {
private final DynamicProto.Int32ToFloatOp.Builder mImpl =
DynamicProto.Int32ToFloatOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-619592745);
public Builder() {}
/**
* Sets the input Int32 to convert to a Float.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicInt32 input) {
mImpl.setInput(input.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public Int32ToFloatOp build() {
return new Int32ToFloatOp(mImpl.build(), mFingerprint);
}
}
}
/**
* A static interpolation node, between two fixed floating point values.
*
* @since 1.2
*/
static final class AnimatableFixedFloat implements DynamicFloat {
private final DynamicProto.AnimatableFixedFloat mImpl;
@Nullable private final Fingerprint mFingerprint;
AnimatableFixedFloat(
DynamicProto.AnimatableFixedFloat impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the number to start animating from.
*
* @since 1.2
*/
public float getFromValue() {
return mImpl.getFromValue();
}
/**
* Gets the number to animate to.
*
* @since 1.2
*/
public float getToValue() {
return mImpl.getToValue();
}
/**
* Gets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@Nullable
public AnimationSpec getAnimationSpec() {
if (mImpl.hasAnimationSpec()) {
return AnimationSpec.fromProto(mImpl.getAnimationSpec());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static AnimatableFixedFloat fromProto(@NonNull DynamicProto.AnimatableFixedFloat proto) {
return new AnimatableFixedFloat(proto, null);
}
@NonNull
DynamicProto.AnimatableFixedFloat toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicFloat toDynamicFloatProto() {
return DynamicProto.DynamicFloat.newBuilder().setAnimatableFixed(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "AnimatableFixedFloat{"
+ "fromValue="
+ getFromValue()
+ ", toValue="
+ getToValue()
+ ", animationSpec="
+ getAnimationSpec()
+ "}";
}
/** Builder for {@link AnimatableFixedFloat}. */
public static final class Builder implements DynamicFloat.Builder {
private final DynamicProto.AnimatableFixedFloat.Builder mImpl =
DynamicProto.AnimatableFixedFloat.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1964707538);
public Builder() {}
/**
* Sets the number to start animating from.
*
* @since 1.2
*/
@NonNull
public Builder setFromValue(float fromValue) {
mImpl.setFromValue(fromValue);
mFingerprint.recordPropertyUpdate(1, Float.floatToIntBits(fromValue));
return this;
}
/**
* Sets the number to animate to.
*
* @since 1.2
*/
@NonNull
public Builder setToValue(float toValue) {
mImpl.setToValue(toValue);
mFingerprint.recordPropertyUpdate(2, Float.floatToIntBits(toValue));
return this;
}
/**
* Sets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@NonNull
public Builder setAnimationSpec(@NonNull AnimationSpec animationSpec) {
mImpl.setAnimationSpec(animationSpec.toProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(animationSpec.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public AnimatableFixedFloat build() {
return new AnimatableFixedFloat(mImpl.build(), mFingerprint);
}
}
}
/**
* A dynamic interpolation node. This will watch the value of its input and, when the first
* update arrives, immediately emit that value. On subsequent updates, it will animate between
* the old and new values.
*
* <p>If this node receives an invalid value (e.g. as a result of an upstream node having no
* value), then it will emit a single invalid value, and forget its "stored" value. The next
* valid value that arrives is then used as the "first" value again.
*
* @since 1.2
*/
static final class AnimatableDynamicFloat implements DynamicFloat {
private final DynamicProto.AnimatableDynamicFloat mImpl;
@Nullable private final Fingerprint mFingerprint;
AnimatableDynamicFloat(
DynamicProto.AnimatableDynamicFloat impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the value to watch, and animate when it changes.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@Nullable
public AnimationSpec getAnimationSpec() {
if (mImpl.hasAnimationSpec()) {
return AnimationSpec.fromProto(mImpl.getAnimationSpec());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static AnimatableDynamicFloat fromProto(
@NonNull DynamicProto.AnimatableDynamicFloat proto) {
return new AnimatableDynamicFloat(proto, null);
}
@NonNull
DynamicProto.AnimatableDynamicFloat toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicFloat toDynamicFloatProto() {
return DynamicProto.DynamicFloat.newBuilder().setAnimatableDynamic(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "AnimatableDynamicFloat{"
+ "input="
+ getInput()
+ ", animationSpec="
+ getAnimationSpec()
+ "}";
}
/** Builder for {@link AnimatableDynamicFloat}. */
public static final class Builder implements DynamicFloat.Builder {
private final DynamicProto.AnimatableDynamicFloat.Builder mImpl =
DynamicProto.AnimatableDynamicFloat.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1543182280);
public Builder() {}
/**
* Sets the value to watch, and animate when it changes.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicFloat input) {
mImpl.setInput(input.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@NonNull
public Builder setAnimationSpec(@NonNull AnimationSpec animationSpec) {
mImpl.setAnimationSpec(animationSpec.toProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(animationSpec.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public AnimatableDynamicFloat build() {
return new AnimatableDynamicFloat(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic float type.
*
* <p>It offers a set of helper methods for creating arithmetic and logical expressions, e.g.
* {@link #plus(float)}, {@link #times(float)}, {@link #eq(float)}, etc. These helper methods
* produce expression trees based on the order in which they were called in an expression. Thus,
* no operator precedence rules are applied.
*
* <p>For example the following expression is equivalent to {@code result = ((a + b)*c)/d }:
*
* <pre>{@code
* a.plus(b).times(c).div(d);
* }</pre>
*
* More complex expressions can be created by nesting expressions. For example the following
* expression is equivalent to {@code result = (a + b)*(c - d) }:
*
* <pre>{@code
* (a.plus(b)).times(c.minus(d));
* }</pre>
*
* @since 1.2
*/
public interface DynamicFloat extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicFloat toDynamicFloatProto();
/**
* Creates a {@link DynamicFloat} from a byte array generated by {@link
* #toDynamicFloatByteArray()}.
*/
@NonNull
static DynamicFloat fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicFloatFromProto(
DynamicProto.DynamicFloat.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicFloat", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicFloatByteArray() {
return toDynamicFloatProto().toByteArray();
}
/**
* Creates a constant-valued {@link DynamicFloat}.
*
* <p>If {@code Float.isNan(constant)} is true, the value will be invalid. And any
* expression that uses this {@link DynamicFloat} will have an invalid result (which will be
* delivered through {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
*/
@NonNull
static DynamicFloat constant(float constant) {
return new FixedFloat.Builder().setValue(constant).build();
}
/**
* Creates a {@link DynamicFloat} that is bound to the value of an item of the State.
*
* @param stateKey The key to a {@link StateEntryValue} with a float value from the
* provider's state.
*/
@NonNull
static DynamicFloat fromState(@NonNull String stateKey) {
return new StateFloatSource.Builder().setSourceKey(stateKey).build();
}
/**
* Creates a {@link DynamicFloat} which will animate over the range of floats from {@code
* start} to {@code end}.
*
* @param start The start value of the range.
* @param end The end value of the range.
*/
@NonNull
static DynamicFloat animate(float start, float end) {
return new AnimatableFixedFloat.Builder().setFromValue(start).setToValue(end).build();
}
/**
* Creates a {@link DynamicFloat} which will animate over the range of floats from {@code
* start} to {@code end} with the given animation parameters.
*
* @param start The start value of the range.
* @param end The end value of the range.
* @param animationSpec The animation parameters.
*/
@NonNull
static DynamicFloat animate(float start, float end, @NonNull AnimationSpec animationSpec) {
return new AnimatableFixedFloat.Builder()
.setFromValue(start)
.setToValue(end)
.setAnimationSpec(animationSpec)
.build();
}
/**
* Creates a {@link DynamicFloat} that is bound to the value of an item of the State. Every
* time the state value changes, this {@link DynamicFloat} will animate from its current
* value to the new value (from the state).
*
* @param stateKey The key to a {@link StateEntryValue} with a float value from the
* providers state.
*/
@NonNull
static DynamicFloat animate(@NonNull String stateKey) {
return new AnimatableDynamicFloat.Builder().setInput(fromState(stateKey)).build();
}
/**
* Creates a {@link DynamicFloat} that is bound to the value of an item of the State. Every
* time the state value changes, this {@link DynamicFloat} will animate from its current
* value to the new value (from the state).
*
* @param stateKey The key to a {@link StateEntryValue} with a float value from the
* providers state.
* @param animationSpec The animation parameters.
*/
@NonNull
static DynamicFloat animate(
@NonNull String stateKey, @NonNull AnimationSpec animationSpec) {
return new AnimatableDynamicFloat.Builder()
.setInput(fromState(stateKey))
.setAnimationSpec(animationSpec)
.build();
}
/**
* Returns a {@link DynamicFloat} that is bound to the value of this {@link DynamicFloat}
* and every time its value is changing, it animates from its current value to the new
* value.
*
* @param animationSpec The animation parameters.
*/
@NonNull
default DynamicFloat animate(@NonNull AnimationSpec animationSpec) {
return new AnimatableDynamicFloat.Builder()
.setInput(this)
.setAnimationSpec(animationSpec)
.build();
}
/**
* Returns a {@link DynamicFloat} that is bound to the value of this {@link DynamicFloat}
* and every time its value is changing, it animates from its current value to the new
* value.
*/
@NonNull
default DynamicFloat animate() {
return new AnimatableDynamicFloat.Builder().setInput(this).build();
}
/**
* Returns a {@link DynamicInt32} which holds the largest integer value that is smaller than
* or equal to this {@link DynamicFloat}, i.e. {@code int result = (int) Math.floor(this)}
*
* <p>If the float value is larger than {@link Integer#MAX_VALUE} or smaller than {@link
* Integer#MIN_VALUE}, the result of this operation will be invalid and any expression that
* uses the {@link DynamicInt32} will have an invalid result (which will be delivered
* through {@link DynamicTypeValueReceiver<T>#onInvalidate()}.
*/
@NonNull
default DynamicInt32 asInt() {
return new FloatToInt32Op.Builder()
.setRoundMode(DynamicBuilders.ROUND_MODE_FLOOR)
.setInput(this)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of adding another {@link
* DynamicFloat} to this {@link DynamicFloat}; As an example, the following is equal to
* {@code DynamicFloat.constant(13f)}
*
* <pre>
* DynamicFloat.constant(7f).plus(DynamicFloat.constant(5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat plus(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of adding a float to this {@link
* DynamicFloat}; As an example, the following is equal to {@code
* DynamicFloat.constant(13f)}
*
* <pre>
* DynamicFloat.constant(7f).plus(5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat plus(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of adding a {@link DynamicInt32} to
* this {@link DynamicFloat}; As an example, the following is equal to {@code
* DynamicFloat.constant(13f)}
*
* <pre>
* DynamicFloat.constant(7f).plus(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat plus(@NonNull DynamicInt32 other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other.asFloat())
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_ADD)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of subtracting another {@link
* DynamicFloat} from this {@link DynamicFloat}; As an example, the following is equal to
* {@code DynamicFloat.constant(2f)}
*
* <pre>
* DynamicFloat.constant(7f).minus(DynamicFloat.constant(5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat minus(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of subtracting a flaot from this
* {@link DynamicFloat}; As an example, the following is equal to {@code
* DynamicFloat.constant(2f)}
*
* <pre>
* DynamicFloat.constant(7f).minus(5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat minus(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of subtracting a {@link
* DynamicInt32} from this {@link DynamicFloat}; As an example, the following is equal to
* {@code DynamicFloat.constant(2f)}
*
* <pre>
* DynamicFloat.constant(7f).minus(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat minus(@NonNull DynamicInt32 other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other.asFloat())
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_SUBTRACT)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of multiplying this {@link
* DynamicFloat} by another {@link DynamicFloat}; As an example, the following is equal to
* {@code DynamicFloat.constant(35f)}
*
* <pre>
* DynamicFloat.constant(7f).times(DynamicFloat.constant(5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat times(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of multiplying this {@link
* DynamicFloat} by a flaot; As an example, the following is equal to {@code
* DynamicFloat.constant(35f)}
*
* <pre>
* DynamicFloat.constant(7f).times(5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat times(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of multiplying this {@link
* DynamicFloat} by a {@link DynamicInt32}; As an example, the following is equal to {@code
* DynamicFloat.constant(35f)}
*
* <pre>
* DynamicFloat.constant(7f).times(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat times(@NonNull DynamicInt32 other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other.asFloat())
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MULTIPLY)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of dividing this {@link
* DynamicFloat} by another {@link DynamicFloat}; As an example, the following is equal to
* {@code DynamicFloat.constant(1.4f)}
*
* <pre>
* DynamicFloat.constant(7f).div(DynamicFloat.constant(5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat div(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of dividing this {@link
* DynamicFloat} by a float; As an example, the following is equal to {@code
* DynamicFloat.constant(1.4f)}
*
* <pre>
* DynamicFloat.constant(7f).div(5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat div(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the result of dividing this {@link
* DynamicFloat} by a {@link DynamicInt32}; As an example, the following is equal to {@code
* DynamicFloat.constant(1.4f)}
*
* <pre>
* DynamicFloat.constant(7f).div(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat div(@NonNull DynamicInt32 other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other.asFloat())
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_DIVIDE)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the reminder of dividing this {@link
* DynamicFloat} by another {@link DynamicFloat}; As an example, the following is equal to
* {@code DynamicFloat.constant(1.5f)}
*
* <pre>
* DynamicFloat.constant(7f).rem(DynamicFloat.constant(5.5f));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat rem(@NonNull DynamicFloat other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the reminder of dividing this {@link
* DynamicFloat} by a float; As an example, the following is equal to {@code
* DynamicFloat.constant(1.5f)}
*
* <pre>
* DynamicFloat.constant(7f).rem(5.5f);
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat rem(float other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Creates a {@link DynamicFloat} containing the reminder of dividing this {@link
* DynamicFloat} by a {@link DynamicInt32}; As an example, the following is equal to {@code
* DynamicFloat.constant(2f)}
*
* <pre>
* DynamicFloat.constant(7f).rem(DynamicInt32.constant(5));
* </pre>
*
* The operation's evaluation order depends only on its position in the expression; no
* operator precedence rules are applied. See {@link DynamicFloat} for more information on
* operation evaluation order.
*
* @return a new instance of {@link DynamicFloat} containing the result of the operation.
*/
@SuppressWarnings("KotlinOperator")
@NonNull
default DynamicFloat rem(@NonNull DynamicInt32 other) {
return new ArithmeticFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other.asFloat())
.setOperationType(DynamicBuilders.ARITHMETIC_OP_TYPE_MODULO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} and
* {@code other} are equal, otherwise it's false.
*/
@NonNull
default DynamicBool eq(@NonNull DynamicFloat other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} and
* {@code other} are equal, otherwise it's false.
*/
@NonNull
default DynamicBool eq(float other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} and
* {@code other} are not equal, otherwise it's false.
*/
@NonNull
default DynamicBool ne(@NonNull DynamicFloat other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_NOT_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} and
* {@code other} are not equal, otherwise it's false.
*/
@NonNull
default DynamicBool ne(float other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_NOT_EQUALS)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* less than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lt(@NonNull DynamicFloat other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* less than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lt(float other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* less than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lte(@NonNull DynamicFloat other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* less than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool lte(float other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_LESS_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* greater than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gt(@NonNull DynamicFloat other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* greater than {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gt(float other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* greater than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gte(@NonNull DynamicFloat other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(other)
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN_OR_EQUAL_TO)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if the value of this {@link DynamicFloat} is
* greater than or equal to {@code other}, otherwise it's false.
*/
@NonNull
default DynamicBool gte(float other) {
return new ComparisonFloatOp.Builder()
.setInputLhs(this)
.setInputRhs(constant(other))
.setOperationType(DynamicBuilders.COMPARISON_OP_TYPE_GREATER_THAN_OR_EQUAL_TO)
.build();
}
/**
* Bind the value of this {@link DynamicFloat} to the result of a conditional expression.
* This will use the value given in either {@link ConditionScope#use} or {@link
* ConditionScopes.IfTrueScope#elseUse} depending on the value yielded from {@code
* condition}.
*/
@NonNull
static ConditionScope<DynamicFloat, Float> onCondition(@NonNull DynamicBool condition) {
return new ConditionScopes.ConditionScope<>(
(trueValue, falseValue) ->
new ConditionalFloatOp.Builder()
.setCondition(condition)
.setValueIfTrue(trueValue)
.setValueIfFalse(falseValue)
.build(),
DynamicFloat::constant);
}
/**
* Returns a {@link DynamicString} that contains the formatted value of this {@link
* DynamicFloat} (with default formatting parameters). As an example, for locale en_US, the
* following is equal to {@code DynamicString.constant("12.346")}
*
* <pre>
* DynamicFloat.constant(12.34567f).format();
* </pre>
*
* The resulted {@link DynamicString} is subject to being truncated if it's too long.
*/
@NonNull
default DynamicString format() {
return new FloatFormatter.Builder().build().getFloatFormatOp(this);
}
/**
* Returns a {@link DynamicString} that contains the formatted value of this {@link
* DynamicFloat}. As an example, for locale en_US, the following is equal to {@code
* DynamicString.constant("0,012.34")}
*
* <pre>
* DynamicFloat.constant(12.345f)
* .format(
* new FloatFormatter.Builder().setMaxFractionDigits(2).setMinIntegerDigits(4)
* .setGroupingUsed(true).build());
* </pre>
*
* The resulted {@link DynamicString} is subject to being truncated if it's too long.
*
* @param formatter The formatting parameter.
*/
@NonNull
default DynamicString format(@NonNull FloatFormatter formatter) {
return formatter.getFloatFormatOp(this);
}
/** Allows formatting {@link DynamicFloat} into a {@link DynamicString}. */
class FloatFormatter {
private final FloatFormatOp.Builder mFloatFormatOpBuilder;
private final FloatFormatOp mFloatFormatOp;
FloatFormatter(FloatFormatOp.Builder floatFormatOpBuilder) {
mFloatFormatOpBuilder = floatFormatOpBuilder;
mFloatFormatOp = floatFormatOpBuilder.build();
}
@NonNull
FloatFormatOp getFloatFormatOp(@NonNull DynamicFloat dynamicFloat) {
return mFloatFormatOpBuilder.setInput(dynamicFloat).build();
}
/** Returns the minimum number of digits allowed in the fraction portion of a number. */
@IntRange(from = 0)
public int getMinFractionDigits() {
return mFloatFormatOp.getMinFractionDigits();
}
/** Returns the maximum number of digits allowed in the fraction portion of a number. */
@IntRange(from = 0)
public int getMaxFractionDigits() {
return mFloatFormatOp.getMaxFractionDigits();
}
/** Returns the minimum number of digits allowed in the integer portion of a number. */
@IntRange(from = 0)
public int getMinIntegerDigits() {
return mFloatFormatOp.getMinIntegerDigits();
}
/** Returns whether digit grouping is used or not. */
public boolean isGroupingUsed() {
return mFloatFormatOp.getGroupingUsed();
}
/** Builder to create {@link FloatFormatter} objects. */
public static final class Builder {
private static final int MAX_INTEGER_PART_LENGTH = 15;
private static final int MAX_FRACTION_PART_LENGTH = 15;
final FloatFormatOp.Builder mBuilder;
public Builder() {
mBuilder = new FloatFormatOp.Builder();
}
/**
* Sets minimum number of fraction digits for the formatter. Defaults to zero if not
* specified. minimumFractionDigits must be <= maximumFractionDigits. If the
* condition is not satisfied, then minimumFractionDigits will be used for both
* fields.
*/
@NonNull
public Builder setMinFractionDigits(@IntRange(from = 0) int minFractionDigits) {
mBuilder.setMinFractionDigits(minFractionDigits);
return this;
}
/**
* Sets maximum number of fraction digits for the formatter. Defaults to three if
* not specified. minimumFractionDigits must be <= maximumFractionDigits. If the
* condition is not satisfied, then minimumFractionDigits will be used for both
* fields.
*/
@NonNull
public Builder setMaxFractionDigits(@IntRange(from = 0) int maxFractionDigits) {
mBuilder.setMaxFractionDigits(maxFractionDigits);
return this;
}
/**
* Sets minimum number of integer digits for the formatter. Defaults to one if not
* specified. If minIntegerDigits is zero and the -1 < input < 1, the Integer
* part will not appear.
*/
@NonNull
public Builder setMinIntegerDigits(@IntRange(from = 0) int minIntegerDigits) {
mBuilder.setMinIntegerDigits(minIntegerDigits);
return this;
}
/**
* Sets whether grouping is used for the formatter. Defaults to false if not
* specified. If grouping is used, digits will be grouped into digit groups using a
* separator. Digit group size and used separator can vary in different
* countries/regions. As an example, for locale en_US, the following is equal to
* {@code * DynamicString.constant("1,234")}
*
* <pre>
* DynamicFloat.constant(1234)
* .format(
* new FloatFormatter.Builder()
* .setGroupingUsed(true).build());
* </pre>
*/
@NonNull
public Builder setGroupingUsed(boolean groupingUsed) {
mBuilder.setGroupingUsed(groupingUsed);
return this;
}
/** Builds an instance with values accumulated in this Builder. */
@NonNull
public FloatFormatter build() {
FloatFormatOp op = mBuilder.build();
throwIfExceedingMaxValue(
"MinFractionDigits",
op.getMinFractionDigits(),
MAX_FRACTION_PART_LENGTH);
throwIfExceedingMaxValue(
"MaxFractionDigits",
op.getMaxFractionDigits(),
MAX_FRACTION_PART_LENGTH);
throwIfExceedingMaxValue(
"MinIntegerDigits", op.getMinIntegerDigits(), MAX_INTEGER_PART_LENGTH);
return new FloatFormatter(mBuilder);
}
private static void throwIfExceedingMaxValue(
String paramName, int value, int maxValue) {
if (value > maxValue) {
throw new IllegalArgumentException(
String.format(
"%s (%d) is too large. Maximum value for %s is %d",
paramName, value, paramName, maxValue));
}
}
}
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicFloat} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicFloat build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicFloat dynamicFloatFromProto(@NonNull DynamicProto.DynamicFloat proto) {
if (proto.hasFixed()) {
return FixedFloat.fromProto(proto.getFixed());
}
if (proto.hasArithmeticOperation()) {
return ArithmeticFloatOp.fromProto(proto.getArithmeticOperation());
}
if (proto.hasInt32ToFloatOperation()) {
return Int32ToFloatOp.fromProto(proto.getInt32ToFloatOperation());
}
if (proto.hasStateSource()) {
return StateFloatSource.fromProto(proto.getStateSource());
}
if (proto.hasConditionalOp()) {
return ConditionalFloatOp.fromProto(proto.getConditionalOp());
}
if (proto.hasAnimatableFixed()) {
return AnimatableFixedFloat.fromProto(proto.getAnimatableFixed());
}
if (proto.hasAnimatableDynamic()) {
return AnimatableDynamicFloat.fromProto(proto.getAnimatableDynamic());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicFloat");
}
/**
* A dynamic boolean type which sources its data from the tile's state.
*
* @since 1.2
*/
static final class StateBoolSource implements DynamicBool {
private final DynamicProto.StateBoolSource mImpl;
@Nullable private final Fingerprint mFingerprint;
StateBoolSource(DynamicProto.StateBoolSource impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public String getSourceKey() {
return mImpl.getSourceKey();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static StateBoolSource fromProto(@NonNull DynamicProto.StateBoolSource proto) {
return new StateBoolSource(proto, null);
}
@NonNull
DynamicProto.StateBoolSource toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicBool toDynamicBoolProto() {
return DynamicProto.DynamicBool.newBuilder().setStateSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "StateBoolSource{" + "sourceKey=" + getSourceKey() + "}";
}
/** Builder for {@link StateBoolSource}. */
public static final class Builder implements DynamicBool.Builder {
private final DynamicProto.StateBoolSource.Builder mImpl =
DynamicProto.StateBoolSource.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1818702779);
public Builder() {}
/**
* Sets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public Builder setSourceKey(@NonNull String sourceKey) {
mImpl.setSourceKey(sourceKey);
mFingerprint.recordPropertyUpdate(1, sourceKey.hashCode());
return this;
}
@Override
@NonNull
public StateBoolSource build() {
return new StateBoolSource(mImpl.build(), mFingerprint);
}
}
}
/**
* A comparison operation, operating on two Int32 instances. This implements various comparison
* operations of the form "boolean result = LHS <op> RHS", where the available operation types
* are described in {@code ComparisonOpType}.
*
* @since 1.2
*/
static final class ComparisonInt32Op implements DynamicBool {
private final DynamicProto.ComparisonInt32Op mImpl;
@Nullable private final Fingerprint mFingerprint;
ComparisonInt32Op(DynamicProto.ComparisonInt32Op impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the left hand side of the comparison operation.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInputLhs() {
if (mImpl.hasInputLhs()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getInputLhs());
} else {
return null;
}
}
/**
* Gets the right hand side of the comparison operation.
*
* @since 1.2
*/
@Nullable
public DynamicInt32 getInputRhs() {
if (mImpl.hasInputRhs()) {
return DynamicBuilders.dynamicInt32FromProto(mImpl.getInputRhs());
} else {
return null;
}
}
/**
* Gets the type of the operation.
*
* @since 1.2
*/
@ComparisonOpType
public int getOperationType() {
return mImpl.getOperationType().getNumber();
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ComparisonInt32Op fromProto(@NonNull DynamicProto.ComparisonInt32Op proto) {
return new ComparisonInt32Op(proto, null);
}
@NonNull
DynamicProto.ComparisonInt32Op toProto() {
return mImpl;
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicBool toDynamicBoolProto() {
return DynamicProto.DynamicBool.newBuilder().setInt32Comparison(mImpl).build();
}
/** Builder for {@link ComparisonInt32Op}. */
public static final class Builder implements DynamicBool.Builder {
private final DynamicProto.ComparisonInt32Op.Builder mImpl =
DynamicProto.ComparisonInt32Op.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1112207999);
public Builder() {}
/**
* Sets the left hand side of the comparison operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputLhs(@NonNull DynamicInt32 inputLhs) {
mImpl.setInputLhs(inputLhs.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(inputLhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the right hand side of the comparison operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputRhs(@NonNull DynamicInt32 inputRhs) {
mImpl.setInputRhs(inputRhs.toDynamicInt32Proto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(inputRhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the type of the operation.
*
* @since 1.2
*/
@NonNull
public Builder setOperationType(@ComparisonOpType int operationType) {
mImpl.setOperationType(DynamicProto.ComparisonOpType.forNumber(operationType));
mFingerprint.recordPropertyUpdate(3, operationType);
return this;
}
@Override
@NonNull
public ComparisonInt32Op build() {
return new ComparisonInt32Op(mImpl.build(), mFingerprint);
}
}
}
/**
* A comparison operation, operating on two Float instances. This implements various comparison
* operations of the form "boolean result = LHS <op> RHS", where the available operation types
* are described in {@code ComparisonOpType}.
*
* @since 1.2
*/
static final class ComparisonFloatOp implements DynamicBool {
private final DynamicProto.ComparisonFloatOp mImpl;
@Nullable private final Fingerprint mFingerprint;
ComparisonFloatOp(DynamicProto.ComparisonFloatOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the left hand side of the comparison operation.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInputLhs() {
if (mImpl.hasInputLhs()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInputLhs());
} else {
return null;
}
}
/**
* Gets the right hand side of the comparison operation.
*
* @since 1.2
*/
@Nullable
public DynamicFloat getInputRhs() {
if (mImpl.hasInputRhs()) {
return DynamicBuilders.dynamicFloatFromProto(mImpl.getInputRhs());
} else {
return null;
}
}
/**
* Gets the type of the operation.
*
* @since 1.2
*/
@ComparisonOpType
public int getOperationType() {
return mImpl.getOperationType().getNumber();
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static ComparisonFloatOp fromProto(@NonNull DynamicProto.ComparisonFloatOp proto) {
return new ComparisonFloatOp(proto, null);
}
@NonNull
DynamicProto.ComparisonFloatOp toProto() {
return mImpl;
}
/** */
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicBool toDynamicBoolProto() {
return DynamicProto.DynamicBool.newBuilder().setFloatComparison(mImpl).build();
}
/** Builder for {@link ComparisonFloatOp}. */
public static final class Builder implements DynamicBool.Builder {
private final DynamicProto.ComparisonFloatOp.Builder mImpl =
DynamicProto.ComparisonFloatOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1679565270);
public Builder() {}
/**
* Sets the left hand side of the comparison operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputLhs(@NonNull DynamicFloat inputLhs) {
mImpl.setInputLhs(inputLhs.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(inputLhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the right hand side of the comparison operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputRhs(@NonNull DynamicFloat inputRhs) {
mImpl.setInputRhs(inputRhs.toDynamicFloatProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(inputRhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the type of the operation.
*
* @since 1.2
*/
@NonNull
public Builder setOperationType(@ComparisonOpType int operationType) {
mImpl.setOperationType(DynamicProto.ComparisonOpType.forNumber(operationType));
mFingerprint.recordPropertyUpdate(3, operationType);
return this;
}
@Override
@NonNull
public ComparisonFloatOp build() {
return new ComparisonFloatOp(mImpl.build(), mFingerprint);
}
}
}
/**
* A boolean operation which implements a "NOT" operator, i.e. "boolean result = !input".
*
* @since 1.2
*/
static final class NotBoolOp implements DynamicBool {
private final DynamicProto.NotBoolOp mImpl;
@Nullable private final Fingerprint mFingerprint;
NotBoolOp(DynamicProto.NotBoolOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the input, whose value to negate.
*
* @since 1.2
*/
@Nullable
public DynamicBool getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getInput());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static NotBoolOp fromProto(@NonNull DynamicProto.NotBoolOp proto) {
return new NotBoolOp(proto, null);
}
@NonNull
DynamicProto.NotBoolOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicBool toDynamicBoolProto() {
return DynamicProto.DynamicBool.newBuilder().setNotOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "NotBoolOp{" + "input=" + getInput() + "}";
}
/** Builder for {@link NotBoolOp}. */
public static final class Builder implements DynamicBool.Builder {
private final DynamicProto.NotBoolOp.Builder mImpl =
DynamicProto.NotBoolOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(91300638);
public Builder() {}
/**
* Sets the input, whose value to negate.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicBool input) {
mImpl.setInput(input.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public NotBoolOp build() {
return new NotBoolOp(mImpl.build(), mFingerprint);
}
}
}
/**
* A logical boolean operator, implementing "boolean result = LHS <op> RHS", for various boolean
* operators (i.e. AND/OR).
*
* @since 1.2
*/
static final class LogicalBoolOp implements DynamicBool {
private final DynamicProto.LogicalBoolOp mImpl;
@Nullable private final Fingerprint mFingerprint;
LogicalBoolOp(DynamicProto.LogicalBoolOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the left hand side of the logical operation.
*
* @since 1.2
*/
@Nullable
public DynamicBool getInputLhs() {
if (mImpl.hasInputLhs()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getInputLhs());
} else {
return null;
}
}
/**
* Gets the right hand side of the logical operation.
*
* @since 1.2
*/
@Nullable
public DynamicBool getInputRhs() {
if (mImpl.hasInputRhs()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getInputRhs());
} else {
return null;
}
}
/**
* Gets the operation type to apply to LHS/RHS.
*
* @since 1.2
*/
@LogicalOpType
public int getOperationType() {
return mImpl.getOperationType().getNumber();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static LogicalBoolOp fromProto(@NonNull DynamicProto.LogicalBoolOp proto) {
return new LogicalBoolOp(proto, null);
}
@NonNull
DynamicProto.LogicalBoolOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicBool toDynamicBoolProto() {
return DynamicProto.DynamicBool.newBuilder().setLogicalOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "LogicalBoolOp{"
+ "inputLhs="
+ getInputLhs()
+ ", inputRhs="
+ getInputRhs()
+ ", operationType="
+ getOperationType()
+ "}";
}
/** Builder for {@link LogicalBoolOp}. */
public static final class Builder implements DynamicBool.Builder {
private final DynamicProto.LogicalBoolOp.Builder mImpl =
DynamicProto.LogicalBoolOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1067523409);
public Builder() {}
/**
* Sets the left hand side of the logical operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputLhs(@NonNull DynamicBool inputLhs) {
mImpl.setInputLhs(inputLhs.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(inputLhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the right hand side of the logical operation.
*
* @since 1.2
*/
@NonNull
public Builder setInputRhs(@NonNull DynamicBool inputRhs) {
mImpl.setInputRhs(inputRhs.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(inputRhs.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the operation type to apply to LHS/RHS.
*
* @since 1.2
*/
@NonNull
public Builder setOperationType(@LogicalOpType int operationType) {
mImpl.setOperationType(DynamicProto.LogicalOpType.forNumber(operationType));
mFingerprint.recordPropertyUpdate(3, operationType);
return this;
}
@Override
@NonNull
public LogicalBoolOp build() {
return new LogicalBoolOp(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic boolean type.
*
* @since 1.2
*/
public interface DynamicBool extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicBool toDynamicBoolProto();
/**
* Creates a {@link DynamicBool} from a byte array generated by {@link
* #toDynamicBoolByteArray()}.
*/
@NonNull
static DynamicBool fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicBoolFromProto(
DynamicProto.DynamicBool.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicBool", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicBoolByteArray() {
return toDynamicBoolProto().toByteArray();
}
/** Creates a constant-valued {@link DynamicBool}. */
@NonNull
static DynamicBool constant(boolean constant) {
return new FixedBool.Builder().setValue(constant).build();
}
/**
* Creates a {@link DynamicBool} that is bound to the value of an item of the State.
*
* @param stateKey The key to a {@link StateEntryValue} with a boolean value from the
* provider's state.
*/
@NonNull
static DynamicBool fromState(@NonNull String stateKey) {
return new StateBoolSource.Builder().setSourceKey(stateKey).build();
}
/**
* Returns a {@link DynamicBool} that has the opposite value of this {@link DynamicBool}.
* i.e. {code result = !this}
*/
@NonNull
default DynamicBool negate() {
return new NotBoolOp.Builder().setInput(this).build();
}
/**
* Returns a {@link DynamicBool} that is true if this {@link DynamicBool} and {@code input}
* are both true, otherwise it is false. i.e. {@code boolean result = this && input}
*
* @param input The right hand operand of the "and" operation.
*/
@NonNull
default DynamicBool and(@NonNull DynamicBool input) {
return new LogicalBoolOp.Builder()
.setInputLhs(this)
.setInputRhs(input)
.setOperationType(DynamicBuilders.LOGICAL_OP_TYPE_AND)
.build();
}
/**
* Returns a {@link DynamicBool} that is true if this {@link DynamicBool} or {@code input}
* are true, otherwise it is false. i.e. {@code boolean result = this || input}
*
* @param input The right hand operand of the "or" operation.
*/
@NonNull
default DynamicBool or(@NonNull DynamicBool input) {
return new LogicalBoolOp.Builder()
.setInputLhs(this)
.setInputRhs(input)
.setOperationType(DynamicBuilders.LOGICAL_OP_TYPE_OR)
.build();
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicBool} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicBool build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicBool dynamicBoolFromProto(@NonNull DynamicProto.DynamicBool proto) {
if (proto.hasFixed()) {
return FixedBool.fromProto(proto.getFixed());
}
if (proto.hasStateSource()) {
return StateBoolSource.fromProto(proto.getStateSource());
}
if (proto.hasInt32Comparison()) {
return ComparisonInt32Op.fromProto(proto.getInt32Comparison());
}
if (proto.hasNotOp()) {
return NotBoolOp.fromProto(proto.getNotOp());
}
if (proto.hasLogicalOp()) {
return LogicalBoolOp.fromProto(proto.getLogicalOp());
}
if (proto.hasFloatComparison()) {
return ComparisonFloatOp.fromProto(proto.getFloatComparison());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicBool");
}
/**
* A dynamic Color which sources its data from the tile's state.
*
* @since 1.2
*/
static final class StateColorSource implements DynamicColor {
private final DynamicProto.StateColorSource mImpl;
@Nullable private final Fingerprint mFingerprint;
StateColorSource(DynamicProto.StateColorSource impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public String getSourceKey() {
return mImpl.getSourceKey();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static StateColorSource fromProto(@NonNull DynamicProto.StateColorSource proto) {
return new StateColorSource(proto, null);
}
@NonNull
DynamicProto.StateColorSource toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicColor toDynamicColorProto() {
return DynamicProto.DynamicColor.newBuilder().setStateSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "StateColorSource{" + "sourceKey=" + getSourceKey() + "}";
}
/** Builder for {@link StateColorSource}. */
public static final class Builder implements DynamicColor.Builder {
private final DynamicProto.StateColorSource.Builder mImpl =
DynamicProto.StateColorSource.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(1981221690);
public Builder() {}
/**
* Sets the key in the state to bind to.
*
* @since 1.2
*/
@NonNull
public Builder setSourceKey(@NonNull String sourceKey) {
mImpl.setSourceKey(sourceKey);
mFingerprint.recordPropertyUpdate(1, sourceKey.hashCode());
return this;
}
@Override
@NonNull
public StateColorSource build() {
return new StateColorSource(mImpl.build(), mFingerprint);
}
}
}
/**
* A static interpolation node, between two fixed color values.
*
* @since 1.2
*/
static final class AnimatableFixedColor implements DynamicColor {
private final DynamicProto.AnimatableFixedColor mImpl;
@Nullable private final Fingerprint mFingerprint;
AnimatableFixedColor(
DynamicProto.AnimatableFixedColor impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the color value (in ARGB format) to start animating from.
*
* @since 1.2
*/
@ColorInt
public int getFromArgb() {
return mImpl.getFromArgb();
}
/**
* Gets the color value (in ARGB format) to animate to.
*
* @since 1.2
*/
@ColorInt
public int getToArgb() {
return mImpl.getToArgb();
}
/**
* Gets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@Nullable
public AnimationSpec getAnimationSpec() {
if (mImpl.hasAnimationSpec()) {
return AnimationSpec.fromProto(mImpl.getAnimationSpec());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static AnimatableFixedColor fromProto(@NonNull DynamicProto.AnimatableFixedColor proto) {
return new AnimatableFixedColor(proto, null);
}
@NonNull
DynamicProto.AnimatableFixedColor toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicColor toDynamicColorProto() {
return DynamicProto.DynamicColor.newBuilder().setAnimatableFixed(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "AnimatableFixedColor{"
+ "fromArgb="
+ getFromArgb()
+ ", toArgb="
+ getToArgb()
+ ", animationSpec="
+ getAnimationSpec()
+ "}";
}
/** Builder for {@link AnimatableFixedColor}. */
public static final class Builder implements DynamicColor.Builder {
private final DynamicProto.AnimatableFixedColor.Builder mImpl =
DynamicProto.AnimatableFixedColor.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(2051778294);
public Builder() {}
/**
* Sets the color value (in ARGB format) to start animating from.
*
* @since 1.2
*/
@NonNull
public Builder setFromArgb(@ColorInt int fromArgb) {
mImpl.setFromArgb(fromArgb);
mFingerprint.recordPropertyUpdate(1, fromArgb);
return this;
}
/**
* Sets the color value (in ARGB format) to animate to.
*
* @since 1.2
*/
@NonNull
public Builder setToArgb(@ColorInt int toArgb) {
mImpl.setToArgb(toArgb);
mFingerprint.recordPropertyUpdate(2, toArgb);
return this;
}
/**
* Sets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@NonNull
public Builder setAnimationSpec(@NonNull AnimationSpec animationSpec) {
mImpl.setAnimationSpec(animationSpec.toProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(animationSpec.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public AnimatableFixedColor build() {
return new AnimatableFixedColor(mImpl.build(), mFingerprint);
}
}
}
/**
* A dynamic interpolation node. This will watch the value of its input and, when the first
* update arrives, immediately emit that value. On subsequent updates, it will animate between
* the old and new values.
*
* <p>If this node receives an invalid value (e.g. as a result of an upstream node having no
* value), then it will emit a single invalid value, and forget its "stored" value. The next
* valid value that arrives is then used as the "first" value again.
*
* @since 1.2
*/
static final class AnimatableDynamicColor implements DynamicColor {
private final DynamicProto.AnimatableDynamicColor mImpl;
@Nullable private final Fingerprint mFingerprint;
AnimatableDynamicColor(
DynamicProto.AnimatableDynamicColor impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the value to watch, and animate when it changes.
*
* @since 1.2
*/
@Nullable
public DynamicColor getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicColorFromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@Nullable
public AnimationSpec getAnimationSpec() {
if (mImpl.hasAnimationSpec()) {
return AnimationSpec.fromProto(mImpl.getAnimationSpec());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static AnimatableDynamicColor fromProto(
@NonNull DynamicProto.AnimatableDynamicColor proto) {
return new AnimatableDynamicColor(proto, null);
}
@NonNull
DynamicProto.AnimatableDynamicColor toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicColor toDynamicColorProto() {
return DynamicProto.DynamicColor.newBuilder().setAnimatableDynamic(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "AnimatableDynamicColor{"
+ "input="
+ getInput()
+ ", animationSpec="
+ getAnimationSpec()
+ "}";
}
/** Builder for {@link AnimatableDynamicColor}. */
public static final class Builder implements DynamicColor.Builder {
private final DynamicProto.AnimatableDynamicColor.Builder mImpl =
DynamicProto.AnimatableDynamicColor.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-193597422);
public Builder() {}
/**
* Sets the value to watch, and animate when it changes.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicColor input) {
mImpl.setInput(input.toDynamicColorProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the animation parameters for duration, delay, etc.
*
* @since 1.2
*/
@NonNull
public Builder setAnimationSpec(@NonNull AnimationSpec animationSpec) {
mImpl.setAnimationSpec(animationSpec.toProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(animationSpec.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public AnimatableDynamicColor build() {
return new AnimatableDynamicColor(mImpl.build(), mFingerprint);
}
}
}
/**
* A conditional operator which yields a color depending on the boolean operand. This
* implements:
*
* <pre>{@code
* color result = condition ? value_if_true : value_if_false
* }</pre>
*
* @since 1.2
*/
static final class ConditionalColorOp implements DynamicColor {
private final DynamicProto.ConditionalColorOp mImpl;
@Nullable private final Fingerprint mFingerprint;
ConditionalColorOp(
DynamicProto.ConditionalColorOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the condition to use.
*
* @since 1.2
*/
@Nullable
public DynamicBool getCondition() {
if (mImpl.hasCondition()) {
return DynamicBuilders.dynamicBoolFromProto(mImpl.getCondition());
} else {
return null;
}
}
/**
* Gets the color to yield if condition is true.
*
* @since 1.2
*/
@Nullable
public DynamicColor getValueIfTrue() {
if (mImpl.hasValueIfTrue()) {
return DynamicBuilders.dynamicColorFromProto(mImpl.getValueIfTrue());
} else {
return null;
}
}
/**
* Gets the color to yield if condition is false.
*
* @since 1.2
*/
@Nullable
public DynamicColor getValueIfFalse() {
if (mImpl.hasValueIfFalse()) {
return DynamicBuilders.dynamicColorFromProto(mImpl.getValueIfFalse());
} 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 ConditionalColorOp fromProto(
@NonNull DynamicProto.ConditionalColorOp proto, @Nullable Fingerprint fingerprint) {
return new ConditionalColorOp(proto, fingerprint);
}
@NonNull
static ConditionalColorOp fromProto(@NonNull DynamicProto.ConditionalColorOp proto) {
return fromProto(proto, null);
}
/** Returns the internal proto instance. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.ConditionalColorOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicColor toDynamicColorProto() {
return DynamicProto.DynamicColor.newBuilder().setConditionalOp(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "ConditionalColorOp{"
+ "condition="
+ getCondition()
+ ", valueIfTrue="
+ getValueIfTrue()
+ ", valueIfFalse="
+ getValueIfFalse()
+ "}";
}
/** Builder for {@link ConditionalColorOp}. */
public static final class Builder implements DynamicColor.Builder {
private final DynamicProto.ConditionalColorOp.Builder mImpl =
DynamicProto.ConditionalColorOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1961850082);
public Builder() {}
/**
* Sets the condition to use.
*
* @since 1.2
*/
@NonNull
public Builder setCondition(@NonNull DynamicBool condition) {
mImpl.setCondition(condition.toDynamicBoolProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(condition.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the color to yield if condition is true.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfTrue(@NonNull DynamicColor valueIfTrue) {
mImpl.setValueIfTrue(valueIfTrue.toDynamicColorProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(valueIfTrue.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the color to yield if condition is false.
*
* @since 1.2
*/
@NonNull
public Builder setValueIfFalse(@NonNull DynamicColor valueIfFalse) {
mImpl.setValueIfFalse(valueIfFalse.toDynamicColorProto());
mFingerprint.recordPropertyUpdate(
3, checkNotNull(valueIfFalse.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public ConditionalColorOp build() {
return new ConditionalColorOp(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic color type.
*
* @since 1.2
*/
public interface DynamicColor extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicColor toDynamicColorProto();
/**
* Creates a {@link DynamicColor} from a byte array generated by {@link
* #toDynamicColorByteArray()}.
*/
@NonNull
static DynamicColor fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicColorFromProto(
DynamicProto.DynamicColor.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicColor", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicColorByteArray() {
return toDynamicColorProto().toByteArray();
}
/** Creates a constant-valued {@link DynamicColor}. */
@NonNull
static DynamicColor constant(@ColorInt int constant) {
return new FixedColor.Builder().setArgb(constant).build();
}
/**
* Creates a {@link DynamicColor} that is bound to the value of an item of the State.
*
* @param stateKey The key to a {@link StateEntryValue} with a color value from the
* provider's state.
*/
@NonNull
static DynamicColor fromState(@NonNull String stateKey) {
return new StateColorSource.Builder().setSourceKey(stateKey).build();
}
/**
* Creates a {@link DynamicColor} which will animate over the range of colors from {@code
* start} to {@code end}.
*
* @param start The start value of the range.
* @param end The end value of the range.
*/
@NonNull
static DynamicColor animate(@ColorInt int start, @ColorInt int end) {
return new AnimatableFixedColor.Builder().setFromArgb(start).setToArgb(end).build();
}
/**
* Creates a {@link DynamicColor} which will animate over the range of colors from {@code
* start} to {@code end} with the given animation parameters.
*
* @param start The start value of the range.
* @param end The end value of the range.
* @param animationSpec The animation parameters.
*/
@NonNull
static DynamicColor animate(
@ColorInt int start, @ColorInt int end, @NonNull AnimationSpec animationSpec) {
return new AnimatableFixedColor.Builder()
.setFromArgb(start)
.setToArgb(end)
.setAnimationSpec(animationSpec)
.build();
}
/**
* Creates a {@link DynamicColor} that is bound to the value of an item of the State. Every
* time the state value changes, this {@link DynamicColor} will animate from its current
* value to the new value (from the state).
*
* @param stateKey The key to a {@link StateEntryValue} with a color value from the
* provider's state.
*/
@NonNull
static DynamicColor animate(@NonNull String stateKey) {
return new AnimatableDynamicColor.Builder().setInput(fromState(stateKey)).build();
}
/**
* Creates a {@link DynamicColor} that is bound to the value of an item of the State. Every
* time the state value changes, this {@link DynamicColor} will animate from its current
* value to the new value (from the state).
*
* @param stateKey The key to a {@link StateEntryValue} with a color value from the
* provider's state.
* @param animationSpec The animation parameters.
*/
@NonNull
static DynamicColor animate(
@NonNull String stateKey, @NonNull AnimationSpec animationSpec) {
return new AnimatableDynamicColor.Builder()
.setInput(fromState(stateKey))
.setAnimationSpec(animationSpec)
.build();
}
/**
* Returns a {@link DynamicColor} that is bound to the value of this {@link DynamicColor}
* and every time its value is changing, it animates from its current value to the new
* value.
*
* @param animationSpec The animation parameters.
*/
@NonNull
default DynamicColor animate(@NonNull AnimationSpec animationSpec) {
return new AnimatableDynamicColor.Builder()
.setInput(this)
.setAnimationSpec(animationSpec)
.build();
}
/**
* Returns a {@link DynamicColor} that is bound to the value of this {@link DynamicColor}
* and every time its value is changing, it animates from its current value to the new
* value.
*/
@NonNull
default DynamicColor animate() {
return new AnimatableDynamicColor.Builder().setInput(this).build();
}
/**
* Bind the value of this {@link DynamicColor} to the result of a conditional expression.
* This will use the value given in either {@link ConditionScope#use} or {@link
* ConditionScopes.IfTrueScope#elseUse} depending on the value yielded from {@code
* condition}.
*/
@NonNull
static ConditionScope<DynamicColor, Integer> onCondition(@NonNull DynamicBool condition) {
return new ConditionScopes.ConditionScope<>(
(trueValue, falseValue) ->
new ConditionalColorOp.Builder()
.setCondition(condition)
.setValueIfTrue(trueValue)
.setValueIfFalse(falseValue)
.build(),
DynamicColor::constant);
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicColor} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicColor build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicColor dynamicColorFromProto(@NonNull DynamicProto.DynamicColor proto) {
if (proto.hasFixed()) {
return FixedColor.fromProto(proto.getFixed());
}
if (proto.hasStateSource()) {
return StateColorSource.fromProto(proto.getStateSource());
}
if (proto.hasAnimatableFixed()) {
return AnimatableFixedColor.fromProto(proto.getAnimatableFixed());
}
if (proto.hasAnimatableDynamic()) {
return AnimatableDynamicColor.fromProto(proto.getAnimatableDynamic());
}
if (proto.hasConditionalOp()) {
return ConditionalColorOp.fromProto(proto.getConditionalOp());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicColor");
}
/**
* A dynamic time instant that sources its value from the platform.
*
* @since 1.2
*/
static final class PlatformTimeSource implements DynamicInstant {
private final DynamicProto.PlatformTimeSource mImpl;
@Nullable private final Fingerprint mFingerprint;
PlatformTimeSource(
DynamicProto.PlatformTimeSource impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static PlatformTimeSource fromProto(@NonNull DynamicProto.PlatformTimeSource proto) {
return new PlatformTimeSource(proto, null);
}
@NonNull
DynamicProto.PlatformTimeSource toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInstant toDynamicInstantProto() {
return DynamicProto.DynamicInstant.newBuilder().setPlatformSource(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "PlatformTimeSource";
}
/** Builder for {@link PlatformTimeSource}. */
public static final class Builder implements DynamicInstant.Builder {
private final DynamicProto.PlatformTimeSource.Builder mImpl =
DynamicProto.PlatformTimeSource.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1895976938);
public Builder() {}
@Override
@NonNull
public PlatformTimeSource build() {
return new PlatformTimeSource(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic time instant type.
*
* <p>{@link DynamicInstant} precision is seconds. Thus, any time or duration operation will
* operate on that precision level.
*
* @since 1.2
*/
public interface DynamicInstant extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicInstant toDynamicInstantProto();
/**
* Creates a {@link DynamicInstant} from a byte array generated by {@link
* #toDynamicInstantByteArray()}.
*/
@NonNull
static DynamicInstant fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicInstantFromProto(
DynamicProto.DynamicInstant.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicInstant", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicInstantByteArray() {
return toDynamicInstantProto().toByteArray();
}
/**
* Creates a constant-valued {@link DynamicInstant} from an {@link Instant}. If {@link
* Instant} precision is greater than seconds, then any excess precision information will be
* dropped.
*/
@NonNull
static DynamicInstant withSecondsPrecision(@NonNull Instant instant) {
return new FixedInstant.Builder().setEpochSeconds(instant.getEpochSecond()).build();
}
/**
* Creates a {@link DynamicInstant} that updates its value periodically from the system
* time.
*/
@NonNull
static DynamicInstant platformTimeWithSecondsPrecision() {
return new PlatformTimeSource.Builder().build();
}
/**
* Returns duration between the two {@link DynamicInstant} instances as a {@link
* DynamicDuration}. The resulted duration is inclusive of the start instant and exclusive
* of the end; As an example, the following expression yields a duration object representing
* 10 seconds:
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(10L))
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(20L)));
* </pre>
*
* @return a new instance of {@link DynamicDuration} containing the result of the operation.
*/
@NonNull
default DynamicDuration durationUntil(@NonNull DynamicInstant to) {
return new BetweenDuration.Builder()
.setStartInclusive(this)
.setEndExclusive(to)
.build();
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicInstant} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicInstant build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicInstant dynamicInstantFromProto(
@NonNull DynamicProto.DynamicInstant proto) {
if (proto.hasFixed()) {
return FixedInstant.fromProto(proto.getFixed());
}
if (proto.hasPlatformSource()) {
return PlatformTimeSource.fromProto(proto.getPlatformSource());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicInstant");
}
/**
* A dynamic duration type that represents the duration between two dynamic time instants.
*
* @since 1.2
*/
static final class BetweenDuration implements DynamicDuration {
private final DynamicProto.BetweenDuration mImpl;
@Nullable private final Fingerprint mFingerprint;
BetweenDuration(DynamicProto.BetweenDuration impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the time instant value marking the start of the duration.
*
* @since 1.2
*/
@Nullable
public DynamicInstant getStartInclusive() {
if (mImpl.hasStartInclusive()) {
return DynamicBuilders.dynamicInstantFromProto(mImpl.getStartInclusive());
} else {
return null;
}
}
/**
* Gets the time instant value marking the end of the duration.
*
* @since 1.2
*/
@Nullable
public DynamicInstant getEndExclusive() {
if (mImpl.hasEndExclusive()) {
return DynamicBuilders.dynamicInstantFromProto(mImpl.getEndExclusive());
} else {
return null;
}
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static BetweenDuration fromProto(@NonNull DynamicProto.BetweenDuration proto) {
return new BetweenDuration(proto, null);
}
@NonNull
DynamicProto.BetweenDuration toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicDuration toDynamicDurationProto() {
return DynamicProto.DynamicDuration.newBuilder().setBetween(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "BetweenDuration{"
+ "startInclusive="
+ getStartInclusive()
+ ", endExclusive="
+ getEndExclusive()
+ "}";
}
/** Builder for {@link BetweenDuration}. */
public static final class Builder implements DynamicDuration.Builder {
private final DynamicProto.BetweenDuration.Builder mImpl =
DynamicProto.BetweenDuration.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-1615230958);
public Builder() {}
/**
* Sets the time instant value marking the start of the duration.
*
* @since 1.2
*/
@NonNull
public Builder setStartInclusive(@NonNull DynamicInstant startInclusive) {
mImpl.setStartInclusive(startInclusive.toDynamicInstantProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(startInclusive.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the time instant value marking the end of the duration.
*
* @since 1.2
*/
@NonNull
public Builder setEndExclusive(@NonNull DynamicInstant endExclusive) {
mImpl.setEndExclusive(endExclusive.toDynamicInstantProto());
mFingerprint.recordPropertyUpdate(
2, checkNotNull(endExclusive.getFingerprint()).aggregateValueAsInt());
return this;
}
@Override
@NonNull
public BetweenDuration build() {
return new BetweenDuration(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface defining a dynamic duration type.
*
* @since 1.2
*/
public interface DynamicDuration extends DynamicType {
/** Get the protocol buffer representation of this object. */
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
DynamicProto.DynamicDuration toDynamicDurationProto();
/**
* Creates a {@link DynamicDuration} from a byte array generated by {@link
* #toDynamicDurationByteArray()}.
*/
@NonNull
static DynamicDuration fromByteArray(@NonNull byte[] byteArray) {
try {
return dynamicDurationFromProto(
DynamicProto.DynamicDuration.parseFrom(
byteArray, ExtensionRegistryLite.getEmptyRegistry()));
} catch (InvalidProtocolBufferException e) {
throw new IllegalArgumentException(
"Byte array could not be parsed into DynamicDuration", e);
}
}
/** Creates a byte array that can later be used with {@link #fromByteArray(byte[])}. */
@NonNull
default byte[] toDynamicDurationByteArray() {
return toDynamicDurationProto().toByteArray();
}
/**
* Returns the total number of days in a {@link DynamicDuration} as a {@link DynamicInt32}.
* The fraction part of the result will be truncated. This is based on the standard
* definition of a day as 24 hours. As an example, the following is equal to {@code
* DynamicInt32.constant(1)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .toIntDays();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
* Integer overflow can occur if the result of the operation is larger than {@link
* Integer#MAX_VALUE}.
*/
@NonNull
default DynamicInt32 toIntDays() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_TOTAL_DAYS)
.build();
}
/**
* Returns the total number of hours in a {@link DynamicDuration} as a {@link DynamicInt32}.
* The fraction part of the result will be truncated. As an example, the following is equal
* to {@code DynamicInt32.constant(34)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .toIntHours();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
* Integer overflow can occur if the result of the operation is larger than {@link
* Integer#MAX_VALUE}.
*/
@NonNull
default DynamicInt32 toIntHours() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_TOTAL_HOURS)
.build();
}
/**
* Returns the total number of minutes in a {@link DynamicDuration} as a {@link
* DynamicInt32}. The fraction part of the result will be truncated. As an example, the
* following is equal to {@code DynamicInt32.constant(2057)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .toIntMinutes();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
* Integer overflow can occur if the result of the operation is larger than {@link
* Integer#MAX_VALUE}.
*/
@NonNull
default DynamicInt32 toIntMinutes() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_TOTAL_MINUTES)
.build();
}
/**
* Returns the total number of seconds in a {@link DynamicDuration} as a {@link
* DynamicInt32}. As an example, the following is equal to {@code
* DynamicInt32.constant(123456)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .toIntSeconds();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
* Integer overflow can occur if the result of the operation is larger than {@link
* Integer#MAX_VALUE}.
*/
@NonNull
default DynamicInt32 toIntSeconds() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_TOTAL_SECONDS)
.build();
}
/**
* Returns the total number of days in a duration as a {@link DynamicInt32}. This represents
* the absolute value of the total number of days in the duration based on the 24 hours day
* definition. The fraction part of the result will be truncated; As an example, the
* following is equal to {@code DynamicInt32.constant(1)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .getIntDaysPart();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
* Integer overflow can occur if the result of the operation is larger than {@link
* Integer#MAX_VALUE}.
*/
@NonNull
default DynamicInt32 getIntDaysPart() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_DAYS)
.build();
}
/**
* Returns the number of hours part in the duration as a {@link DynamicInt32}. This
* represents the absolute value of remaining hours when dividing total hours by hours in a
* day (24 hours); As an example, the following is equal to {@code
* DynamicInt32.constant(10)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .getHoursPart();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@NonNull
default DynamicInt32 getHoursPart() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_HOURS)
.build();
}
/**
* Returns the number of minutes part in the duration as a {@link DynamicInt32}. This
* represents the absolute value of remaining minutes when dividing total minutes by minutes
* in an hour (60 minutes). As an example, the following is equal to {@code
* DynamicInt32.constant(17)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .getMinutesPart();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@NonNull
default DynamicInt32 getMinutesPart() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_MINUTES)
.build();
}
/**
* Returns the number of seconds part in the duration as a {@link DynamicInt32}. This
* represents the absolute value of remaining seconds when dividing total seconds by seconds
* in a minute (60 seconds); As an example, the following is equal to {@code
* DynamicInt32.constant(36)}
*
* <pre>
* DynamicInstant.withSecondsPrecision(Instant.EPOCH)
* .durationUntil(DynamicInstant.withSecondsPrecision(Instant.ofEpochSecond(123456L)))
* .getSecondsPart();
* </pre>
*
* @return a new instance of {@link DynamicInt32} containing the result of the operation.
*/
@NonNull
default DynamicInt32 getSecondsPart() {
return new GetDurationPartOp.Builder()
.setInput(this)
.setDurationPart(DURATION_PART_TYPE_SECONDS)
.build();
}
/** Get the fingerprint for this object or null if unknown. */
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
Fingerprint getFingerprint();
/** Builder to create {@link DynamicDuration} objects. */
@RestrictTo(Scope.LIBRARY_GROUP)
interface Builder {
/** Builds an instance with values accumulated in this Builder. */
@NonNull
DynamicDuration build();
}
}
/**
* Creates a new wrapper instance from the proto. Intended for testing purposes only. An object
* created using this method can't be added to any other wrapper.
*/
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public static DynamicDuration dynamicDurationFromProto(
@NonNull DynamicProto.DynamicDuration proto) {
if (proto.hasBetween()) {
return BetweenDuration.fromProto(proto.getBetween());
}
throw new IllegalStateException("Proto was not a recognised instance of DynamicDuration");
}
/**
* Retrieve the specified duration part of a {@link DynamicDuration} instance as a {@link
* DynamicInt32}.
*
* @since 1.2
*/
static final class GetDurationPartOp implements DynamicInt32 {
private final DynamicProto.GetDurationPartOp mImpl;
@Nullable private final Fingerprint mFingerprint;
GetDurationPartOp(DynamicProto.GetDurationPartOp impl, @Nullable Fingerprint fingerprint) {
this.mImpl = impl;
this.mFingerprint = fingerprint;
}
/**
* Gets the duration input.
*
* @since 1.2
*/
@Nullable
public DynamicDuration getInput() {
if (mImpl.hasInput()) {
return DynamicBuilders.dynamicDurationFromProto(mImpl.getInput());
} else {
return null;
}
}
/**
* Gets the duration part to retrieve.
*
* @since 1.2
*/
@DurationPartType
public int getDurationPart() {
return mImpl.getDurationPart().getNumber();
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@Nullable
public Fingerprint getFingerprint() {
return mFingerprint;
}
@NonNull
static GetDurationPartOp fromProto(@NonNull DynamicProto.GetDurationPartOp proto) {
return new GetDurationPartOp(proto, null);
}
@NonNull
DynamicProto.GetDurationPartOp toProto() {
return mImpl;
}
@Override
@RestrictTo(Scope.LIBRARY_GROUP)
@NonNull
public DynamicProto.DynamicInt32 toDynamicInt32Proto() {
return DynamicProto.DynamicInt32.newBuilder().setDurationPart(mImpl).build();
}
@Override
@NonNull
public String toString() {
return "GetDurationPartOp{"
+ "input="
+ getInput()
+ ", durationPart="
+ getDurationPart()
+ "}";
}
/** Builder for {@link GetDurationPartOp}. */
public static final class Builder implements DynamicInt32.Builder {
private final DynamicProto.GetDurationPartOp.Builder mImpl =
DynamicProto.GetDurationPartOp.newBuilder();
private final Fingerprint mFingerprint = new Fingerprint(-225941123);
public Builder() {}
/**
* Sets the duration input.
*
* @since 1.2
*/
@NonNull
public Builder setInput(@NonNull DynamicDuration input) {
mImpl.setInput(input.toDynamicDurationProto());
mFingerprint.recordPropertyUpdate(
1, checkNotNull(input.getFingerprint()).aggregateValueAsInt());
return this;
}
/**
* Sets the duration part to retrieve.
*
* @since 1.2
*/
@NonNull
public Builder setDurationPart(@DurationPartType int durationPart) {
mImpl.setDurationPart(DynamicProto.DurationPartType.forNumber(durationPart));
mFingerprint.recordPropertyUpdate(2, durationPart);
return this;
}
@Override
@NonNull
public GetDurationPartOp build() {
return new GetDurationPartOp(mImpl.build(), mFingerprint);
}
}
}
/**
* Interface to be used as a base type for all other dynamic types. This is not consumed by any
* Tile elements, it exists just as a marker interface for use internally in the Tiles library.
*/
public interface DynamicType {}
}