Int32Nodes.java
/*
* 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.pipeline;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.wear.protolayout.expression.pipeline.PlatformDataSources.EpochTimePlatformDataSource;
import androidx.wear.protolayout.expression.pipeline.PlatformDataSources.PlatformDataSource;
import androidx.wear.protolayout.expression.pipeline.PlatformDataSources.SensorGatewayPlatformDataSource;
import androidx.wear.protolayout.expression.proto.DynamicProto.ArithmeticInt32Op;
import androidx.wear.protolayout.expression.proto.DynamicProto.FloatToInt32Op;
import androidx.wear.protolayout.expression.proto.DynamicProto.PlatformInt32Source;
import androidx.wear.protolayout.expression.proto.DynamicProto.PlatformInt32SourceType;
import androidx.wear.protolayout.expression.proto.DynamicProto.StateInt32Source;
import androidx.wear.protolayout.expression.proto.FixedProto.FixedInt32;
/** Dynamic data nodes which yield integers. */
class Int32Nodes {
private Int32Nodes() {}
/** Dynamic integer node that has a fixed value. */
static class FixedInt32Node implements DynamicDataSourceNode<Integer> {
private final int mValue;
private final DynamicTypeValueReceiver<Integer> mDownstream;
FixedInt32Node(FixedInt32 protoNode, DynamicTypeValueReceiver<Integer> downstream) {
this.mValue = protoNode.getValue();
this.mDownstream = downstream;
}
@Override
@UiThread
public void preInit() {
mDownstream.onPreUpdate();
}
@Override
@UiThread
public void init() {
mDownstream.onData(mValue);
}
@Override
@UiThread
public void destroy() {}
}
/** Dynamic integer node that gets value from the platform source. */
static class PlatformInt32SourceNode implements DynamicDataSourceNode<Integer> {
private static final String TAG = "PlatformInt32SourceNode";
@Nullable private final SensorGatewayPlatformDataSource mSensorGatewaySource;
@Nullable private final EpochTimePlatformDataSource mEpochTimePlatformDataSource;
private final PlatformInt32Source mProtoNode;
private final DynamicTypeValueReceiver<Integer> mDownstream;
PlatformInt32SourceNode(
PlatformInt32Source protoNode,
@Nullable EpochTimePlatformDataSource epochTimePlatformDataSource,
@Nullable SensorGatewayPlatformDataSource sensorGatewaySource,
DynamicTypeValueReceiver<Integer> downstream) {
this.mProtoNode = protoNode;
this.mEpochTimePlatformDataSource = epochTimePlatformDataSource;
this.mSensorGatewaySource = sensorGatewaySource;
this.mDownstream = downstream;
}
@Override
@UiThread
public void preInit() {
if (platformInt32SourceTypeToPlatformDataSource(mProtoNode.getSourceType()) != null) {
mDownstream.onPreUpdate();
}
}
@Override
@UiThread
public void init() {
PlatformDataSource dataSource =
platformInt32SourceTypeToPlatformDataSource(mProtoNode.getSourceType());
if (dataSource != null) {
dataSource.registerForData(mProtoNode.getSourceType(), mDownstream);
} else {
mDownstream.onInvalidated();
}
}
@Override
@UiThread
public void destroy() {
PlatformDataSource dataSource =
platformInt32SourceTypeToPlatformDataSource(mProtoNode.getSourceType());
if (dataSource != null) {
dataSource.unregisterForData(mProtoNode.getSourceType(), mDownstream);
}
}
@Nullable
private PlatformDataSource platformInt32SourceTypeToPlatformDataSource(
PlatformInt32SourceType sourceType) {
switch (sourceType) {
case UNRECOGNIZED:
case PLATFORM_INT32_SOURCE_TYPE_UNDEFINED:
Log.w(TAG, "Unknown PlatformInt32SourceType");
return null;
case PLATFORM_INT32_SOURCE_TYPE_CURRENT_HEART_RATE:
case PLATFORM_INT32_SOURCE_TYPE_DAILY_STEP_COUNT:
return mSensorGatewaySource;
case PLATFORM_INT32_SOURCE_TYPE_EPOCH_TIME_SECONDS:
return mEpochTimePlatformDataSource;
}
Log.w(TAG, "Unknown PlatformInt32SourceType");
return null;
}
}
/** Dynamic integer node that supports arithmetic operations. */
static class ArithmeticInt32Node extends DynamicDataBiTransformNode<Integer, Integer, Integer> {
private static final String TAG = "ArithmeticInt32Node";
ArithmeticInt32Node(
ArithmeticInt32Op protoNode, DynamicTypeValueReceiver<Integer> downstream) {
super(
downstream,
(lhs, rhs) -> {
try {
switch (protoNode.getOperationType()) {
case ARITHMETIC_OP_TYPE_UNDEFINED:
case UNRECOGNIZED:
Log.e(TAG, "Unknown operation type in ArithmeticInt32Node");
return 0;
case ARITHMETIC_OP_TYPE_ADD:
return lhs + rhs;
case ARITHMETIC_OP_TYPE_SUBTRACT:
return lhs - rhs;
case ARITHMETIC_OP_TYPE_MULTIPLY:
return lhs * rhs;
case ARITHMETIC_OP_TYPE_DIVIDE:
return lhs / rhs;
case ARITHMETIC_OP_TYPE_MODULO:
return lhs % rhs;
}
} catch (ArithmeticException ex) {
Log.e(TAG, "ArithmeticException in ArithmeticInt32Node", ex);
return 0;
}
Log.e(TAG, "Unknown operation type in ArithmeticInt32Node");
return 0;
});
}
}
/** Dynamic integer node that gets value from the state. */
static class StateInt32SourceNode extends StateSourceNode<Integer> {
StateInt32SourceNode(
ObservableStateStore observableStateStore,
StateInt32Source protoNode,
DynamicTypeValueReceiver<Integer> downstream) {
super(
observableStateStore,
protoNode.getSourceKey(),
se -> se.getInt32Val().getValue(),
downstream);
}
}
/** Dynamic integer node that gets value from float. */
static class FloatToInt32Node extends DynamicDataTransformNode<Float, Integer> {
FloatToInt32Node(FloatToInt32Op protoNode, DynamicTypeValueReceiver<Integer> downstream) {
super(
downstream,
x -> {
switch (protoNode.getRoundMode()) {
case ROUND_MODE_UNDEFINED:
case ROUND_MODE_FLOOR:
return (int) Math.floor(x);
case ROUND_MODE_ROUND:
return Math.round(x);
case ROUND_MODE_CEILING:
return (int) Math.ceil(x);
default:
throw new IllegalArgumentException("Unknown rounding mode");
}
});
}
}
}