diff options
8 files changed, 229 insertions, 59 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index e84c64838fd6..3aa9f73939ac 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -293,6 +293,17 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe } /** + * Request the stack expand if needed, then select the specified Bubble as current. + * + * @param notificationKey the notification key for the bubble to be selected + */ + public void expandStackAndSelectBubble(String notificationKey) { + if (mStackView != null && mBubbleData.getBubble(notificationKey) != null) { + mStackView.setExpandedBubble(notificationKey); + } + } + + /** * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack. */ void dismissStack(@DismissReason int reason) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java index b788f537316b..fd2f72062be7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -78,8 +78,7 @@ public final class NotificationClicker implements View.OnClickListener { row.setJustClicked(true); DejankUtils.postAfterTraversal(() -> row.setJustClicked(false)); - // If it was a bubble we should close it - if (row.getEntry().isBubble()) { + if (!row.getEntry().isBubble()) { mBubbleController.collapseStack(); } @@ -95,7 +94,8 @@ public final class NotificationClicker implements View.OnClickListener { */ public void register(ExpandableNotificationRow row, StatusBarNotification sbn) { Notification notification = sbn.getNotification(); - if (notification.contentIntent != null || notification.fullScreenIntent != null) { + if (notification.contentIntent != null || notification.fullScreenIntent != null + || row.getEntry().isBubble()) { row.setOnClickListener(this); } else { row.setOnClickListener(null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java index b91cdaf9ae80..d3e5af8c729e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java @@ -220,8 +220,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { StatusBarNotification sbn, ExpandableNotificationRow row) { row.setIsLowPriority(entry.ambient); - // bind the click event to the content area - checkNotNull(mNotificationClicker).register(row, sbn); // Extract target SDK version. try { @@ -257,6 +255,9 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { row.setNeedsRedaction( Dependency.get(NotificationLockscreenUserManager.class).needsRedaction(entry)); row.inflateViews(); + + // bind the click event to the content area + checkNotNull(mNotificationClicker).register(row, sbn); } private void logNotificationExpansion(String key, boolean userAction, boolean expanded) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index db91d0160391..7e0623250c31 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -25,6 +25,7 @@ import static android.app.StatusBarManager.WindowVisibleState; import static android.app.StatusBarManager.windowStateToString; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; +import static com.android.systemui.Dependency.BG_HANDLER; import static com.android.systemui.Dependency.MAIN_HANDLER; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; @@ -1076,7 +1077,7 @@ public class StatusBar extends SystemUI implements DemoMode, mLockscreenUserManager, shadeController, mKeyguardMonitor, mNotificationInterruptionStateProvider, mMetricsLogger, new LockPatternUtils(mContext), Dependency.get(MAIN_HANDLER), - mActivityIntentHelper); + Dependency.get(BG_HANDLER), mActivityIntentHelper, mBubbleController); mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 215f5c4dfc5b..e4af15cf7dd1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -48,6 +48,7 @@ import com.android.systemui.Dependency; import com.android.systemui.EventLogTags; import com.android.systemui.UiOffloadThread; import com.android.systemui.assist.AssistManager; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -98,7 +99,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final CommandQueue mCommandQueue; private final IDreamManager mDreamManager; private final Handler mMainThreadHandler; + private final Handler mBackgroundHandler; private final ActivityIntentHelper mActivityIntentHelper; + private final BubbleController mBubbleController; private boolean mIsCollapsingToShowActivityOverLockscreen; @@ -125,7 +128,9 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils, Handler mainThreadHandler, - ActivityIntentHelper activityIntentHelper) { + Handler backgroundHandler, + ActivityIntentHelper activityIntentHelper, + BubbleController bubbleController) { mContext = context; mNotificationPanel = panel; mPresenter = presenter; @@ -147,6 +152,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mAssistManager = assistManager; mGroupManager = groupManager; mLockPatternUtils = lockPatternUtils; + mBackgroundHandler = backgroundHandler; mEntryManager.addNotificationEntryListener(new NotificationEntryListener() { @Override public void onPendingEntryAdded(NotificationEntry entry) { @@ -156,6 +162,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mStatusBarRemoteInputCallback = remoteInputCallback; mMainThreadHandler = mainThreadHandler; mActivityIntentHelper = activityIntentHelper; + mBubbleController = bubbleController; } /** @@ -178,14 +185,24 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit final PendingIntent intent = notification.contentIntent != null ? notification.contentIntent : notification.fullScreenIntent; + final boolean isBubble = row.getEntry().isBubble(); + + // This code path is now executed for notification without a contentIntent. + // The only valid case is Bubble notifications. Guard against other cases + // entering here. + if (intent == null && !isBubble) { + Log.e(TAG, "onNotificationClicked called for non-clickable notification!"); + return; + } + final String notificationKey = sbn.getKey(); - boolean isActivityIntent = intent.isActivity(); + boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble; final boolean afterKeyguardGone = isActivityIntent && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); final boolean wasOccluded = mShadeController.isOccluded(); - boolean showOverLockscreen = mKeyguardMonitor.isShowing() + boolean showOverLockscreen = mKeyguardMonitor.isShowing() && intent != null && mActivityIntentHelper.wouldShowOverLockscreen(intent.getIntent(), mLockscreenUserManager.getCurrentUserId()); ActivityStarter.OnDismissAction postKeyguardAction = @@ -244,9 +261,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController.addAfterKeyguardGoneRunnable(runnable); mShadeController.collapsePanel(); } else { - new Thread(runnable).start(); + mBackgroundHandler.postAtFrontOfQueue(runnable); } - return !mNotificationPanel.isFullyCollapsed(); } @@ -287,6 +303,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } Intent fillInIntent = null; NotificationEntry entry = row.getEntry(); + final boolean isBubble = entry.isBubble(); CharSequence remoteInputText = null; if (!TextUtils.isEmpty(entry.remoteInputText)) { remoteInputText = entry.remoteInputText; @@ -295,8 +312,12 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT, remoteInputText.toString()); } - startNotificationIntent(intent, fillInIntent, row, wasOccluded, isActivityIntent); - if (isActivityIntent) { + if (isBubble) { + expandBubbleStackOnMainThread(notificationKey); + } else { + startNotificationIntent(intent, fillInIntent, row, wasOccluded, isActivityIntent); + } + if (isActivityIntent || isBubble) { mAssistManager.hideAssist(); } if (shouldCollapse()) { @@ -316,18 +337,29 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } catch (RemoteException ex) { // system process is dead if we're here. } - if (parentToCancelFinal != null) { - removeNotification(parentToCancelFinal); - } - if (shouldAutoCancel(sbn) - || mRemoteInputManager.isNotificationKeptForRemoteInputHistory( - notificationKey)) { - // Automatically remove all notifications that we may have kept around longer - removeNotification(sbn); + if (!isBubble) { + if (parentToCancelFinal != null) { + removeNotification(parentToCancelFinal); + } + if (shouldAutoCancel(sbn) + || mRemoteInputManager.isNotificationKeptForRemoteInputHistory( + notificationKey)) { + // Automatically remove all notifications that we may have kept around longer + removeNotification(sbn); + } } mIsCollapsingToShowActivityOverLockscreen = false; } + private void expandBubbleStackOnMainThread(String notificationKey) { + if (Looper.getMainLooper().isCurrentThread()) { + mBubbleController.expandStackAndSelectBubble(notificationKey); + } else { + mMainThreadHandler.post( + () -> mBubbleController.expandStackAndSelectBubble(notificationKey)); + } + } + private void startNotificationIntent(PendingIntent intent, Intent fillInIntent, ExpandableNotificationRow row, boolean wasOccluded, boolean isActivityIntent) { RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(row, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 14bc71b6a142..9fa85d307d2a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -438,6 +438,22 @@ public class BubbleControllerTest extends SysuiTestCase { } @Test + public void testExpandStackAndSelectBubble_removedFirst() { + final String key = mRow.getEntry().key; + + mEntryListener.onPendingEntryAdded(mRow.getEntry()); + mBubbleController.updateBubble(mRow.getEntry(), true /* updatePosition */); + + assertTrue(mRow.getEntry().isBubble()); + + // Simulate notification cancellation. + mEntryListener.onEntryRemoved(mRow.getEntry(), null /* notificationVisibility (unused) */, + false /* removedbyUser */); + + mBubbleController.expandStackAndSelectBubble(key); + } + + @Test public void testMarkNewNotificationAsBubble() { mEntryListener.onPendingEntryAdded(mRow.getEntry()); assertTrue(mRow.getEntry().isBubble()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index 5ea4636149a2..7e089a653b9e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -151,6 +151,16 @@ public class NotificationTestHelper { /** * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble. + */ + public ExpandableNotificationRow createBubble() + throws Exception { + Notification n = createNotification(false /* isGroupSummary */, + null /* groupKey */, makeBubbleMetadata(null)); + return generateRow(n, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH); + } + + /** + * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble. * * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent} */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 20af1ac5a42f..41e82cbeac36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -24,7 +24,10 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; 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.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.app.KeyguardManager; @@ -49,6 +52,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.systemui.ActivityIntentHelper; import com.android.systemui.SysuiTestCase; import com.android.systemui.assist.AssistManager; +import com.android.systemui.bubbles.BubbleController; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; @@ -101,22 +105,23 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private KeyguardMonitor mKeyguardMonitor; @Mock private Handler mHandler; + @Mock + private BubbleController mBubbleController; @Mock private ActivityIntentHelper mActivityIntentHelper; @Mock private PendingIntent mContentIntent; @Mock - private NotificationData mNotificationData; - @Mock - private NotificationEntry mNotificationEntry; + private Intent mContentIntentInner; @Mock - private NotificationEntry mBubbleEntry; + private NotificationData mNotificationData; private NotificationActivityStarter mNotificationActivityStarter; private NotificationTestHelper mNotificationTestHelper; - ExpandableNotificationRow mNotificationRow; + private ExpandableNotificationRow mNotificationRow; + private ExpandableNotificationRow mBubbleNotificationRow; private final Answer<Void> mCallOnDismiss = answerVoid( (ActivityStarter.OnDismissAction dismissAction, Runnable cancel, @@ -129,14 +134,32 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); - mActiveNotifications = new ArrayList<>(); - mActiveNotifications.add(mNotificationEntry); - mActiveNotifications.add(mBubbleEntry); - when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications); - when(mNotificationEntry.getRow()).thenReturn(mNotificationRow); + when(mContentIntent.isActivity()).thenReturn(true); + when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1)); + when(mContentIntent.getIntent()).thenReturn(mContentIntentInner); mNotificationTestHelper = new NotificationTestHelper(mContext); + + // Create standard notification with contentIntent mNotificationRow = mNotificationTestHelper.createRow(); + StatusBarNotification sbn = mNotificationRow.getStatusBarNotification(); + sbn.getNotification().contentIntent = mContentIntent; + sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; + + // Create bubble notification row with contentIntent + mBubbleNotificationRow = mNotificationTestHelper.createBubble(); + StatusBarNotification bubbleSbn = mBubbleNotificationRow.getStatusBarNotification(); + bubbleSbn.getNotification().contentIntent = mContentIntent; + bubbleSbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; + // Do what BubbleController's NotificationEntryListener#onPendingEntryAdded does: + mBubbleNotificationRow.getEntry().setIsBubble(true); + mBubbleNotificationRow.getEntry().setShowInShadeWhenBubble(true); + + mActiveNotifications = new ArrayList<>(); + mActiveNotifications.add(mNotificationRow.getEntry()); + mActiveNotifications.add(mBubbleNotificationRow.getEntry()); + when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications); + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); mNotificationActivityStarter = new StatusBarNotificationActivityStarter(getContext(), mock(CommandQueue.class), mAssistManager, mock(NotificationPanelView.class), @@ -147,16 +170,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class), mock(NotificationLockscreenUserManager.class), mShadeController, mKeyguardMonitor, mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class), - mock(LockPatternUtils.class), mHandler, mActivityIntentHelper); - - - when(mContentIntent.isActivity()).thenReturn(true); - when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1)); - - // SBNActivityStarter expects contentIntent or fullScreenIntent to be set - mNotificationRow.getEntry().notification.getNotification().contentIntent = mContentIntent; - - when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); + mock(LockPatternUtils.class), mHandler, mHandler, mActivityIntentHelper, + mBubbleController); // set up dismissKeyguardThenExecute to synchronously invoke the OnDismissAction arg doAnswer(mCallOnDismiss).when(mActivityStarter).dismissKeyguardThenExecute( @@ -173,33 +188,26 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { // set up Handler to synchronously invoke the Runnable arg doAnswer(answerVoid(Runnable::run)) .when(mHandler).post(any(Runnable.class)); + + doAnswer(answerVoid(Runnable::run)) + .when(mHandler).postAtFrontOfQueue(any(Runnable.class)); } @Test - public void testOnNotificationClicked_whileKeyguardVisible() + public void testOnNotificationClicked_keyGuardShowing() throws PendingIntent.CanceledException, RemoteException { // Given + StatusBarNotification sbn = mNotificationRow.getStatusBarNotification(); + sbn.getNotification().contentIntent = mContentIntent; + sbn.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; + when(mKeyguardMonitor.isShowing()).thenReturn(true); when(mShadeController.isOccluded()).thenReturn(true); - when(mContentIntent.isActivity()).thenReturn(true); - when(mActivityIntentHelper.wouldShowOverLockscreen(any(Intent.class), anyInt())) - .thenReturn(false); - when(mActivityIntentHelper.wouldLaunchResolverActivity(any(Intent.class), anyInt())) - .thenReturn(false); - - StatusBarNotification statusBarNotification = mNotificationRow.getEntry().notification; - statusBarNotification.getNotification().flags |= Notification.FLAG_AUTO_CANCEL; // When - mNotificationActivityStarter.onNotificationClicked(statusBarNotification, - mNotificationRow); + mNotificationActivityStarter.onNotificationClicked(sbn, mNotificationRow); // Then - verify(mActivityStarter).dismissKeyguardThenExecute( - any(ActivityStarter.OnDismissAction.class), - any() /* cancel */, - anyBoolean() /* afterKeyguardGone */); - verify(mShadeController, atLeastOnce()).collapsePanel(); verify(mContentIntent).sendAndReturnResult( @@ -214,9 +222,100 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { verify(mAssistManager).hideAssist(); verify(mStatusBarService).onNotificationClick( - eq(mNotificationRow.getEntry().key), any(NotificationVisibility.class)); + eq(sbn.getKey()), any(NotificationVisibility.class)); // Notification is removed due to FLAG_AUTO_CANCEL - verify(mEntryManager).performRemoveNotification(eq(statusBarNotification)); + verify(mEntryManager).performRemoveNotification(eq(sbn)); + } + + @Test + public void testOnNotificationClicked_bubble_noContentIntent_noKeyGuard() + throws RemoteException { + StatusBarNotification sbn = mBubbleNotificationRow.getStatusBarNotification(); + + // Given + sbn.getNotification().contentIntent = null; + + // When + mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); + + // Then + verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey())); + + // This is called regardless, and simply short circuits when there is nothing to do. + verify(mShadeController, atLeastOnce()).collapsePanel(); + + verify(mAssistManager).hideAssist(); + + verify(mStatusBarService).onNotificationClick( + eq(sbn.getKey()), any(NotificationVisibility.class)); + + // The content intent should NOT be sent on click. + verifyZeroInteractions(mContentIntent); + + // Notification should not be cancelled. + verify(mEntryManager, never()).performRemoveNotification(eq(sbn)); + } + + @Test + public void testOnNotificationClicked_bubble_noContentIntent_keyGuardShowing() + throws RemoteException { + StatusBarNotification sbn = mBubbleNotificationRow.getStatusBarNotification(); + + // Given + sbn.getNotification().contentIntent = null; + when(mKeyguardMonitor.isShowing()).thenReturn(true); + when(mShadeController.isOccluded()).thenReturn(true); + + // When + mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); + + // Then + verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey())); + + verify(mShadeController, atLeastOnce()).collapsePanel(); + + verify(mAssistManager).hideAssist(); + + verify(mStatusBarService).onNotificationClick( + eq(sbn.getKey()), any(NotificationVisibility.class)); + + // The content intent should NOT be sent on click. + verifyZeroInteractions(mContentIntent); + + // Notification should not be cancelled. + verify(mEntryManager, never()).performRemoveNotification(eq(sbn)); + } + + @Test + public void testOnNotificationClicked_bubble_withContentIntent_keyGuardShowing() + throws RemoteException { + StatusBarNotification sbn = mBubbleNotificationRow.getStatusBarNotification(); + + // Given + sbn.getNotification().contentIntent = mContentIntent; + when(mKeyguardMonitor.isShowing()).thenReturn(true); + when(mShadeController.isOccluded()).thenReturn(true); + + // When + mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); + + // Then + verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey())); + + verify(mShadeController, atLeastOnce()).collapsePanel(); + + verify(mAssistManager).hideAssist(); + + verify(mStatusBarService).onNotificationClick( + eq(sbn.getKey()), any(NotificationVisibility.class)); + + // The content intent should NOT be sent on click. + verify(mContentIntent).getIntent(); + verify(mContentIntent).isActivity(); + verifyNoMoreInteractions(mContentIntent); + + // Notification should not be cancelled. + verify(mEntryManager, never()).performRemoveNotification(eq(sbn)); } } |