Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; Loading Loading @@ -218,7 +219,7 @@ public class NotificationConversationInfo extends LinearLayout implements // TODO: consider querying this earlier in the notification pipeline and passing it in // TODO: consider querying this earlier in the notification pipeline and passing it in LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() .setPackage(mPackageName) .setPackage(mPackageName) .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED) .setShortcutIds(Arrays.asList(mConversationId)); .setShortcutIds(Arrays.asList(mConversationId)); List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser()); List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser()); if (shortcuts != null && !shortcuts.isEmpty()) { if (shortcuts != null && !shortcuts.isEmpty()) { Loading services/core/java/com/android/server/notification/NotificationManagerService.java +37 −33 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.BIND_NOT_PERCEPTIBLE; import static android.content.Context.BIND_NOT_PERCEPTIBLE; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_LEANBACK; Loading Loading @@ -3448,16 +3449,10 @@ public class NotificationManagerService extends SystemService { ArrayList<ConversationChannelWrapper> conversations = ArrayList<ConversationChannelWrapper> conversations = mPreferencesHelper.getConversations(onlyImportant); mPreferencesHelper.getConversations(onlyImportant); for (ConversationChannelWrapper conversation : conversations) { for (ConversationChannelWrapper conversation : conversations) { LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() conversation.setShortcutInfo(getShortcutInfo( .setPackage(conversation.getPkg()) conversation.getNotificationChannel().getConversationId(), .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) conversation.getPkg(), .setShortcutIds(Arrays.asList( UserHandle.of(UserHandle.getUserId(conversation.getUid())))); conversation.getNotificationChannel().getConversationId())); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts( query, UserHandle.of(UserHandle.getUserId(conversation.getUid()))); if (shortcuts != null && !shortcuts.isEmpty()) { conversation.setShortcutInfo(shortcuts.get(0)); } } } return new ParceledListSlice<>(conversations); return new ParceledListSlice<>(conversations); } } Loading @@ -3477,16 +3472,10 @@ public class NotificationManagerService extends SystemService { ArrayList<ConversationChannelWrapper> conversations = ArrayList<ConversationChannelWrapper> conversations = mPreferencesHelper.getConversations(pkg, uid); mPreferencesHelper.getConversations(pkg, uid); for (ConversationChannelWrapper conversation : conversations) { for (ConversationChannelWrapper conversation : conversations) { LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() conversation.setShortcutInfo(getShortcutInfo( .setPackage(pkg) conversation.getNotificationChannel().getConversationId(), .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) pkg, .setShortcutIds(Arrays.asList( UserHandle.of(UserHandle.getUserId(uid)))); conversation.getNotificationChannel().getConversationId())); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts( query, UserHandle.of(UserHandle.getUserId(uid))); if (shortcuts != null && !shortcuts.isEmpty()) { conversation.setShortcutInfo(shortcuts.get(0)); } } } return new ParceledListSlice<>(conversations); return new ParceledListSlice<>(conversations); } } Loading Loading @@ -5646,6 +5635,8 @@ public class NotificationManagerService extends SystemService { } } } } r.setShortcutInfo(getShortcutInfo(notification.getShortcutId(), pkg, user)); if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, r.getSbn().getOverrideGroupKey() != null)) { r.getSbn().getOverrideGroupKey() != null)) { return; return; Loading Loading @@ -5959,7 +5950,12 @@ public class NotificationManagerService extends SystemService { return false; return false; } } private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) { private ShortcutInfo getShortcutInfo(String shortcutId, String packageName, UserHandle user) { final long token = Binder.clearCallingIdentity(); try { if (shortcutId == null || packageName == null || user == null) { return null; } LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); if (packageName != null) { if (packageName != null) { query.setPackage(packageName); query.setPackage(packageName); Loading @@ -5967,12 +5963,20 @@ public class NotificationManagerService extends SystemService { if (shortcutId != null) { if (shortcutId != null) { query.setShortcutIds(Arrays.asList(shortcutId)); query.setShortcutIds(Arrays.asList(shortcutId)); } } query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED); query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user); ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0 ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0 ? shortcuts.get(0) ? shortcuts.get(0) : null; : null; return shortcutInfo != null; return shortcutInfo; } finally { Binder.restoreCallingIdentity(token); } } private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) { ShortcutInfo shortcutInfo = getShortcutInfo(shortcutId, packageName, user); return shortcutInfo != null && shortcutInfo.isLongLived(); } } private void logBubbleError(String key, String failureMessage) { private void logBubbleError(String key, String failureMessage) { Loading services/core/java/com/android/server/notification/NotificationRecord.java +10 −3 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.media.AudioSystem; import android.media.AudioSystem; Loading Loading @@ -166,6 +167,7 @@ public final class NotificationRecord { private boolean mAllowBubble; private boolean mAllowBubble; private Light mLight; private Light mLight; private boolean mIsNotConversationOverride; private boolean mIsNotConversationOverride; private ShortcutInfo mShortcutInfo; /** /** * This list contains system generated smart actions from NAS, app-generated smart actions are * This list contains system generated smart actions from NAS, app-generated smart actions are * stored in Notification.actions with isContextual() set to true. * stored in Notification.actions with isContextual() set to true. Loading Loading @@ -1338,14 +1340,20 @@ public final class NotificationRecord { return hasCustomRemoteView && !hasDecoratedStyle; return hasCustomRemoteView && !hasDecoratedStyle; } } /** Whether this notification is a conversation notification. */ public void setShortcutInfo(ShortcutInfo shortcutInfo) { mShortcutInfo = shortcutInfo; } /** * Whether this notification is a conversation notification. */ public boolean isConversation() { public boolean isConversation() { Notification notification = getNotification(); Notification notification = getNotification(); if (mChannel.isDemoted() if (mChannel.isDemoted() || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { return false; return false; } } if (notification.getShortcutId() == null if (mShortcutInfo == null && !FeatureFlagUtils.isEnabled( && !FeatureFlagUtils.isEnabled( mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) { mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) { return false; return false; Loading @@ -1353,7 +1361,6 @@ public final class NotificationRecord { if (mIsNotConversationOverride) { if (mIsNotConversationOverride) { return false; return false; } } // STOPSHIP b/137397357: Check shortcut to make a further decision return true; return true; } } Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +5 −7 Original line number Original line Diff line number Diff line Loading @@ -6089,7 +6089,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Pretend the shortcut exists // Pretend the shortcut exists List<ShortcutInfo> shortcutInfos = new ArrayList<>(); List<ShortcutInfo> shortcutInfos = new ArrayList<>(); shortcutInfos.add(mock(ShortcutInfo.class)); ShortcutInfo info = mock(ShortcutInfo.class); when(info.isLongLived()).thenReturn(true); shortcutInfos.add(info); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); // Test: Send the bubble notification // Test: Send the bubble notification Loading @@ -6116,7 +6118,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); // We're no longer a bubble // We're no longer a bubble Notification notif2 = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); Notification notif2 = mService.getNotificationRecord( nr.getSbn().getKey()).getNotification(); assertFalse(notif2.isBubbleNotification()); assertFalse(notif2.isBubbleNotification()); } } Loading Loading @@ -6409,11 +6412,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { convos.add(convo2); convos.add(convo2); when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); // only one valid shortcut LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() .setPackage(PKG_P) .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) .setShortcutIds(Arrays.asList(channel1.getConversationId())); ShortcutInfo si = mock(ShortcutInfo.class); ShortcutInfo si = mock(ShortcutInfo.class); when(si.getShortLabel()).thenReturn("Hello"); when(si.getShortLabel()).thenReturn("Hello"); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +13 −10 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Color; import android.graphics.Color; import android.graphics.drawable.Icon; import android.graphics.drawable.Icon; import android.media.AudioAttributes; import android.media.AudioAttributes; Loading Loading @@ -203,16 +204,13 @@ public class NotificationRecordTest extends UiServiceTestCase { return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); } } private StatusBarNotification getMessagingStyleNotification(@Nullable String shortcutId) { private StatusBarNotification getMessagingStyleNotification() { final Builder builder = new Builder(mMockContext) final Builder builder = new Builder(mMockContext) .setContentTitle("foo") .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon); .setSmallIcon(android.R.drawable.sym_def_app_icon); Person person = new Person.Builder().setName("Bob").build(); Person person = new Person.Builder().setName("Bob").build(); builder.setStyle(new Notification.MessagingStyle(person)); builder.setStyle(new Notification.MessagingStyle(person)); if (shortcutId != null) { builder.setShortcutId(shortcutId); } Notification n = builder.build(); Notification n = builder.build(); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); Loading Loading @@ -1122,16 +1120,18 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test @Test public void testIsConversation() { public void testIsConversation() { StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(mock(ShortcutInfo.class)); assertTrue(record.isConversation()); assertTrue(record.isConversation()); } } @Test @Test public void testIsConversation_nullShortcutId() { public void testIsConversation_nullShortcut() { StatusBarNotification sbn = getMessagingStyleNotification(null); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(null); assertFalse(record.isConversation()); assertFalse(record.isConversation()); } } Loading @@ -1140,25 +1140,28 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testIsConversation_bypassShortcutFlagEnabled() { public void testIsConversation_bypassShortcutFlagEnabled() { Settings.Global.putString(mContentResolver, Settings.Global.putString(mContentResolver, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true"); FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true"); StatusBarNotification sbn = getMessagingStyleNotification(null); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(null); assertTrue(record.isConversation()); assertTrue(record.isConversation()); } } @Test @Test public void testIsConversation_channelDemoted() { public void testIsConversation_channelDemoted() { StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); StatusBarNotification sbn = getMessagingStyleNotification(); channel.setDemoted(true); channel.setDemoted(true); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(mock(ShortcutInfo.class)); assertFalse(record.isConversation()); assertFalse(record.isConversation()); } } @Test @Test public void testIsConversation_withAdjustmentOverride() { public void testIsConversation_withAdjustmentOverride() { StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(mock(ShortcutInfo.class)); Bundle bundle = new Bundle(); Bundle bundle = new Bundle(); bundle.putBoolean(KEY_NOT_CONVERSATION, true); bundle.putBoolean(KEY_NOT_CONVERSATION, true); Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +2 −1 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_LOW; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; import static android.provider.Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS; Loading Loading @@ -218,7 +219,7 @@ public class NotificationConversationInfo extends LinearLayout implements // TODO: consider querying this earlier in the notification pipeline and passing it in // TODO: consider querying this earlier in the notification pipeline and passing it in LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() .setPackage(mPackageName) .setPackage(mPackageName) .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED) .setShortcutIds(Arrays.asList(mConversationId)); .setShortcutIds(Arrays.asList(mConversationId)); List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser()); List<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser()); if (shortcuts != null && !shortcuts.isEmpty()) { if (shortcuts != null && !shortcuts.isEmpty()) { Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +37 −33 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.Context.BIND_NOT_PERCEPTIBLE; import static android.content.Context.BIND_NOT_PERCEPTIBLE; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED; import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_LEANBACK; Loading Loading @@ -3448,16 +3449,10 @@ public class NotificationManagerService extends SystemService { ArrayList<ConversationChannelWrapper> conversations = ArrayList<ConversationChannelWrapper> conversations = mPreferencesHelper.getConversations(onlyImportant); mPreferencesHelper.getConversations(onlyImportant); for (ConversationChannelWrapper conversation : conversations) { for (ConversationChannelWrapper conversation : conversations) { LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() conversation.setShortcutInfo(getShortcutInfo( .setPackage(conversation.getPkg()) conversation.getNotificationChannel().getConversationId(), .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) conversation.getPkg(), .setShortcutIds(Arrays.asList( UserHandle.of(UserHandle.getUserId(conversation.getUid())))); conversation.getNotificationChannel().getConversationId())); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts( query, UserHandle.of(UserHandle.getUserId(conversation.getUid()))); if (shortcuts != null && !shortcuts.isEmpty()) { conversation.setShortcutInfo(shortcuts.get(0)); } } } return new ParceledListSlice<>(conversations); return new ParceledListSlice<>(conversations); } } Loading @@ -3477,16 +3472,10 @@ public class NotificationManagerService extends SystemService { ArrayList<ConversationChannelWrapper> conversations = ArrayList<ConversationChannelWrapper> conversations = mPreferencesHelper.getConversations(pkg, uid); mPreferencesHelper.getConversations(pkg, uid); for (ConversationChannelWrapper conversation : conversations) { for (ConversationChannelWrapper conversation : conversations) { LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() conversation.setShortcutInfo(getShortcutInfo( .setPackage(pkg) conversation.getNotificationChannel().getConversationId(), .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) pkg, .setShortcutIds(Arrays.asList( UserHandle.of(UserHandle.getUserId(uid)))); conversation.getNotificationChannel().getConversationId())); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts( query, UserHandle.of(UserHandle.getUserId(uid))); if (shortcuts != null && !shortcuts.isEmpty()) { conversation.setShortcutInfo(shortcuts.get(0)); } } } return new ParceledListSlice<>(conversations); return new ParceledListSlice<>(conversations); } } Loading Loading @@ -5646,6 +5635,8 @@ public class NotificationManagerService extends SystemService { } } } } r.setShortcutInfo(getShortcutInfo(notification.getShortcutId(), pkg, user)); if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r, r.getSbn().getOverrideGroupKey() != null)) { r.getSbn().getOverrideGroupKey() != null)) { return; return; Loading Loading @@ -5959,7 +5950,12 @@ public class NotificationManagerService extends SystemService { return false; return false; } } private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) { private ShortcutInfo getShortcutInfo(String shortcutId, String packageName, UserHandle user) { final long token = Binder.clearCallingIdentity(); try { if (shortcutId == null || packageName == null || user == null) { return null; } LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery(); if (packageName != null) { if (packageName != null) { query.setPackage(packageName); query.setPackage(packageName); Loading @@ -5967,12 +5963,20 @@ public class NotificationManagerService extends SystemService { if (shortcutId != null) { if (shortcutId != null) { query.setShortcutIds(Arrays.asList(shortcutId)); query.setShortcutIds(Arrays.asList(shortcutId)); } } query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED); query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_CACHED); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user); List<ShortcutInfo> shortcuts = mLauncherAppsService.getShortcuts(query, user); ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0 ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0 ? shortcuts.get(0) ? shortcuts.get(0) : null; : null; return shortcutInfo != null; return shortcutInfo; } finally { Binder.restoreCallingIdentity(token); } } private boolean hasValidShortcutInfo(String shortcutId, String packageName, UserHandle user) { ShortcutInfo shortcutInfo = getShortcutInfo(shortcutId, packageName, user); return shortcutInfo != null && shortcutInfo.isLongLived(); } } private void logBubbleError(String key, String failureMessage) { private void logBubbleError(String key, String failureMessage) { Loading
services/core/java/com/android/server/notification/NotificationRecord.java +10 −3 Original line number Original line Diff line number Diff line Loading @@ -35,6 +35,7 @@ import android.content.Context; import android.content.Intent; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutInfo; import android.graphics.Bitmap; import android.graphics.Bitmap; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.media.AudioSystem; import android.media.AudioSystem; Loading Loading @@ -166,6 +167,7 @@ public final class NotificationRecord { private boolean mAllowBubble; private boolean mAllowBubble; private Light mLight; private Light mLight; private boolean mIsNotConversationOverride; private boolean mIsNotConversationOverride; private ShortcutInfo mShortcutInfo; /** /** * This list contains system generated smart actions from NAS, app-generated smart actions are * This list contains system generated smart actions from NAS, app-generated smart actions are * stored in Notification.actions with isContextual() set to true. * stored in Notification.actions with isContextual() set to true. Loading Loading @@ -1338,14 +1340,20 @@ public final class NotificationRecord { return hasCustomRemoteView && !hasDecoratedStyle; return hasCustomRemoteView && !hasDecoratedStyle; } } /** Whether this notification is a conversation notification. */ public void setShortcutInfo(ShortcutInfo shortcutInfo) { mShortcutInfo = shortcutInfo; } /** * Whether this notification is a conversation notification. */ public boolean isConversation() { public boolean isConversation() { Notification notification = getNotification(); Notification notification = getNotification(); if (mChannel.isDemoted() if (mChannel.isDemoted() || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { || !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { return false; return false; } } if (notification.getShortcutId() == null if (mShortcutInfo == null && !FeatureFlagUtils.isEnabled( && !FeatureFlagUtils.isEnabled( mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) { mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) { return false; return false; Loading @@ -1353,7 +1361,6 @@ public final class NotificationRecord { if (mIsNotConversationOverride) { if (mIsNotConversationOverride) { return false; return false; } } // STOPSHIP b/137397357: Check shortcut to make a further decision return true; return true; } } Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +5 −7 Original line number Original line Diff line number Diff line Loading @@ -6089,7 +6089,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Pretend the shortcut exists // Pretend the shortcut exists List<ShortcutInfo> shortcutInfos = new ArrayList<>(); List<ShortcutInfo> shortcutInfos = new ArrayList<>(); shortcutInfos.add(mock(ShortcutInfo.class)); ShortcutInfo info = mock(ShortcutInfo.class); when(info.isLongLived()).thenReturn(true); shortcutInfos.add(info); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); // Test: Send the bubble notification // Test: Send the bubble notification Loading @@ -6116,7 +6118,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); // We're no longer a bubble // We're no longer a bubble Notification notif2 = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); Notification notif2 = mService.getNotificationRecord( nr.getSbn().getKey()).getNotification(); assertFalse(notif2.isBubbleNotification()); assertFalse(notif2.isBubbleNotification()); } } Loading Loading @@ -6409,11 +6412,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { convos.add(convo2); convos.add(convo2); when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); // only one valid shortcut LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery() .setPackage(PKG_P) .setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED) .setShortcutIds(Arrays.asList(channel1.getConversationId())); ShortcutInfo si = mock(ShortcutInfo.class); ShortcutInfo si = mock(ShortcutInfo.class); when(si.getShortLabel()).thenReturn("Hello"); when(si.getShortLabel()).thenReturn("Hello"); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +13 −10 Original line number Original line Diff line number Diff line Loading @@ -51,6 +51,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Color; import android.graphics.Color; import android.graphics.drawable.Icon; import android.graphics.drawable.Icon; import android.media.AudioAttributes; import android.media.AudioAttributes; Loading Loading @@ -203,16 +204,13 @@ public class NotificationRecordTest extends UiServiceTestCase { return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); } } private StatusBarNotification getMessagingStyleNotification(@Nullable String shortcutId) { private StatusBarNotification getMessagingStyleNotification() { final Builder builder = new Builder(mMockContext) final Builder builder = new Builder(mMockContext) .setContentTitle("foo") .setContentTitle("foo") .setSmallIcon(android.R.drawable.sym_def_app_icon); .setSmallIcon(android.R.drawable.sym_def_app_icon); Person person = new Person.Builder().setName("Bob").build(); Person person = new Person.Builder().setName("Bob").build(); builder.setStyle(new Notification.MessagingStyle(person)); builder.setStyle(new Notification.MessagingStyle(person)); if (shortcutId != null) { builder.setShortcutId(shortcutId); } Notification n = builder.build(); Notification n = builder.build(); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n, mUser, null, uid); Loading Loading @@ -1122,16 +1120,18 @@ public class NotificationRecordTest extends UiServiceTestCase { @Test @Test public void testIsConversation() { public void testIsConversation() { StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(mock(ShortcutInfo.class)); assertTrue(record.isConversation()); assertTrue(record.isConversation()); } } @Test @Test public void testIsConversation_nullShortcutId() { public void testIsConversation_nullShortcut() { StatusBarNotification sbn = getMessagingStyleNotification(null); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(null); assertFalse(record.isConversation()); assertFalse(record.isConversation()); } } Loading @@ -1140,25 +1140,28 @@ public class NotificationRecordTest extends UiServiceTestCase { public void testIsConversation_bypassShortcutFlagEnabled() { public void testIsConversation_bypassShortcutFlagEnabled() { Settings.Global.putString(mContentResolver, Settings.Global.putString(mContentResolver, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true"); FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true"); StatusBarNotification sbn = getMessagingStyleNotification(null); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(null); assertTrue(record.isConversation()); assertTrue(record.isConversation()); } } @Test @Test public void testIsConversation_channelDemoted() { public void testIsConversation_channelDemoted() { StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); StatusBarNotification sbn = getMessagingStyleNotification(); channel.setDemoted(true); channel.setDemoted(true); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(mock(ShortcutInfo.class)); assertFalse(record.isConversation()); assertFalse(record.isConversation()); } } @Test @Test public void testIsConversation_withAdjustmentOverride() { public void testIsConversation_withAdjustmentOverride() { StatusBarNotification sbn = getMessagingStyleNotification("test_shortcut_id"); StatusBarNotification sbn = getMessagingStyleNotification(); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel); record.setShortcutInfo(mock(ShortcutInfo.class)); Bundle bundle = new Bundle(); Bundle bundle = new Bundle(); bundle.putBoolean(KEY_NOT_CONVERSATION, true); bundle.putBoolean(KEY_NOT_CONVERSATION, true); Loading