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

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

Handle apps that upgrade to full conversations

- Apps that have sent incomplete conversations only are allowed
into the conversation section, but not allowed to have full controls.
Users can also demote these apps entirely from the converstion space
- Once an app starts using complete notifications, it can no longer
be fully demoted out of the conversation space, it's only demoted on
a per conversation basis.
- If an app has sent full conversation notifications, and then sends
an incomplete one, the incomplete notification will not be shown in
the conversation space.

Test: atest
Bug: 155276427

Change-Id: Iba9b01c53949632b6db2834511165e3571387ac9
parent f30c225f
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -58,7 +58,9 @@ interface INotificationManager

    void setShowBadge(String pkg, int uid, boolean showBadge);
    boolean canShowBadge(String pkg, int uid);
    boolean hasSentMessage(String pkg, int uid);
    boolean isInInvalidMsgState(String pkg, int uid);
    boolean hasUserDemotedInvalidMsgApp(String pkg, int uid);
    void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted);
    void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled);
    /**
     * Updates the notification's enabled state. Additionally locks importance for all of the
+30 −5
Original line number Diff line number Diff line
@@ -2725,10 +2725,19 @@ public class NotificationManagerService extends SystemService {
        Context appContext = r.getSbn().getPackageContext(getContext());
        Notification.Builder nb =
                Notification.Builder.recoverBuilder(appContext, r.getNotification());
        if (nb.getStyle() instanceof Notification.MessagingStyle && r.getShortcutInfo() == null) {
            mPreferencesHelper.setMessageSent(r.getSbn().getPackageName(), r.getUid());
        if (nb.getStyle() instanceof Notification.MessagingStyle) {
            if (r.getShortcutInfo() != null) {
                if (mPreferencesHelper.setValidMessageSent(
                        r.getSbn().getPackageName(), r.getUid())) {
                    handleSavePolicyFile();
                }
            } else {
                if (mPreferencesHelper.setInvalidMessageSent(
                        r.getSbn().getPackageName(), r.getUid())) {
                    handleSavePolicyFile();
                }
            }
        }
    }

    /**
@@ -3158,9 +3167,22 @@ public class NotificationManagerService extends SystemService {
        }

        @Override
        public boolean hasSentMessage(String pkg, int uid) {
        public boolean isInInvalidMsgState(String pkg, int uid) {
            checkCallerIsSystem();
            return mPreferencesHelper.isInInvalidMsgState(pkg, uid);
        }

        @Override
        public boolean hasUserDemotedInvalidMsgApp(String pkg, int uid) {
            checkCallerIsSystem();
            return mPreferencesHelper.hasSentMessage(pkg, uid);
            return mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, uid);
        }

        @Override
        public void setInvalidMsgAppDemoted(String pkg, int uid, boolean isDemoted) {
            checkCallerIsSystem();
            mPreferencesHelper.setInvalidMsgAppDemoted(pkg, uid, isDemoted);
            handleSavePolicyFile();
        }

        @Override
@@ -5698,6 +5720,9 @@ public class NotificationManagerService extends SystemService {
            Slog.w(TAG, "notification " + r.getKey() + " added an invalid shortcut");
        }
        r.setShortcutInfo(info);
        r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid));
        r.userDemotedAppFromConvoSpace(
                mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));

        if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                r.getSbn().getOverrideGroupKey() != null)) {
+16 −0
Original line number Diff line number Diff line
@@ -188,6 +188,8 @@ public final class NotificationRecord {
    private boolean mHasSeenSmartReplies;
    private boolean mFlagBubbleRemoved;
    private boolean mPostSilently;
    private boolean mHasSentValidMsg;
    private boolean mAppDemotedFromConvo;
    /**
     * Whether this notification (and its channels) should be considered user locked. Used in
     * conjunction with user sentiment calculation.
@@ -1377,6 +1379,14 @@ public final class NotificationRecord {
        return mShortcutInfo;
    }

    public void setHasSentValidMsg(boolean hasSentValidMsg) {
        mHasSentValidMsg = hasSentValidMsg;
    }

    public void userDemotedAppFromConvoSpace(boolean userDemoted) {
        mAppDemotedFromConvo = userDemoted;
    }

    /**
     * Whether this notification is a conversation notification.
     */
