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

Commit ea90e950 authored by Jan Tomljanovic's avatar Jan Tomljanovic
Browse files

Don't try to show the current toast again while it's showing.

By doing this we avoid a few bad things:
 - mechanism that hides the current toast by trying to show it again
 - delaying the call to hide and remove the current toast from the queue
   when it's duration expires (which in the case of repeated calls can
   delay this indefinitely)

Test: atest NotificationManagerServiceTest
Test: atest android.widget.cts.ToastTest
Bug: 167672740
Change-Id: Ie4953109314113efae49fa0c5e0c236e6e0dbb23
parent 85b41414
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -494,6 +494,10 @@ public class NotificationManagerService extends SystemService {
    final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
    final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();

    // True if the toast that's on top of the queue is being shown at the moment.
    @GuardedBy("mToastQueue")
    private boolean mIsCurrentToastShown = false;

    // The last key in this list owns the hardware.
    ArrayList<String> mLights = new ArrayList<>();

@@ -7297,10 +7301,15 @@ public class NotificationManagerService extends SystemService {

    @GuardedBy("mToastQueue")
    void showNextToastLocked() {
        if (mIsCurrentToastShown) {
            return; // Don't show the same toast twice.
        }

        ToastRecord record = mToastQueue.get(0);
        while (record != null) {
            if (record.show()) {
                scheduleDurationReachedLocked(record);
                mIsCurrentToastShown = true;
                return;
            }
            int index = mToastQueue.indexOf(record);
@@ -7316,6 +7325,10 @@ public class NotificationManagerService extends SystemService {
        ToastRecord record = mToastQueue.get(index);
        record.hide();

        if (index == 0) {
            mIsCurrentToastShown = false;
        }

        ToastRecord lastToast = mToastQueue.remove(index);

        mWindowManagerInternal.removeWindowToken(lastToast.windowToken, false /* removeWindows */,
+53 −0
Original line number Diff line number Diff line
@@ -4922,6 +4922,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(0, mService.mToastQueue.size());
    }

    @Test
    public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception {
        final String testPackage = "testPackageName";
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
                .thenReturn(false);

        setAppInForegroundForToasts(mUid, true);

        Binder token = new Binder();
        ITransientNotification callback = mock(ITransientNotification.class);
        INotificationManager nmService = (INotificationManager) mService.mService;

        // first time trying to show the toast, showToast gets called
        nmService.enqueueToast(testPackage, token, callback, 2000, 0);
        verify(callback, times(1)).show(any());

        // second time trying to show the same toast, showToast isn't called again (total number of
        // invocations stays at one)
        nmService.enqueueToast(testPackage, token, callback, 2000, 0);
        verify(callback, times(1)).show(any());
    }

    @Test
    public void testAllowForegroundTextToasts() throws Exception {
        final String testPackage = "testPackageName";
@@ -4958,6 +4984,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        assertEquals(1, mService.mToastQueue.size());
    }

    @Test
    public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception {
        final String testPackage = "testPackageName";
        assertEquals(0, mService.mToastQueue.size());
        mService.isSystemUid = false;

        // package is not suspended
        when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
                .thenReturn(false);

        setAppInForegroundForToasts(mUid, true);

        Binder token = new Binder();
        INotificationManager nmService = (INotificationManager) mService.mService;

        // first time trying to show the toast, showToast gets called
        nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
        verify(mStatusBar, times(1))
                .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());

        // second time trying to show the same toast, showToast isn't called again (total number of
        // invocations stays at one)
        nmService.enqueueTextToast(testPackage, token, "Text", 2000, 0, null);
        verify(mStatusBar, times(1))
                .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
    }

    @Test
    public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws
            Exception {