/**
   * Adds bandwidth to the current filtered latency counter. Sends a broadcast to all {@link
   * ConnectionClassStateChangeListener} if the counter moves from one bucket to another (i.e. poor
   * bandwidth -> moderate bandwidth).
   */
  public synchronized void addBandwidth(long bytes, long timeInMs) {

    // Ignore garbage values.
    if (timeInMs == 0 || (bytes) * 1.0 / (timeInMs) * BYTES_TO_BITS < BANDWIDTH_LOWER_BOUND) {
      return;
    }

    double bandwidth = (bytes) * 1.0 / (timeInMs) * BYTES_TO_BITS;
    mDownloadBandwidth.addMeasurement(bandwidth);

    if (mInitiateStateChange) {
      mSampleCounter += 1;
      if (getCurrentBandwidthQuality() != mNextBandwidthConnectionQuality.get()) {
        mInitiateStateChange = false;
        mSampleCounter = 1;
      }
      if (mSampleCounter >= DEFAULT_SAMPLES_TO_QUALITY_CHANGE
          && significantlyOutsideCurrentBand()) {
        mInitiateStateChange = false;
        mSampleCounter = 1;
        mCurrentBandwidthConnectionQuality.set(mNextBandwidthConnectionQuality.get());
        notifyListeners();
      }
      return;
    }

    if (mCurrentBandwidthConnectionQuality.get() != getCurrentBandwidthQuality()) {
      mInitiateStateChange = true;
      mNextBandwidthConnectionQuality =
          new AtomicReference<ConnectionQuality>(getCurrentBandwidthQuality());
    }
  }
 private boolean significantlyOutsideCurrentBand() {
   if (mDownloadBandwidth == null) {
     // Make Infer happy. It wouldn't make any sense to call this while mDownloadBandwidth is null.
     return false;
   }
   ConnectionQuality currentQuality = mCurrentBandwidthConnectionQuality.get();
   double bottomOfBand;
   double topOfBand;
   switch (currentQuality) {
     case POOR:
       bottomOfBand = 0;
       topOfBand = DEFAULT_POOR_BANDWIDTH;
       break;
     case MODERATE:
       bottomOfBand = DEFAULT_POOR_BANDWIDTH;
       topOfBand = DEFAULT_MODERATE_BANDWIDTH;
       break;
     case GOOD:
       bottomOfBand = DEFAULT_MODERATE_BANDWIDTH;
       topOfBand = DEFAULT_GOOD_BANDWIDTH;
       break;
     case EXCELLENT:
       bottomOfBand = DEFAULT_GOOD_BANDWIDTH;
       topOfBand = Float.MAX_VALUE;
       break;
     default: // If current quality is UNKNOWN, then changing is always valid.
       return true;
   }
   double average = mDownloadBandwidth.getAverage();
   if (average > topOfBand) {
     if (average > topOfBand * HYSTERESIS_TOP_MULTIPLIER) {
       return true;
     }
   } else if (average < bottomOfBand * HYSTERESIS_BOTTOM_MULTIPLIER) {
     return true;
   }
   return false;
 }
 /**
  * Accessor method for the current bandwidth average.
  *
  * @return The current bandwidth average, or -1 if no average has been recorded.
  */
 public synchronized double getDownloadKBitsPerSecond() {
   return mDownloadBandwidth == null ? -1.0 : mDownloadBandwidth.getAverage();
 }
 /**
  * Get the ConnectionQuality that the moving bandwidth average currently represents.
  *
  * @return A ConnectionQuality representing the device's bandwidth at this exact moment.
  */
 public synchronized ConnectionQuality getCurrentBandwidthQuality() {
   if (mDownloadBandwidth == null) {
     return ConnectionQuality.UNKNOWN;
   }
   return mapBandwidthQuality(mDownloadBandwidth.getAverage());
 }
 /** Resets the bandwidth average for this instance of the bandwidth manager. */
 public void reset() {
   if (mDownloadBandwidth != null) {
     mDownloadBandwidth.reset();
   }
   mCurrentBandwidthConnectionQuality.set(ConnectionQuality.UNKNOWN);
 }