Merge "Let NoMan know when something is no longer a bubble" into qt-dev
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -71,7 +71,6 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.AutomaticZenRule;
|
||||
@@ -5047,4 +5046,112 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(),
|
||||
mUid + UserHandle.PER_USER_RANGE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotificationBubbleChanged_false() throws Exception {
|
||||
// Bubbles are allowed!
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
|
||||
when(mPreferencesHelper.getNotificationChannel(
|
||||
anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
|
||||
mTestNotificationChannel);
|
||||
when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
|
||||
mTestNotificationChannel.getImportance());
|
||||
|
||||
// Notif with bubble metadata but not our other misc requirements
|
||||
NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
|
||||
null /* tvExtender */, true /* isBubble */);
|
||||
|
||||
// Say we're foreground
|
||||
when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
|
||||
IMPORTANCE_FOREGROUND);
|
||||
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
// First we were a bubble
|
||||
StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
|
||||
assertEquals(1, notifsBefore.length);
|
||||
assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0);
|
||||
|
||||
// Notify we're not a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false);
|
||||
waitForIdle();
|
||||
|
||||
// Now we are not a bubble
|
||||
StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
|
||||
assertEquals(1, notifsAfter.length);
|
||||
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotificationBubbleChanged_true() throws Exception {
|
||||
// Bubbles are allowed!
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
|
||||
when(mPreferencesHelper.getNotificationChannel(
|
||||
anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
|
||||
mTestNotificationChannel);
|
||||
when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
|
||||
mTestNotificationChannel.getImportance());
|
||||
|
||||
// Plain notification that has bubble metadata
|
||||
NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
|
||||
null /* tvExtender */, true /* isBubble */);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
// Would be a normal notification because wouldn't have met requirements to bubble
|
||||
StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
|
||||
assertEquals(1, notifsBefore.length);
|
||||
assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
|
||||
|
||||
// Make the package foreground so that we're allowed to be a bubble
|
||||
when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
|
||||
IMPORTANCE_FOREGROUND);
|
||||
|
||||
// Notify we are now a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
|
||||
waitForIdle();
|
||||
|
||||
// Make sure we are a bubble
|
||||
StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
|
||||
assertEquals(1, notifsAfter.length);
|
||||
assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotificationBubbleChanged_true_notAllowed() throws Exception {
|
||||
// Bubbles are allowed!
|
||||
mService.setPreferencesHelper(mPreferencesHelper);
|
||||
when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
|
||||
when(mPreferencesHelper.getNotificationChannel(
|
||||
anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
|
||||
mTestNotificationChannel);
|
||||
when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
|
||||
mTestNotificationChannel.getImportance());
|
||||
|
||||
// Notif that is not a bubble
|
||||
NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
|
||||
null /* tvExtender */, true /* isBubble */);
|
||||
mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
|
||||
nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
|
||||
waitForIdle();
|
||||
|
||||
// Would be a normal notification because wouldn't have met requirements to bubble
|
||||
StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(PKG);
|
||||
assertEquals(1, notifsBefore.length);
|
||||
assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0);
|
||||
|
||||
// Notify we are now a bubble
|
||||
mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true);
|
||||
waitForIdle();
|
||||
|
||||
// We still wouldn't be a bubble because the notification didn't meet requirements
|
||||
StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(PKG);
|
||||
assertEquals(1, notifsAfter.length);
|
||||
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user