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

Commit d61bdf17 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Update shortcut queries

- Include cached shortcuts also
- Require long lived flag

Test: atest
Fixes: 149925743
Change-Id: If3e50d2ffdc82308a503bce13fc28443fb77a6b6
parent 44a56296
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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<ShortcutInfo> shortcuts = mLauncherApps.getShortcuts(query, mSbn.getUser());
        if (shortcuts != null && !shortcuts.isEmpty()) {
+37 −33
Original line number Diff line number Diff line
@@ -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<ConversationChannelWrapper> 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<ShortcutInfo> 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<ConversationChannelWrapper> 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<ShortcutInfo> 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,7 +5950,12 @@ public class NotificationManagerService extends SystemService {
        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();
            if (packageName != null) {
                query.setPackage(packageName);
@@ -5967,12 +5963,20 @@ public class NotificationManagerService extends SystemService {
            if (shortcutId != null) {
                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);
            ShortcutInfo shortcutInfo = shortcuts != null && shortcuts.size() > 0
                    ? shortcuts.get(0)
                    : 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) {
+10 −3
Original line number Diff line number Diff line
@@ -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;
    }

+5 −7
Original line number Diff line number Diff line
@@ -6089,7 +6089,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {

        // Pretend the shortcut exists
        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);

        // 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));
+13 −10
Original line number Diff line number Diff line
@@ -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);