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

Commit fd303327 authored by Tony Mak's avatar Tony Mak
Browse files

Fix first notification of each app is not shown

When app tries to post its first notification,
value of now is equal to that of mLastEventTime.
And hence getRate return a very large number.

Bug: 28902358

Change-Id: If5b5b3c46e2bb80a9b40988ba7f7d777e40cc8e7
parent d86ac811
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -384,7 +384,7 @@ public class NotificationUsageStats {
            noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_");
            quietImportance = new ImportanceHistogram(context, "note_imp_quiet_");
            finalImportance = new ImportanceHistogram(context, "note_importance_");
            enqueueRate = new RateEstimator(mCreated);
            enqueueRate = new RateEstimator();
        }

        public AggregatedStats getPrevious() {
+22 −9
Original line number Diff line number Diff line
@@ -25,30 +25,43 @@ package com.android.server.notification;
public class RateEstimator {
    private static final double RATE_ALPHA = 0.8;
    private static final double MINIMUM_DT = 0.0005;
    private long mLastEventTime;
    private float mInterarrivalTime;
    private Long mLastEventTime;
    private Float mInterarrivalTime;

    public RateEstimator(long now) {
        mLastEventTime = now;
    }
    public RateEstimator() {}

    /** Update the estimate to account for an event that jsut happened. */
    /** Update the estimate to account for an event that just happened. */
    public float update(long now) {
        float rate;
        if (mLastEventTime == null) {
            // No last event time, rate is zero.
            rate = 0f;
        } else {
            // Calculate the new inter-arrival time based on last event time.
            mInterarrivalTime = (float) getInterarrivalEstimate(now);
            rate = (float) (1.0 / mInterarrivalTime);
        }
        mLastEventTime = now;
        return (float) (1.0 / mInterarrivalTime);
        return rate;
    }

    /** @return the estimated rate if there were a new event right now. */
    public float getRate(long now) {
        if (mLastEventTime == null) {
            return 0f;
        }
        return (float) (1.0 / getInterarrivalEstimate(now));
    }

    /** @return the average inter-arrival time if there were a new event right now. */
    private double getInterarrivalEstimate(long now) {
        // a*iat_old + (1-a)*(t_now-t_last)
        double dt = ((double) (now - mLastEventTime)) / 1000.0;
        dt = Math.max(dt, MINIMUM_DT);
        if (mInterarrivalTime == null) {
            // No last inter-arrival time, return the new value directly.
            return dt;
        }
        // a*iat_old + (1-a)*(t_now-t_last)
        return (RATE_ALPHA * mInterarrivalTime + (1.0 - RATE_ALPHA) * dt);
    }
}
+25 −7
Original line number Diff line number Diff line
@@ -26,18 +26,18 @@ public class RateEstimatorTest extends AndroidTestCase {
    @Override
    public void setUp() {
        mTestStartTime = 1225731600000L;
        mEstimator = new RateEstimator(mTestStartTime);
        mEstimator = new RateEstimator();
    }

    @SmallTest
    public void testRunningTimeBackwardDoesntExplodeUpdate() throws Exception {
        final float rate = mEstimator.update(mTestStartTime - 1000L);
        assertFalse(Float.isInfinite(rate));
        assertFalse(Float.isNaN(rate));
        assertUpdateTime(mTestStartTime);
        assertUpdateTime(mTestStartTime - 1000L);
    }

    @SmallTest
    public void testRunningTimeBackwardDoesntExplodeGet() throws Exception {
        assertUpdateTime(mTestStartTime);
        final float rate = mEstimator.getRate(mTestStartTime - 1000L);
        assertFalse(Float.isInfinite(rate));
        assertFalse(Float.isNaN(rate));
@@ -45,13 +45,14 @@ public class RateEstimatorTest extends AndroidTestCase {

    @SmallTest
    public void testInstantaneousEventsDontExplodeUpdate() throws Exception {
        final float rate = mEstimator.update(mTestStartTime);
        assertFalse(Float.isInfinite(rate));
        assertFalse(Float.isNaN(rate));
        assertUpdateTime(mTestStartTime);
        assertUpdateTime(mTestStartTime);
    }

    @SmallTest
    public void testInstantaneousEventsDontExplodeGet() throws Exception {
        assertUpdateTime(mTestStartTime);
        assertUpdateTime(mTestStartTime);
        final float rate = mEstimator.getRate(mTestStartTime);
        assertFalse(Float.isInfinite(rate));
        assertFalse(Float.isNaN(rate));
@@ -59,6 +60,7 @@ public class RateEstimatorTest extends AndroidTestCase {

    @SmallTest
    public void testCompactBurstIsEstimatedUnderTwoPercent() throws Exception {
        assertUpdateTime(mTestStartTime);
        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
        long nextEventTime = postEvents(eventStart, 1, 5); // five events at 1000Hz
        final float rate = mEstimator.getRate(nextEventTime);
@@ -67,6 +69,7 @@ public class RateEstimatorTest extends AndroidTestCase {

    @SmallTest
    public void testSustained1000HzBurstIsEstimatedOverNinetyPercent() throws Exception {
        assertUpdateTime(mTestStartTime);
        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
        long nextEventTime = postEvents(eventStart, 1, 100); // one hundred events at 1000Hz
        final float rate = mEstimator.getRate(nextEventTime);
@@ -75,6 +78,7 @@ public class RateEstimatorTest extends AndroidTestCase {

    @SmallTest
    public void testSustained100HzBurstIsEstimatedOverNinetyPercent() throws Exception {
        assertUpdateTime(mTestStartTime);
        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
        long nextEventTime = postEvents(eventStart, 10, 100); // one hundred events at 100Hz
        final float rate = mEstimator.getRate(nextEventTime);
@@ -84,6 +88,7 @@ public class RateEstimatorTest extends AndroidTestCase {

    @SmallTest
    public void testRecoverQuicklyAfterSustainedBurst() throws Exception {
        assertUpdateTime(mTestStartTime);
        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
        long nextEventTime = postEvents(eventStart, 10, 1000); // one hundred events at 100Hz
        final float rate = mEstimator.getRate(nextEventTime + 5000L); // two seconds later
@@ -92,12 +97,19 @@ public class RateEstimatorTest extends AndroidTestCase {

    @SmallTest
    public void testEstimateShouldNotOvershoot() throws Exception {
        assertUpdateTime(mTestStartTime);
        long eventStart = mTestStartTime + 1000; // start event a long time after initialization
        long nextEventTime = postEvents(eventStart, 1, 1000); // one thousand events at 1000Hz
        final float rate = mEstimator.getRate(nextEventTime);
        assertLessThan("Rate", rate, 1000f);
    }

    @SmallTest
    public void testGetRateWithoutUpdate() throws Exception {
        final float rate = mEstimator.getRate(mTestStartTime);
        assertLessThan("Rate", rate, 0.1f);
    }

    private void assertLessThan(String label, float a, float b)  {
        assertTrue(String.format("%s was %f, but should be less than %f", label, a, b), a < b);
    }
@@ -115,4 +127,10 @@ public class RateEstimatorTest extends AndroidTestCase {
        }
        return time;
    }

    private void assertUpdateTime(long time) {
        final float rate = mEstimator.update(time);
        assertFalse(Float.isInfinite(rate));
        assertFalse(Float.isNaN(rate));
    }
}