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

Commit a54e9fab authored by Mady Mellor's avatar Mady Mellor
Browse files

Let NoMan know when something is no longer a bubble

This is needed for some of the notification group summary stuff to work.

More importantly, this is needed so that we can properly report to apps
if their notification is bubbled or not, e.g. if the user dismisses the
bubble & the notification is in the shade, that shouldn't be reported as
'FLAG_BUBBLE' as that notification is not actually being shown as a bubble.

* Adds onBubbleNotificationChanged to NotificationDelegate to pipe through
  changes in bubble state, currently we only ever change it to 'false' but
  this CL includes ability to flip it to 'true' (and also checks if the
  notif should actually be able to bubble)
* Factors code that indicates something is approved to bubble into own
  method
* Adds way to set BubbleMetadata on a notification (hidden !!)

Bug: 130250809
Test: atest NotificationManagerServiceTest
Change-Id: I8df4cc1231ed5d078ce4d50a70d2631f82fd2306
parent c79a8e67
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ interface IStatusBarService
            in int notificationLocation, boolean modifiedBeforeSending);
    void onNotificationSettingsViewed(String key);
    void setSystemUiVisibility(int displayId, int vis, int mask, String cause);
    void onNotificationBubbleChanged(String key, boolean isBubble);

    void onGlobalActionsShown();
    void onGlobalActionsHidden();
+17 −10
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.INotificationManager;
import android.app.Notification;
import android.content.Context;
import android.content.pm.ParceledListSlice;
@@ -52,6 +51,7 @@ import androidx.annotation.IntDef;
import androidx.annotation.MainThread;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.R;
@@ -131,8 +131,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
    private StatusBarStateListener mStatusBarStateListener;

    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;

    private INotificationManager mNotificationManagerService;
    private IStatusBarService mBarService;

    // Used for determining view rect for touch interaction
    private Rect mTempRect = new Rect();
@@ -207,13 +206,6 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
        mNotificationEntryManager.addNotificationEntryListener(mEntryListener);

        try {
            mNotificationManagerService = INotificationManager.Stub.asInterface(
                    ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
        } catch (ServiceManager.ServiceNotFoundException e) {
            e.printStackTrace();
        }

        mStatusBarWindowController = statusBarWindowController;
        mStatusBarStateListener = new StatusBarStateListener();
        Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
@@ -231,6 +223,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
        mBubbleData = data;
        mBubbleData.setListener(mBubbleDataListener);
        mSurfaceSynchronizer = synchronizer;

        mBarService = IStatusBarService.Stub.asInterface(
                ServiceManager.getService(Context.STATUS_BAR_SERVICE));
    }

    /**
@@ -462,6 +457,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
            if (mStackView != null) {
                mStackView.removeBubble(bubble);
            }
            if (!bubble.entry.showInShadeWhenBubble()) {
                // The notification is gone & bubble is gone, time to actually remove it
                mNotificationEntryManager.performRemoveNotification(bubble.entry.notification);
            } else {
                // The notification is still in the shade but we've removed the bubble so
                // lets make sure NoMan knows it's not a bubble anymore
                try {
                    mBarService.onNotificationBubbleChanged(bubble.getKey(), false /* isBubble */);
                } catch (RemoteException e) {
                    // Bad things have happened
                }
            }
        }

        public void onBubbleUpdated(Bubble bubble) {
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ public interface NotificationDelegate {
            int notificationLocation);
    void onNotificationDirectReplied(String key);
    void onNotificationSettingsViewed(String key);
    void onNotificationBubbleChanged(String key, boolean isBubble);

    /**
     * Notifies that smart replies and actions have been added to the UI.
+32 −6
Original line number Diff line number Diff line
@@ -1020,6 +1020,24 @@ public class NotificationManagerService extends SystemService {
                }
            }
        }

        @Override
        public void onNotificationBubbleChanged(String key, boolean isBubble) {
            synchronized (mNotificationLock) {
                NotificationRecord r = mNotificationsByKey.get(key);
                if (r != null) {
                    final StatusBarNotification n = r.sbn;
                    final int callingUid = n.getUid();
                    final String pkg = n.getPackageName();
                    if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid,
                            null /* oldEntry */)) {
                        r.getNotification().flags |= FLAG_BUBBLE;
                    } else {
                        r.getNotification().flags &= ~FLAG_BUBBLE;
                    }
                }
            }
        }
    };

    @VisibleForTesting
@@ -4782,6 +4800,19 @@ public class NotificationManagerService extends SystemService {
    private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId,
            NotificationRecord oldRecord) {
        Notification notification = r.getNotification();
        if (isNotificationAppropriateToBubble(r, pkg, userId, oldRecord)) {
            notification.flags |= FLAG_BUBBLE;
        } else {
            notification.flags &= ~FLAG_BUBBLE;
        }
    }

    /**
     * @return whether the provided notification record is allowed to be represented as a bubble.
     */
    private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
            NotificationRecord oldRecord) {
        Notification notification = r.getNotification();

        // Does the app want to bubble & have permission to bubble?
        boolean canBubble = notification.getBubbleMetadata() != null
@@ -4807,12 +4838,7 @@ public class NotificationManagerService extends SystemService {
        // OR something that was previously a bubble & still exists
        boolean bubbleUpdate = oldRecord != null
                && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0;

        if (canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate)) {
            notification.flags |= FLAG_BUBBLE;
        } else {
            notification.flags &= ~FLAG_BUBBLE;
        }
        return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate);
    }

    private void doChannelWarningToast(CharSequence toastText) {
+11 −0
Original line number Diff line number Diff line
@@ -1313,6 +1313,17 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
        }
    }

    @Override
    public void onNotificationBubbleChanged(String key, boolean isBubble) {
        enforceStatusBarService();
        long identity = Binder.clearCallingIdentity();
        try {
            mNotificationDelegate.onNotificationBubbleChanged(key, isBubble);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
Loading