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

Commit 90bd918e authored by Mykola Podolian's avatar Mykola Podolian Committed by Android (Google) Code Review
Browse files

Merge "Fixed issue with notification bubble icon interaction on the lock screen" into main

parents c0f4718d 318236a5
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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);

+3 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }

+14 −7
Original line number Diff line number Diff line
@@ -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 */);
        return mBubbleClickListener;
    }
            mHeadsUpManager.removeNotification(mEntry.getKey(), true /* releaseImmediately */);
        };

    /**
     * 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);
    }

    /**
+48 −4
Original line number Diff line number Diff line
@@ -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;

@@ -206,6 +220,30 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
        launchFullScreenIntentProvider.registerListener(entry -> launchFullScreenIntent(entry));
    }

    /**
     * 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.
     *
@@ -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 */);
+49 −3
Original line number Diff line number Diff line
@@ -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,
@@ -416,6 +417,51 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
        verifyNoMoreInteractions(mContentIntent);
    }

    @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