Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ad7b629 authored by Nazanin Bakhshi's avatar Nazanin Bakhshi Committed by Gerrit Code Review
Browse files

Merge "Add slidingWindowEventCounter class in telephony"

parents 45afd727 1e8d1684
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony;

import android.annotation.IntRange;
import android.util.LongArrayQueue;

import com.android.internal.annotations.VisibleForTesting;

/**
 * Tracks whether an event occurs mNumOccurrences times within the time span mWindowSizeMillis.
 * <p/>
 * Stores all events in memory, use a small number of required occurrences when using.
 */
public class SlidingWindowEventCounter {
    private final long mWindowSizeMillis;
    private final int mNumOccurrences;
    private final LongArrayQueue mTimestampQueueMillis;

    public SlidingWindowEventCounter(@IntRange(from = 1) final long windowSizeMillis,
            @IntRange(from = 2) final int numOccurrences) {
        if (windowSizeMillis <= 0) {
            throw new IllegalArgumentException("windowSizeMillis must be greater than 0");
        }
        if (numOccurrences <= 1) {
            throw new IllegalArgumentException("numOccurrences must be greater than 1");
        }

        mWindowSizeMillis = windowSizeMillis;
        mNumOccurrences = numOccurrences;
        mTimestampQueueMillis = new LongArrayQueue(numOccurrences);
    }

    /**
     * Increments the occurrence counter.
     *
     * Returns true if an event has occurred at least mNumOccurrences times within the
     * time span mWindowSizeMillis.
     * @param timestampMillis
     */
    public synchronized boolean addOccurrence(long timestampMillis) {
        mTimestampQueueMillis.addLast(timestampMillis);
        if (mTimestampQueueMillis.size() > mNumOccurrences) {
            mTimestampQueueMillis.removeFirst();
        }
        return isInWindow();
    }

    /**
     * Returns true if the conditions is satisfied.
     */
    public synchronized boolean isInWindow() {
        return (mTimestampQueueMillis.size() == mNumOccurrences)
                && mTimestampQueueMillis.peekFirst()
                + mWindowSizeMillis >= mTimestampQueueMillis.peekLast();
    }

    @VisibleForTesting
    int getNumOccurrences() {
        return mTimestampQueueMillis.size();
    }
}
+76 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.os.SystemClock;

import org.junit.Before;
import org.junit.Test;

public class SlidingWindowEventCounterTest extends TelephonyTest {
    long mInitialTime;

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
        mInitialTime = SystemClock.elapsedRealtime();
    }

    @Test
    public void test_returnsTrue_ifEnoughEntriesInWindow() {
        SlidingWindowEventCounter counter = new SlidingWindowEventCounter(100, 3);
        for (int i = 0; i < 3; i++) {
            counter.addOccurrence(mInitialTime + i);
        }
        assertTrue(counter.isInWindow());
    }

    @Test
    public void test_returnsTrue_ifMoreThanEnoughEntriesInWindow() {
        SlidingWindowEventCounter counter = new SlidingWindowEventCounter(100, 3);
        for (int i = 0; i < 3; i++) {
            counter.addOccurrence(mInitialTime + i);
        }
        for (int i = 0; i < 3; i++) {
            counter.addOccurrence(mInitialTime + i + 50);
        }
        assertTrue(counter.isInWindow());
    }

    @Test
    public void test_returnsFalse_ifNotEnoughEntriesInWindow() {
        SlidingWindowEventCounter counter = new SlidingWindowEventCounter(100, 3);
        for (int i = 0; i < 2; i++) {
            counter.addOccurrence(mInitialTime + i);
        }
        assertFalse(counter.isInWindow());
    }

    @Test
    public void test_returnsFalse_ifEnoughEntriesButTooFarApart() {
        SlidingWindowEventCounter counter = new SlidingWindowEventCounter(100, 3);
        for (int i = 0; i < 2; i++) {
            counter.addOccurrence(mInitialTime + i);
        }
        counter.addOccurrence(mInitialTime + 101);
        counter.addOccurrence(mInitialTime + 102);
        assertFalse(counter.isInWindow());
    }
}