From a97c612f42774f1580e1dbb016864ed41fd1537c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20Kurucz?= Date: Tue, 19 Jul 2022 13:23:44 +0000 Subject: [PATCH] make IStatusBarService:onNotificationClear calls async Blocking binder calls to IStatusBarService:onNotificationClear during important system transitions were causing user-visible jank in traces collected from real user devices. Test: atest NotificationEntryManagerTest Test: atest NotifCollectionTest Test: atest NotificationEntryManagerInflationTest Test: atest LaunchConversationActivityTest Bug: 230668198 Change-Id: I737a5d85049e5e016fd2f4ad37285001752f5f95 --- .../widget/LaunchConversationActivity.java | 62 ++++++++------ .../NotificationEntryManager.java | 31 ++++--- .../collection/NotifCollection.java | 31 ++++--- .../dagger/NotificationsModule.java | 6 +- .../LaunchConversationActivityTest.java | 9 +- .../NotificationEntryManagerTest.java | 83 ++++++++++++++----- .../collection/NotifCollectionTest.java | 9 ++ ...NotificationEntryManagerInflationTest.java | 3 +- 8 files changed, 160 insertions(+), 74 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java index e1b97a454c5d7..20c6c556706ec 100644 --- a/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java +++ b/packages/SystemUI/src/com/android/systemui/people/widget/LaunchConversationActivity.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; import android.os.Bundle; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; @@ -34,6 +35,7 @@ import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.people.PeopleSpaceUtils; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -43,6 +45,7 @@ import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubble; import java.util.Optional; +import java.util.concurrent.Executor; import javax.inject.Inject; @@ -58,6 +61,7 @@ public class LaunchConversationActivity extends Activity { private boolean mIsForTesting; private IStatusBarService mIStatusBarService; private CommandQueue mCommandQueue; + private Executor mBgExecutor; private Bubble mBubble; private NotificationEntry mEntryToBubble; @@ -67,7 +71,8 @@ public class LaunchConversationActivity extends Activity { CommonNotifCollection commonNotifCollection, Optional bubblesManagerOptional, UserManager userManager, - CommandQueue commandQueue + CommandQueue commandQueue, + @Background Executor bgExecutor ) { super(); mVisibilityProvider = visibilityProvider; @@ -91,6 +96,7 @@ public class LaunchConversationActivity extends Activity { mCommandQueue.removeCallback(this); } }); + mBgExecutor = bgExecutor; } @Override @@ -172,34 +178,36 @@ public class LaunchConversationActivity extends Activity { return; } - try { - if (mIStatusBarService == null || mCommonNotifCollection == null) { - if (DEBUG) { - Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey); - } - return; + if (mIStatusBarService == null || mCommonNotifCollection == null) { + if (DEBUG) { + Log.d(TAG, "Skipping clear notification: null services, key: " + notifKey); } - - NotificationEntry entry = mCommonNotifCollection.getEntry(notifKey); - if (entry == null || entry.getRanking() == null) { - if (DEBUG) { - Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking" - + " is null, key: " + notifKey); - } - return; - } - - NotificationVisibility notifVisibility = mVisibilityProvider.obtain(entry, true); - int rank = notifVisibility.rank; - - if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank); - mIStatusBarService.onNotificationClear( - packageName, userHandle.getIdentifier(), notifKey, - NotificationStats.DISMISSAL_OTHER, - NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility); - } catch (Exception e) { - Log.e(TAG, "Exception cancelling notification:" + e); + return; } + + NotificationEntry entry = mCommonNotifCollection.getEntry(notifKey); + if (entry == null || entry.getRanking() == null) { + if (DEBUG) { + Log.d(TAG, "Skipping clear notification: NotificationEntry or its Ranking" + + " is null, key: " + notifKey); + } + return; + } + + NotificationVisibility notifVisibility = mVisibilityProvider.obtain(entry, true); + int rank = notifVisibility.rank; + + if (DEBUG) Log.d(TAG, "Clearing notification, key: " + notifKey + ", rank: " + rank); + mBgExecutor.execute(() -> { + try { + mIStatusBarService.onNotificationClear( + packageName, userHandle.getIdentifier(), notifKey, + NotificationStats.DISMISSAL_OTHER, + NotificationStats.DISMISS_SENTIMENT_POSITIVE, notifVisibility); + } catch (RemoteException e) { + Log.e(TAG, "Exception cancelling notification:" + e); + } + }); } @VisibleForTesting diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index c86bf93628dd4..852d5f7a16e6f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -41,6 +41,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.systemui.Dumpable; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dump.DumpManager; import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationListener; @@ -73,6 +74,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import dagger.Lazy; @@ -113,6 +115,7 @@ public class NotificationEntryManager implements private final IStatusBarService mStatusBarService; private final NotifLiveDataStoreImpl mNotifLiveDataStore; private final DumpManager mDumpManager; + private final Executor mBgExecutor; private final Set mAllNotifications = new ArraySet<>(); private final Set mReadOnlyAllNotifications = @@ -159,7 +162,8 @@ public class NotificationEntryManager implements LeakDetector leakDetector, IStatusBarService statusBarService, NotifLiveDataStoreImpl notifLiveDataStore, - DumpManager dumpManager + DumpManager dumpManager, + @Background Executor bgExecutor ) { mLogger = logger; mGroupManager = groupManager; @@ -170,6 +174,7 @@ public class NotificationEntryManager implements mStatusBarService = statusBarService; mNotifLiveDataStore = notifLiveDataStore; mDumpManager = dumpManager; + mBgExecutor = bgExecutor; } /** Once called, the NEM will start processing notification events from system server. */ @@ -566,17 +571,19 @@ public class NotificationEntryManager implements private void sendNotificationRemovalToServer( StatusBarNotification notification, DismissedByUserStats dismissedByUserStats) { - try { - mStatusBarService.onNotificationClear( - notification.getPackageName(), - notification.getUser().getIdentifier(), - notification.getKey(), - dismissedByUserStats.dismissalSurface, - dismissedByUserStats.dismissalSentiment, - dismissedByUserStats.notificationVisibility); - } catch (RemoteException ex) { - // system process is dead if we're here. - } + mBgExecutor.execute(() -> { + try { + mStatusBarService.onNotificationClear( + notification.getPackageName(), + notification.getUser().getIdentifier(), + notification.getKey(), + dismissedByUserStats.dismissalSurface, + dismissedByUserStats.dismissalSentiment, + dismissedByUserStats.notificationVisibility); + } catch (RemoteException ex) { + // system process is dead if we're here. + } + }); } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java index 2c85fddc2905f..351a4bea2947d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java @@ -70,6 +70,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.dump.LogBufferEulogizer; @@ -112,6 +113,7 @@ import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.Set; +import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import javax.inject.Inject; @@ -146,6 +148,7 @@ public class NotifCollection implements Dumpable { private final NotifPipelineFlags mNotifPipelineFlags; private final NotifCollectionLogger mLogger; private final Handler mMainHandler; + private final Executor mBgExecutor; private final LogBufferEulogizer mEulogizer; private final DumpManager mDumpManager; @@ -174,6 +177,7 @@ public class NotifCollection implements Dumpable { NotifPipelineFlags notifPipelineFlags, NotifCollectionLogger logger, @Main Handler mainHandler, + @Background Executor bgExecutor, LogBufferEulogizer logBufferEulogizer, DumpManager dumpManager) { mStatusBarService = statusBarService; @@ -181,6 +185,7 @@ public class NotifCollection implements Dumpable { mNotifPipelineFlags = notifPipelineFlags; mLogger = logger; mMainHandler = mainHandler; + mBgExecutor = bgExecutor; mEulogizer = logBufferEulogizer; mDumpManager = dumpManager; } @@ -294,18 +299,20 @@ public class NotifCollection implements Dumpable { entriesToLocallyDismiss.add(entry); if (!isCanceled(entry)) { // send message to system server if this notification hasn't already been cancelled - try { - mStatusBarService.onNotificationClear( - entry.getSbn().getPackageName(), - entry.getSbn().getUser().getIdentifier(), - entry.getSbn().getKey(), - stats.dismissalSurface, - stats.dismissalSentiment, - stats.notificationVisibility); - } catch (RemoteException e) { - // system process is dead if we're here. - mLogger.logRemoteExceptionOnNotificationClear(entry, e); - } + mBgExecutor.execute(() -> { + try { + mStatusBarService.onNotificationClear( + entry.getSbn().getPackageName(), + entry.getSbn().getUser().getIdentifier(), + entry.getSbn().getKey(), + stats.dismissalSurface, + stats.dismissalSentiment, + stats.notificationVisibility); + } catch (RemoteException e) { + // system process is dead if we're here. + mLogger.logRemoteExceptionOnNotificationClear(entry, e); + } + }); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 4956a27698bcd..bf08fc7f53e28 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -128,7 +128,8 @@ public interface NotificationsModule { LeakDetector leakDetector, IStatusBarService statusBarService, NotifLiveDataStoreImpl notifLiveDataStore, - DumpManager dumpManager) { + DumpManager dumpManager, + @Background Executor bgExecutor) { return new NotificationEntryManager( logger, groupManager, @@ -138,7 +139,8 @@ public interface NotificationsModule { leakDetector, statusBarService, notifLiveDataStore, - dumpManager); + dumpManager, + bgExecutor); } /** Provides an instance of {@link NotificationGutsManager} */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java index 99f21ad4d5087..c8ebd1240149c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/LaunchConversationActivityTest.java @@ -48,6 +48,8 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import com.android.systemui.wmshell.BubblesManager; import com.android.wm.shell.bubbles.Bubble; @@ -106,6 +108,9 @@ public class LaunchConversationActivityTest extends SysuiTestCase { private Intent mIntent; + private FakeSystemClock mFakeSystemClock = new FakeSystemClock(); + private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock); + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -114,7 +119,8 @@ public class LaunchConversationActivityTest extends SysuiTestCase { mNotifCollection, Optional.of(mBubblesManager), mUserManager, - mCommandQueue + mCommandQueue, + mBgExecutor ); verify(mCommandQueue, times(1)).addCallback(mCallbacksCaptor.capture()); @@ -193,6 +199,7 @@ public class LaunchConversationActivityTest extends SysuiTestCase { // Ensure callback removed verify(mCommandQueue).removeCallback(any()); // Clear the notification for bubbles. + FakeExecutor.exhaustExecutors(mBgExecutor); verify(mIStatusBarService, times(1)).onNotificationClear(any(), anyInt(), any(), anyInt(), anyInt(), mNotificationVisibilityCaptor.capture()); // Do not select the bubble. diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index 16b0376ba1f9b..aeef6b04108e4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED; import static android.service.notification.NotificationListenerService.REASON_CANCEL; +import static android.service.notification.NotificationStats.DISMISSAL_SHADE; +import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL; import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON; @@ -41,6 +43,7 @@ import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.app.ActivityManager; @@ -50,6 +53,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.graphics.drawable.Icon; import android.os.Handler; +import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; @@ -91,7 +95,9 @@ import com.android.systemui.statusbar.notification.row.NotificationEntryManagerI import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.leak.LeakDetector; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; import org.junit.Test; @@ -138,9 +144,14 @@ public class NotificationEntryManagerTest extends SysuiTestCase { @Mock private NotificationMediaManager mNotificationMediaManager; @Mock private NotificationRowBinder mNotificationRowBinder; @Mock private NotificationListener mNotificationListener; + @Mock private IStatusBarService mStatusBarService; + + private FakeSystemClock mFakeSystemClock = new FakeSystemClock(); + private FakeExecutor mBgExecutor = new FakeExecutor(mFakeSystemClock); private int mId; private NotificationEntry mEntry; + private DismissedByUserStats mStats; private StatusBarNotification mSbn; private NotificationEntryManager mEntryManager; @@ -191,6 +202,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase { Handler.createAsync(TestableLooper.get(this).getLooper())); mEntry = createNotification(); + mStats = defaultStats(mEntry); mSbn = mEntry.getSbn(); when(mNotifPipelineFlags.isNewPipelineEnabled()).thenReturn(false); @@ -201,9 +213,10 @@ public class NotificationEntryManagerTest extends SysuiTestCase { () -> mNotificationRowBinder, () -> mRemoteInputManager, mLeakDetector, - mock(IStatusBarService.class), + mStatusBarService, NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(), - mock(DumpManager.class) + mock(DumpManager.class), + mBgExecutor ); mEntryManager.initialize( mNotificationListener, @@ -315,6 +328,31 @@ public class NotificationEntryManagerTest extends SysuiTestCase { assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey())); } + @Test + public void testPerformRemoveNotification_sendRemovalToServer() throws RemoteException { + // GIVEN an entry manager with a notification + mEntryManager.addActiveNotificationForTest(mEntry); + + // GIVEN interceptor that doesn't intercept + when(mRemoveInterceptor.onNotificationRemoveRequested( + eq(mEntry.getKey()), argThat(matchEntryOnKey()), anyInt())) + .thenReturn(false); + + // WHEN the notification entry is removed + mEntryManager.performRemoveNotification(mSbn, mStats, REASON_CANCEL); + + // THEN notification removal is sent to the server + FakeExecutor.exhaustExecutors(mBgExecutor); + verify(mStatusBarService).onNotificationClear( + mSbn.getPackageName(), + mSbn.getUser().getIdentifier(), + mSbn.getKey(), + mStats.dismissalSurface, + mStats.dismissalSentiment, + mStats.notificationVisibility); + verifyNoMoreInteractions(mStatusBarService); + } + @Test public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() { @@ -573,23 +611,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase { any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON)); } - private NotificationEntry createNotification() { - Notification.Builder n = new Notification.Builder(mContext, "id") - .setSmallIcon(R.drawable.ic_person) - .setContentTitle("Title") - .setContentText("Text"); - - return new NotificationEntryBuilder() - .setPkg(TEST_PACKAGE_NAME) - .setOpPkg(TEST_PACKAGE_NAME) - .setUid(TEST_UID) - .setId(mId++) - .setNotification(n.build()) - .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT)) - .setUser(new UserHandle(ActivityManager.getCurrentUser())) - .build(); - } - /* Tests annexed from NotificationDataTest go here */ @Test @@ -713,4 +734,28 @@ public class NotificationEntryManagerTest extends SysuiTestCase { return mManagedNotifs.contains(notificationKey); } } + + private NotificationEntry createNotification() { + Notification.Builder n = new Notification.Builder(mContext, "id") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + + return new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_NAME) + .setOpPkg(TEST_PACKAGE_NAME) + .setUid(TEST_UID) + .setId(mId++) + .setNotification(n.build()) + .setChannel(new NotificationChannel("id", "", IMPORTANCE_DEFAULT)) + .setUser(new UserHandle(ActivityManager.getCurrentUser())) + .build(); + } + + private static DismissedByUserStats defaultStats(NotificationEntry entry) { + return new DismissedByUserStats( + DISMISSAL_SHADE, + DISMISS_SENTIMENT_NEUTRAL, + NotificationVisibility.obtain(entry.getKey(), 7, 2, true)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java index ef763d9f8b307..4df99be9efd15 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java @@ -92,6 +92,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionLogger; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; +import com.android.systemui.util.concurrency.FakeExecutor; import com.android.systemui.util.time.FakeSystemClock; import org.junit.Before; @@ -146,6 +147,7 @@ public class NotifCollectionTest extends SysuiTestCase { private NoManSimulator mNoMan; private FakeSystemClock mClock = new FakeSystemClock(); + private FakeExecutor mBgExecutor = new FakeExecutor(mClock); @Before public void setUp() { @@ -162,6 +164,7 @@ public class NotifCollectionTest extends SysuiTestCase { mNotifPipelineFlags, mLogger, mMainHandler, + mBgExecutor, mEulogizer, mock(DumpManager.class)); mCollection.attach(mGroupCoalescer); @@ -461,6 +464,8 @@ public class NotifCollectionTest extends SysuiTestCase { DismissedByUserStats stats = defaultStats(entry2); mCollection.dismissNotification(entry2, defaultStats(entry2)); + FakeExecutor.exhaustExecutors(mBgExecutor); + // THEN we send the dismissal to system server verify(mStatusBarService).onNotificationClear( notif2.sbn.getPackageName(), @@ -674,6 +679,8 @@ public class NotifCollectionTest extends SysuiTestCase { mInterceptor1.onEndInterceptionCallback.onEndDismissInterception(mInterceptor1, entry, stats); + FakeExecutor.exhaustExecutors(mBgExecutor); + // THEN we send the dismissal to system server verify(mStatusBarService).onNotificationClear( eq(notif.sbn.getPackageName()), @@ -1211,6 +1218,7 @@ public class NotifCollectionTest extends SysuiTestCase { new Pair<>(entry2, defaultStats(entry2)))); // THEN we send the dismissals to system server + FakeExecutor.exhaustExecutors(mBgExecutor); verify(mStatusBarService).onNotificationClear( notif1.sbn.getPackageName(), notif1.sbn.getUser().getIdentifier(), @@ -1577,6 +1585,7 @@ public class NotifCollectionTest extends SysuiTestCase { // WHEN finally dismissing onDismiss.run(); + FakeExecutor.exhaustExecutors(mBgExecutor); verify(mStatusBarService).onNotificationClear(any(), anyInt(), eq(notifEvent.key), anyInt(), anyInt(), any()); verifyNoMoreInteractions(mStatusBarService); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index 251ac7d250fe1..bf7549a237079 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -194,7 +194,8 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { mLeakDetector, mock(IStatusBarService.class), NotifLiveDataStoreMocksKt.createNotifLiveDataStoreImplMock(), - mock(DumpManager.class) + mock(DumpManager.class), + mBgExecutor ); mEntryManager.initialize( mNotificationListener,