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