@@ -1397,6 +1407,12 @@ public final class NotificationRecord {
            && mShortcutInfo == null) {
            return false;
        }
        if (mHasSentValidMsg && mShortcutInfo == null) {
            return false;
        }
        if (mAppDemotedFromConvo) {
            return false;
        }
        return true;
    }

+80 −10
Original line number Diff line number Diff line
@@ -116,7 +116,9 @@ public class PreferencesHelper implements RankingConfig {
    private static final String ATT_ENABLED = "enabled";
    private static final String ATT_USER_ALLOWED = "allowed";
    private static final String ATT_HIDE_SILENT = "hide_gentle";
    private static final String ATT_SENT_MESSAGE = "sent_invalid_msg";
    private static final String ATT_SENT_INVALID_MESSAGE = "sent_invalid_msg";
    private static final String ATT_SENT_VALID_MESSAGE = "sent_valid_msg";
    private static final String ATT_USER_DEMOTED_INVALID_MSG_APP = "user_demote_msg_app";

    private static final int DEFAULT_PRIORITY = Notification.PRIORITY_DEFAULT;
    private static final int DEFAULT_VISIBILITY = NotificationManager.VISIBILITY_NO_OVERRIDE;
@@ -253,8 +255,12 @@ public class PreferencesHelper implements RankingConfig {
                                    parser, ATT_SHOW_BADGE, DEFAULT_SHOW_BADGE);
                            r.lockedAppFields = XmlUtils.readIntAttribute(parser,
                                    ATT_APP_USER_LOCKED_FIELDS, DEFAULT_LOCKED_APP_FIELDS);
                            r.hasSentMessage = XmlUtils.readBooleanAttribute(
                                    parser, ATT_SENT_MESSAGE, false);
                            r.hasSentInvalidMessage = XmlUtils.readBooleanAttribute(
                                    parser, ATT_SENT_INVALID_MESSAGE, false);
                            r.hasSentValidMessage = XmlUtils.readBooleanAttribute(
                                    parser, ATT_SENT_VALID_MESSAGE, false);
                            r.userDemotedMsgApp = XmlUtils.readBooleanAttribute(
                                    parser, ATT_USER_DEMOTED_INVALID_MSG_APP, false);

                            final int innerDepth = parser.getDepth();
                            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -497,7 +503,9 @@ public class PreferencesHelper implements RankingConfig {
                                || r.groups.size() > 0
                                || r.delegate != null
                                || r.bubblePreference != DEFAULT_BUBBLE_PREFERENCE
                                || r.hasSentMessage;
                                || r.hasSentInvalidMessage
                                || r.userDemotedMsgApp
                                || r.hasSentValidMessage;
                if (hasNonDefaultSettings) {
                    out.startTag(null, TAG_PACKAGE);
                    out.attribute(null, ATT_NAME, r.pkg);
@@ -516,7 +524,12 @@ public class PreferencesHelper implements RankingConfig {
                    out.attribute(null, ATT_SHOW_BADGE, Boolean.toString(r.showBadge));
                    out.attribute(null, ATT_APP_USER_LOCKED_FIELDS,
                            Integer.toString(r.lockedAppFields));
                    out.attribute(null, ATT_SENT_MESSAGE, Boolean.toString(r.hasSentMessage));
                    out.attribute(null, ATT_SENT_INVALID_MESSAGE,
                            Boolean.toString(r.hasSentInvalidMessage));
                    out.attribute(null, ATT_SENT_VALID_MESSAGE,
                            Boolean.toString(r.hasSentValidMessage));
                    out.attribute(null, ATT_USER_DEMOTED_INVALID_MSG_APP,
                            Boolean.toString(r.userDemotedMsgApp));

                    if (!forBackup) {
                        out.attribute(null, ATT_UID, Integer.toString(r.uid));
@@ -635,15 +648,68 @@ public class PreferencesHelper implements RankingConfig {
        updateConfig();
    }

    public boolean hasSentMessage(String packageName, int uid) {
    public boolean isInInvalidMsgState(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            return getOrCreatePackagePreferencesLocked(packageName, uid).hasSentMessage;
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            return r.hasSentInvalidMessage && !r.hasSentValidMessage;
        }
    }

    public boolean hasUserDemotedInvalidMsgApp(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            return isInInvalidMsgState(packageName, uid) ? r.userDemotedMsgApp : false;
        }
    }

    public void setInvalidMsgAppDemoted(String packageName, int uid, boolean isDemoted) {
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            r.userDemotedMsgApp = isDemoted;
        }
    }

    public boolean setInvalidMessageSent(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            boolean valueChanged = r.hasSentInvalidMessage == false;
            r.hasSentInvalidMessage = true;

            return valueChanged;
        }
    }

    public boolean setValidMessageSent(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            boolean valueChanged = r.hasSentValidMessage == false;
            r.hasSentValidMessage = true;

            return valueChanged;
        }
    }

    public void setMessageSent(String packageName, int uid) {
    @VisibleForTesting
    boolean hasSentInvalidMsg(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            getOrCreatePackagePreferencesLocked(packageName, uid).hasSentMessage = true;
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            return r.hasSentInvalidMessage;
        }
    }

    @VisibleForTesting
    boolean hasSentValidMsg(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            return r.hasSentValidMessage;
        }
    }

    @VisibleForTesting
    boolean didUserEverDemoteInvalidMsgApp(String packageName, int uid) {
        synchronized (mPackagePreferences) {
            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
            return r.userDemotedMsgApp;
        }
    }

