public Result tick() {
    if (System.currentTimeMillis() >= mLastEventHorizonMs) {
      return Result.EXPIRED;
    }
    if (System.currentTimeMillis() < mNextEventMs) {
      return Result.NOT_READY;
    }
    mNextEventMs = System.currentTimeMillis() + mIntervalMs;
    long next = Math.min(mIntervalMs * 2, mMaxIntervalMs);
    // Account for overflow.
    if (next < mIntervalMs) {
      next = Integer.MAX_VALUE;
    }
    mIntervalMs = next;
    mNumEvents++;
    return Result.READY;
  }
@Test(timeout = 2000)
  public void backoff() {
    int n = 10;
    ExponentialTimer timer = new ExponentialTimer(1, 1000, 0, 1000);
    long start = System.currentTimeMillis();
    for (int i = 0; i < n; i++) {
      while (timer.tick() == ExponentialTimer.Result.NOT_READY) {
        CommonUtils.sleepMs(10);
      }
      long now = System.currentTimeMillis();
      assertTrue(now - start >= (1 << i - 1));
    }
  }