chromium/chrome/browser/feed/android/java/src/org/chromium/chrome/browser/feed/ScrollTracker.java

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.feed;

import androidx.annotation.Nullable;

import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits;

/** Helper which is able to track a Scroll and aggregate them before sending the scroll events. */
public abstract class ScrollTracker {
    // onScroll events are very noisy, so we collate them together to avoid over-reporting scrolls.
    private static final long SCROLL_EVENT_COLLATE_MILLIS = 200L;

    @Nullable private ReportFunction mPostedReportFunction;

    // If |mScrollAmount| is non-zero and should be reported when ReportFunction runs.
    private boolean mReadyToReport;
    // How much scrolling is currently unreported. May be negative.
    private int mScrollAmount;

    public void onUnbind() {
        reportAndReset();
    }

    public void trackScroll(int dx, int dy) {
        if (dy == 0) {
            return;
        }

        if (mScrollAmount != 0 && (dy > 0) != (mScrollAmount > 0)) {
            // Scroll direction changing, report it now.
            reportAndReset();
        }

        mScrollAmount += dy;
        if (mPostedReportFunction == null) {
            mReadyToReport = true;
            mPostedReportFunction = new ReportFunction();
            PostTask.postDelayedTask(
                    TaskTraits.UI_DEFAULT, mPostedReportFunction, SCROLL_EVENT_COLLATE_MILLIS);
        } else {
            mReadyToReport = false;
        }
    }

    private void reportAndReset() {
        if (mScrollAmount != 0) {
            onScrollEvent(mScrollAmount);
            mScrollAmount = 0;
        }
        mReadyToReport = false;
    }

    protected abstract void onScrollEvent(int scrollAmount);

    private class ReportFunction implements Runnable {
        @Override
        public void run() {
            if (mReadyToReport) {
                reportAndReset();
                mPostedReportFunction = null;
            } else if (mScrollAmount != 0) {
                mReadyToReport = true;
                PostTask.postDelayedTask(
                        TaskTraits.UI_DEFAULT, mPostedReportFunction, SCROLL_EVENT_COLLATE_MILLIS);
            }
        }
    }
}