/* * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.litho.dataflow; /** * A ValueNode that will linearly update its value from its "initial" input to its "end" input * over the course of the given duration. * * This node supports the "end" input changing: it will animate to that new end value over the * remaining duration meaning that velocity of the value may change. * * NB: If the end input changes after the end of the duration, this node will just pass through that * new value. */ public class TimingNode extends ValueNode implements NodeCanFinish { public static final String INITIAL_INPUT = "initial"; public static final String END_INPUT = "end"; private static final int MS_IN_NANOS = 1000000; private final int mDurationMs; private long mStartTimeNs = Long.MIN_VALUE; private long mExpectedEndTimeNs = Long.MIN_VALUE; private long mLastValueTimeNs = Long.MIN_VALUE; private float mInitialValue; private boolean mAreParentsFinished = false; private boolean mIsFinished = false; public TimingNode(int durationMs) { mDurationMs = durationMs; } @Override public float calculateValue(long frameTimeNanos) { if (mLastValueTimeNs == Long.MIN_VALUE) { mInitialValue = getInput(INITIAL_INPUT).getValue(); mStartTimeNs = frameTimeNanos; mLastValueTimeNs = frameTimeNanos; mExpectedEndTimeNs = mStartTimeNs + (mDurationMs * MS_IN_NANOS); return mInitialValue; } float endValue = getInput(END_INPUT).getValue(); if (frameTimeNanos >= mExpectedEndTimeNs) { mIsFinished = true; return endValue; } float lastValue = getValue(); float desiredVelocity = (endValue - lastValue) / (mExpectedEndTimeNs - mLastValueTimeNs); float increment = desiredVelocity * (frameTimeNanos - mLastValueTimeNs); mLastValueTimeNs = frameTimeNanos; return lastValue + increment; } @Override public boolean isFinished() { return mIsFinished && mAreParentsFinished; } @Override public void onInputsFinished() { mAreParentsFinished = true; mIsFinished = mLastValueTimeNs >= mExpectedEndTimeNs; } }