@@ -2273,7 +2339,11 @@ public class PreferencesHelper implements RankingConfig {
        boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
        List<String> oemLockedChannels = new ArrayList<>();
        boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
        boolean hasSentMessage = false;

        boolean hasSentInvalidMessage = false;
        boolean hasSentValidMessage = false;
        // notE: only valid while hasSentMessage is false and hasSentInvalidMessage is true
        boolean userDemotedMsgApp = false;

        Delegate delegate = null;
        ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
+39 −7
Original line number Diff line number Diff line
@@ -6650,18 +6650,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();

        assertTrue(mBinderService.hasSentMessage(PKG, mUid));
        assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));
    }

    @Test
    public void testRecordMessages_validMsg() throws RemoteException {
        // Messaging notification with shortcut info
        Notification.BubbleMetadata metadata =
                new Notification.BubbleMetadata.Builder("id").build();
        Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
                null /* groupKey */, false /* isSummary */);
        nb.setShortcutId("id");
        nb.setBubbleMetadata(metadata);
        nb.setShortcutId(null);
        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
                "testRecordMessages_validMsg", mUid, 0, nb.build(), new UserHandle(mUid), null, 0);
        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
@@ -6670,7 +6666,43 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();

        assertFalse(mBinderService.hasSentMessage(PKG, mUid));
        assertTrue(mBinderService.isInInvalidMsgState(PKG, mUid));

        nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
                "testRecordMessages_validMsg");

        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();

        assertFalse(mBinderService.isInInvalidMsgState(PKG, mUid));
    }

    @Test
    public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException {
        NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel,
                "testRecordMessages_invalidMsg_afterValidMsg_1");
        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();
        assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation());

        mBinderService.cancelAllNotifications(PKG, mUid);
        waitForIdle();

        Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */,
                null /* groupKey */, false /* isSummary */);
        nb.setShortcutId(null);
        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1,
                "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(),
                new UserHandle(mUid), null, 0);
         nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);

        mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
                nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
        waitForIdle();

        assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation());
    }

    @Test
Loading