/*
* Copyright (c) 2015-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.imagepipeline.testing;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.facebook.common.time.MonotonicClock;
/**
*
*
*/
public class FakeClock implements MonotonicClock {
public interface OnTickListener {
void onTick();
}
private final Map<OnTickListener, OnTickListener> otherClocks =
new ConcurrentHashMap<OnTickListener, OnTickListener>();
private final Map<OnTickListener, OnTickListener> listeners =
new ConcurrentHashMap<OnTickListener, OnTickListener>();
private long now;
public FakeClock() {
now = 100000;
}
public FakeClock(long now) {
this.now = now;
}
public void incrementBy(long amountMs) {
synchronized (this) {
now += amountMs;
}
// Update other clocks before dispatching to listeners. This is not a perfect solution, since
// the other clocks might still dispatch events before subsequent clocks are updated. All
// clocks should be forced to update their time before dispatching events so all clocks are
// guaranteed in sync, but it's better than the random order of having everything in a single
// listeners Map where some events will be dispatched before other clocks are updated depending
// on hashing randomness.
for (OnTickListener otherClock : otherClocks.keySet()) {
otherClock.onTick();
}
for (OnTickListener listener : listeners.keySet()) {
listener.onTick();
}
}
/**
* Increments the clock's time gradually in several steps
*
* The clock will be incremented by tickMs amount repeatedly until it has progress by totalMs
* from the given time when this call was made.
*
* This call is useful for working with animations in tests.
*
* In the end of this call, the call will progress by exactly totalMs, even if it means the last
* tick of the clock is smaller than tickMs
*
* @param tickMs the amount to tick the clock at each step
* @param totalMs the total amount of time to elapse during the call
*/
public void incrementInSteps(long tickMs, long totalMs) {
long start = now;
long end = start + totalMs;
while (now < end) {
incrementBy(Math.min(tickMs, end - now));
}
}
@Override
public synchronized long now() {
return now;
}
/**
* Add a clock that will get called before {@link #listeners}, in order to guarantee call order.
*/
public void addOtherClock(OnTickListener otherClock) {
otherClocks.put(otherClock, otherClock);
}
public void addListener(OnTickListener listener) {
listeners.put(listener, listener);
}
public void removeListener(OnTickListener listener) {
listeners.remove(listener);
}
}