diff options
| author | Jan Tomljanovic <jtomljanovic@google.com> | 2020-11-06 11:28:09 +0000 |
|---|---|---|
| committer | Jan Tomljanovic <jtomljanovic@google.com> | 2020-11-10 14:27:08 +0000 |
| commit | ea90e9501b7925338f3e61fa8ea1b5d0902a53bb (patch) | |
| tree | 6beb5ed95e9d4bc684c28b969f548e7fbd7886c3 | |
| parent | 85b41414abedcddf94fb0afa3a57f83bbecd2a33 (diff) | |
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
2 files changed, 66 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 1516cded50a6..1e2898b91a27 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -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 */, diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 87aaba2b164a..70d3f988f1f7 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -4923,6 +4923,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @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"; assertEquals(0, mService.mToastQueue.size()); @@ -4959,6 +4985,33 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @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 { final String testPackage = "testPackageName"; |
