/**
* 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;
/**
* The default {@link TimingSource} hooked into Android's Choreographer.
*/
public class ChoreographerTimingSource implements TimingSource {
private final ChoreographerCompat mChoreographerCompat;
private final ChoreographerCompat.FrameCallback mFrameCallback;
private DataFlowGraph mDataFlowGraph;
private boolean mIsRunning = false;
private boolean mHasPostedFrameCallback = false;
private long mLastFrameTime = Long.MIN_VALUE;
public ChoreographerTimingSource() {
mChoreographerCompat = ChoreographerCompat.getInstance();
mFrameCallback = new ChoreographerCompat.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
ChoreographerTimingSource.this.doFrame(frameTimeNanos);
}
};
}
public void setDataFlowGraph(DataFlowGraph dataFlowGraph) {
mDataFlowGraph = dataFlowGraph;
}
@Override
public void start() {
if (mDataFlowGraph == null) {
throw new RuntimeException("Must set a binding graph first.");
}
if (mIsRunning) {
throw new RuntimeException("Tried to start but was already running.");
}
mIsRunning = true;
postFrameCallback();
}
@Override
public void stop() {
if (!mIsRunning) {
throw new RuntimeException("Tried to stop but wasn't running.");
}
mIsRunning = false;
stopFrameCallback();
}
private void postFrameCallback() {
if (mHasPostedFrameCallback) {
return;
}
mChoreographerCompat.postFrameCallback(mFrameCallback);
mHasPostedFrameCallback = true;
}
private void stopFrameCallback() {
mChoreographerCompat.removeFrameCallback(mFrameCallback);
}
private void doFrame(long frameTimeNanos) {
mHasPostedFrameCallback = false;
if (!mIsRunning) {
return;
}
// Sometimes Choreographer can call doFrame multiple times with the same frame time, especially
// in the case of skipped frames. De-bounce it here.
if (mLastFrameTime != frameTimeNanos) {
mDataFlowGraph.doFrame(frameTimeNanos);
mLastFrameTime = frameTimeNanos;
}
if (mIsRunning) {
postFrameCallback();
}
}
}