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

Commit aa03774d authored by Julia Tuttle's avatar Julia Tuttle Committed by Android (Google) Code Review
Browse files

Merge "Convert HeadsUpManager et al to use an Executor" into main

parents f350b433 8036c4fa
Loading
Loading
Loading
Loading
+48 −17
Original line number Diff line number Diff line
@@ -18,16 +18,16 @@ package com.android.systemui.statusbar;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Handler;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;

import java.util.stream.Stream;
@@ -46,13 +46,12 @@ public abstract class AlertingNotificationManager {
    protected int mMinimumDisplayTime;
    protected int mStickyForSomeTimeAutoDismissTime;
    protected int mAutoDismissTime;
    @VisibleForTesting
    public Handler mHandler;
    private DelayableExecutor mExecutor;

    public AlertingNotificationManager(HeadsUpManagerLogger logger, @Main Handler handler,
            SystemClock systemClock) {
    public AlertingNotificationManager(HeadsUpManagerLogger logger,
            SystemClock systemClock, @Main DelayableExecutor executor) {
        mLogger = logger;
        mHandler = handler;
        mExecutor = executor;
        mSystemClock = systemClock;
    }

@@ -264,6 +263,7 @@ public abstract class AlertingNotificationManager {
        public long mEarliestRemovalTime;

        @Nullable protected Runnable mRemoveAlertRunnable;
        @Nullable private Runnable mCancelRemoveAlertRunnable;

        public void setEntry(@NonNull final NotificationEntry entry) {
            setEntry(entry, () -> removeAlertEntry(entry.getKey()));
@@ -291,13 +291,15 @@ public abstract class AlertingNotificationManager {
            if (updatePostTime) {
                mPostTime = Math.max(mPostTime, now);
            }
            removeAutoRemovalCallbacks("updateEntry (will be rescheduled)");

            if (!isSticky()) {
            if (isSticky()) {
                removeAutoRemovalCallbacks("updateEntry (sticky)");
                return;
            }

            final long finishTime = calculateFinishTime();
            final long timeLeft = Math.max(finishTime - now, mMinimumDisplayTime);
                mHandler.postDelayed(mRemoveAlertRunnable, timeLeft);
            }
            scheduleAutoRemovalCallback(timeLeft, "updateEntry (not sticky)");
        }

        /**
@@ -340,21 +342,50 @@ public abstract class AlertingNotificationManager {
         * Clear any pending removal runnables.
         */
        public void removeAutoRemovalCallbacks(@Nullable String reason) {
            if (mRemoveAlertRunnable != null) {
            final boolean removed = removeAutoRemovalCallbackInternal();

            if (removed) {
                mLogger.logAutoRemoveCanceled(mEntry, reason);
                mHandler.removeCallbacks(mRemoveAlertRunnable);
            }
        }

        private void scheduleAutoRemovalCallback(long delayMillis, @NonNull String reason) {
            if (mRemoveAlertRunnable == null) {
                Log.wtf(TAG, "scheduleAutoRemovalCallback with no callback set");
                return;
            }

            final boolean removed = removeAutoRemovalCallbackInternal();

            if (removed) {
                mLogger.logAutoRemoveRescheduled(mEntry, delayMillis, reason);
            } else {
                mLogger.logAutoRemoveScheduled(mEntry, delayMillis, reason);
            }


            mCancelRemoveAlertRunnable = mExecutor.executeDelayed(mRemoveAlertRunnable,
                    delayMillis);
        }

        private boolean removeAutoRemovalCallbackInternal() {
            final boolean scheduled = (mCancelRemoveAlertRunnable != null);

            if (scheduled) {
                mCancelRemoveAlertRunnable.run();
                mCancelRemoveAlertRunnable = null;
            }

            return scheduled;
        }

        /**
         * Remove the alert at the earliest allowed removal time.
         */
        public void removeAsSoonAsPossible() {
            if (mRemoveAlertRunnable != null) {
                removeAutoRemovalCallbacks("removeAsSoonAsPossible (will be rescheduled)");

                final long timeLeft = mEarliestRemovalTime - mSystemClock.elapsedRealtime();
                mHandler.postDelayed(mRemoveAlertRunnable, timeLeft);
                scheduleAutoRemovalCallback(timeLeft, "removeAsSoonAsPossible");
            }
        }

+4 −2
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.kotlin.JavaAdapter;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;
@@ -119,12 +120,13 @@ public class HeadsUpManagerPhone extends BaseHeadsUpManager implements OnHeadsUp
            @Main Handler handler,
            GlobalSettings globalSettings,
            SystemClock systemClock,
            @Main DelayableExecutor executor,
            AccessibilityManagerWrapper accessibilityManagerWrapper,
            UiEventLogger uiEventLogger,
            JavaAdapter javaAdapter,
            ShadeInteractor shadeInteractor) {
        super(context, logger, handler, globalSettings, systemClock, accessibilityManagerWrapper,
                uiEventLogger);
        super(context, logger, handler, globalSettings, systemClock, executor,
                accessibilityManagerWrapper, uiEventLogger);
        Resources resources = mContext.getResources();
        mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
        statusBarStateController.addCallback(mStatusBarStateListener);
+3 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.time.SystemClock;

@@ -87,9 +88,10 @@ public abstract class BaseHeadsUpManager extends AlertingNotificationManager imp
            @Main Handler handler,
            GlobalSettings globalSettings,
            SystemClock systemClock,
            @Main DelayableExecutor executor,
            AccessibilityManagerWrapper accessibilityManagerWrapper,
            UiEventLogger uiEventLogger) {
        super(logger, handler, systemClock);
        super(logger, systemClock, executor);
        mContext = context;
        mAccessibilityMgr = accessibilityManagerWrapper;
        mUiEventLogger = uiEventLogger;
+20 −0
Original line number Diff line number Diff line
@@ -66,6 +66,26 @@ class HeadsUpManagerLogger @Inject constructor(
        })
    }

    fun logAutoRemoveScheduled(entry: NotificationEntry, delayMillis: Long, reason: String) {
        buffer.log(TAG, INFO, {
            str1 = entry.logKey
            long1 = delayMillis
            str2 = reason
        }, {
            "schedule auto remove of $str1 in $long1 ms reason: $str2"
        })
    }

    fun logAutoRemoveRescheduled(entry: NotificationEntry, delayMillis: Long, reason: String) {
        buffer.log(TAG, INFO, {
            str1 = entry.logKey
            long1 = delayMillis
            str2 = reason
        }, {
            "reschedule auto remove of $str1 in $long1 ms reason: $str2"
        })
    }

    fun logAutoRemoveCanceled(entry: NotificationEntry, reason: String?) {
        buffer.log(TAG, INFO, {
            str1 = entry.logKey
+14 −54
Original line number Diff line number Diff line
@@ -30,8 +30,6 @@ import static org.mockito.Mockito.spy;

import android.app.ActivityManager;
import android.app.Notification;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -45,12 +43,12 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.FakeGlobalSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.util.time.SystemClockImpl;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,27 +71,24 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
    protected static final int TEST_STICKY_AUTO_DISMISS_TIME = 800;
    // Number of notifications to use in tests requiring multiple notifications
    private static final int TEST_NUM_NOTIFICATIONS = 4;
    protected static final int TEST_TIMEOUT_TIME = 2_000;
    protected final Runnable mTestTimeoutRunnable = () -> mTimedOut = true;

    protected Handler mTestHandler;
    protected final FakeGlobalSettings mGlobalSettings = new FakeGlobalSettings();
    protected final SystemClock mSystemClock = new SystemClockImpl();
    protected boolean mTimedOut = false;
    protected final FakeSystemClock mSystemClock = new FakeSystemClock();
    protected final FakeExecutor mExecutor = new FakeExecutor(mSystemClock);

    @Mock protected ExpandableNotificationRow mRow;

    static {
        assertThat(TEST_MINIMUM_DISPLAY_TIME).isLessThan(TEST_AUTO_DISMISS_TIME);
        assertThat(TEST_AUTO_DISMISS_TIME).isLessThan(TEST_STICKY_AUTO_DISMISS_TIME);
        assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_TIMEOUT_TIME);
    }

    private static class TestableAlertingNotificationManager extends AlertingNotificationManager {
        private AlertEntry mLastCreatedEntry;

        private TestableAlertingNotificationManager(Handler handler, SystemClock systemClock) {
            super(new HeadsUpManagerLogger(logcatLogBuffer()), handler, systemClock);
        private TestableAlertingNotificationManager(SystemClock systemClock,
                DelayableExecutor executor) {
            super(new HeadsUpManagerLogger(logcatLogBuffer()), systemClock, executor);
            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
            mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
            mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
@@ -118,7 +113,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
    }

    protected AlertingNotificationManager createAlertingNotificationManager() {
        return new TestableAlertingNotificationManager(mTestHandler, mSystemClock);
        return new TestableAlertingNotificationManager(mSystemClock, mExecutor);
    }

    protected StatusBarNotification createSbn(int id, Notification n) {
@@ -155,35 +150,6 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
        return new NotificationEntryBuilder().setSbn(createSbn(id)).build();
    }

    protected void verifyAlertingAtTime(AlertingNotificationManager anm, NotificationEntry entry,
            boolean shouldBeAlerting, int whenToCheckAlertingMillis, String whenCondition) {
        final Boolean[] wasAlerting = {null};
        final Runnable checkAlerting =
                () -> wasAlerting[0] = anm.isAlerting(entry.getKey());

        mTestHandler.postDelayed(checkAlerting, whenToCheckAlertingMillis);
        mTestHandler.postDelayed(mTestTimeoutRunnable, TEST_TIMEOUT_TIME);
        TestableLooper.get(this).processMessages(2);

        assertFalse("Test timed out", mTimedOut);
        if (shouldBeAlerting) {
            assertTrue("Should still be alerting after " + whenCondition, wasAlerting[0]);
        } else {
            assertFalse("Should not still be alerting after " + whenCondition, wasAlerting[0]);
        }
        assertFalse("Should not still be alerting after processing",
                anm.isAlerting(entry.getKey()));
    }

    @Before
    public void setUp() {
        mTestHandler = Handler.createAsync(Looper.myLooper());
    }

    @After
    public void tearDown() {
        mTestHandler.removeCallbacksAndMessages(null);
    }

    @Test
    public void testShowNotification_addsEntry() {
@@ -203,9 +169,7 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {
        final NotificationEntry entry = createEntry(/* id = */ 0);

        alm.showNotification(entry);

        verifyAlertingAtTime(alm, entry, false, TEST_AUTO_DISMISS_TIME * 3 / 2,
                "auto dismiss time");
        mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2);

        assertFalse(alm.isAlerting(entry.getKey()));
    }
@@ -217,10 +181,8 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {

        alm.showNotification(entry);

        // Try to remove but defer, since the notification has not been shown long enough.
        final boolean removedImmediately = alm.removeNotification(entry.getKey(),
                false /* releaseImmediately */);

        final boolean removedImmediately = alm.removeNotification(
                entry.getKey(), /* releaseImmediately = */ false);
        assertFalse(removedImmediately);
        assertTrue(alm.isAlerting(entry.getKey()));
    }
@@ -232,10 +194,8 @@ public class AlertingNotificationManagerTest extends SysuiTestCase {

        alm.showNotification(entry);

        // Remove forcibly with releaseImmediately = true.
        final boolean removedImmediately = alm.removeNotification(entry.getKey(),
                true /* releaseImmediately */);

        final boolean removedImmediately = alm.removeNotification(
                entry.getKey(), /* releaseImmediately = */ true);
        assertTrue(removedImmediately);
        assertFalse(alm.isAlerting(entry.getKey()));
    }
Loading