diff options
| author | 2024-05-03 14:48:06 +0100 | |
|---|---|---|
| committer | 2024-05-09 09:59:55 +0100 | |
| commit | 318236a5280b0135e0a39dcea226238aab0a7f3c (patch) | |
| tree | 674241eaf62cd242923d4b1b0959f896412455a2 | |
| parent | 4152bc7ec0f316a8587b31874e9b989d98c62668 (diff) | |
Fixed issue with notification bubble icon interaction on the lock screen
Updated logic to perform bubble action only after user unlocks the
device.
Test: StatusBarNotificationActivityStarterTest
Flag: NA
Fixes: 269059797
Change-Id: I08a41d2f338b6a4705665c7216960c68597b1123
5 files changed, 117 insertions, 14 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java index 0c341cc92f83..ec3c7d0d6de4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationActivityStarter.java @@ -27,6 +27,9 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow * (e.g. clicking on a notification, tapping on the settings icon in the notification guts) */ public interface NotificationActivityStarter { + /** Called when the user clicks on the notification bubble icon. */ + void onNotificationBubbleIconClicked(NotificationEntry entry); + /** Called when the user clicks on the surface of a notification. */ void onNotificationClicked(NotificationEntry entry, ExpandableNotificationRow row); 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 d10fac6ea3fc..6487d55197e8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -117,11 +117,14 @@ public final class NotificationClicker implements View.OnClickListener { Notification notification = sbn.getNotification(); if (notification.contentIntent != null || notification.fullScreenIntent != null || row.getEntry().isBubble()) { + row.setBubbleClickListener(v -> + mNotificationActivityStarter.onNotificationBubbleIconClicked(row.getEntry())); row.setOnClickListener(this); row.setOnDragSuccessListener(mOnDragSuccessListener); } else { row.setOnClickListener(null); row.setOnDragSuccessListener(null); + row.setBubbleClickListener(null); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 5e3df7b5e60f..23c0a0db04d5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -375,6 +375,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView }; private OnClickListener mOnClickListener; + @Nullable + private OnClickListener mBubbleClickListener; private OnDragSuccessListener mOnDragSuccessListener; private boolean mHeadsupDisappearRunning; private View mChildAfterViewWhenDismissed; @@ -1234,14 +1236,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView /** * The click listener for the bubble button. */ + @Nullable public View.OnClickListener getBubbleClickListener() { - return v -> { - if (mBubblesManagerOptional.isPresent()) { - mBubblesManagerOptional.get() - .onUserChangedBubble(mEntry, !mEntry.isBubble() /* createBubble */); - } - mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */); - }; + return mBubbleClickListener; + } + + /** + * Sets the click listener for the bubble button. + */ + public void setBubbleClickListener(@Nullable OnClickListener l) { + mBubbleClickListener = l; + // ensure listener is passed to the content views + mPrivateLayout.updateBubbleButton(mEntry); + mPublicLayout.updateBubbleButton(mEntry); } /** 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 e1a7f22a913a..e92058bf034a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -96,6 +96,20 @@ import javax.inject.Inject; @SysUISingleton public class StatusBarNotificationActivityStarter implements NotificationActivityStarter { + /** + * Helps to avoid recalculation of values provided to + * {@link #onDismiss(PendingIntent, boolean, boolean, boolean)}} method + */ + private interface OnKeyguardDismissedAction { + /** + * Invoked when keyguard is dismissed + * + * @return is used as return value for {@link ActivityStarter.OnDismissAction#onDismiss()} + */ + boolean onDismiss(PendingIntent intent, boolean isActivityIntent, boolean animate, + boolean showOverTheLockScreen); + } + private final Context mContext; private final int mDisplayId; @@ -207,6 +221,30 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } /** + * Called when the user clicks on the notification bubble icon. + * + * @param entry notification that bubble icon was clicked + */ + @Override + public void onNotificationBubbleIconClicked(NotificationEntry entry) { + Runnable action = () -> { + mBubblesManagerOptional.ifPresent(bubblesManager -> + bubblesManager.onUserChangedBubble(entry, !entry.isBubble())); + mHeadsUpManager.removeNotification(entry.getKey(), /* releaseImmediately= */ true); + }; + if (entry.isBubble()) { + // entry is being un-bubbled, no need to unlock + action.run(); + } else { + performActionAfterKeyguardDismissed(entry, + (intent, isActivityIntent, animate, showOverTheLockScreen) -> { + action.run(); + return false; + }); + } + } + + /** * Called when a notification is clicked. * * @param entry notification that was clicked @@ -217,7 +255,15 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mLogger.logStartingActivityFromClick(entry, row.isHeadsUpState(), mKeyguardStateController.isVisible(), mNotificationShadeWindowController.getPanelExpanded()); + OnKeyguardDismissedAction action = + (intent, isActivityIntent, animate, showOverTheLockScreen) -> + performActionOnKeyguardDismissed(entry, row, intent, isActivityIntent, + animate, showOverTheLockScreen); + performActionAfterKeyguardDismissed(entry, action); + } + private void performActionAfterKeyguardDismissed(NotificationEntry entry, + OnKeyguardDismissedAction action) { if (mRemoteInputManager.isRemoteInputActive(entry)) { // We have an active remote input typed and the user clicked on the notification. // this was probably unintentional, so we're closing the edit text instead. @@ -251,8 +297,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit ActivityStarter.OnDismissAction postKeyguardAction = new ActivityStarter.OnDismissAction() { @Override public boolean onDismiss() { - return handleNotificationClickAfterKeyguardDismissed( - entry, row, intent, isActivityIntent, animate, showOverLockscreen); + return action.onDismiss(intent, isActivityIntent, animate, showOverLockscreen); } @Override @@ -271,7 +316,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } } - private boolean handleNotificationClickAfterKeyguardDismissed( + private boolean performActionOnKeyguardDismissed( NotificationEntry entry, ExpandableNotificationRow row, PendingIntent intent, @@ -282,7 +327,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed( entry, row, intent, isActivityIntent, animate); - if (showOverLockscreen) { mShadeController.addPostCollapseAction(runnable); mShadeController.collapseShade(true /* animate */); 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 127a3d7b208b..269510e0b4b2 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 @@ -168,6 +168,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { private FakePowerRepository mPowerRepository; @Mock private UserTracker mUserTracker; + @Mock + private HeadsUpManager mHeadsUpManager; private final FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); private ExpandableNotificationRow mNotificationRow; private ExpandableNotificationRow mBubbleNotificationRow; @@ -222,13 +224,12 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mScreenOffAnimationController, mStatusBarStateController).getPowerInteractor(); - HeadsUpManager headsUpManager = mock(HeadsUpManager.class); NotificationLaunchAnimatorControllerProvider notificationAnimationProvider = new NotificationLaunchAnimatorControllerProvider( new NotificationLaunchAnimationInteractor( new NotificationLaunchAnimationRepository()), mock(NotificationListContainer.class), - headsUpManager, + mHeadsUpManager, mJankMonitor); mNotificationActivityStarter = new StatusBarNotificationActivityStarter( @@ -237,7 +238,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mHandler, mUiBgExecutor, mVisibilityProvider, - headsUpManager, + mHeadsUpManager, mActivityStarter, mCommandQueue, mClickNotifier, @@ -417,6 +418,51 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { } @Test + public void testOnNotificationBubbleIconClicked_unbubble_keyGuardShowing() + throws RemoteException { + NotificationEntry entry = mBubbleNotificationRow.getEntry(); + StatusBarNotification sbn = entry.getSbn(); + + // Given + sbn.getNotification().contentIntent = mContentIntent; + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); + + // When + mNotificationActivityStarter.onNotificationBubbleIconClicked(entry); + + // Then + verify(mBubblesManager).onUserChangedBubble(entry, false); + + verify(mHeadsUpManager).removeNotification(entry.getKey(), true); + + verifyNoMoreInteractions(mContentIntent); + verifyNoMoreInteractions(mShadeController); + } + + @Test + public void testOnNotificationBubbleIconClicked_bubble_keyGuardShowing() { + NotificationEntry entry = mNotificationRow.getEntry(); + StatusBarNotification sbn = entry.getSbn(); + + // Given + sbn.getNotification().contentIntent = mContentIntent; + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(true); + + // When + mNotificationActivityStarter.onNotificationBubbleIconClicked(entry); + + // Then + verify(mBubblesManager).onUserChangedBubble(entry, true); + + verify(mHeadsUpManager).removeNotification(entry.getKey(), true); + + verify(mContentIntent, atLeastOnce()).isActivity(); + verifyNoMoreInteractions(mContentIntent); + } + + @Test public void testOnFullScreenIntentWhenDozing_wakeUpDevice() { // GIVEN entry that can has a full screen intent that can show PendingIntent fullScreenIntent = PendingIntent.getActivity(mContext, 1, |