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

Commit 16291350 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Notification unbundle/rebundle on adjustment type updates" into main

parents 0d74af4e a3ddc7d0
Loading
Loading
Loading
Loading
+25 −0
Original line number Original line Diff line number Diff line
@@ -15,6 +15,10 @@
 */
 */
package android.app;
package android.app;


import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
import static android.service.notification.Adjustment.TYPE_NEWS;
import static android.service.notification.Adjustment.TYPE_PROMOTION;
import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA;
import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT;
import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT;


import android.annotation.FlaggedApi;
import android.annotation.FlaggedApi;
@@ -37,6 +41,7 @@ import android.os.VibrationEffect;
import android.os.vibrator.persistence.VibrationXmlParser;
import android.os.vibrator.persistence.VibrationXmlParser;
import android.os.vibrator.persistence.VibrationXmlSerializer;
import android.os.vibrator.persistence.VibrationXmlSerializer;
import android.provider.Settings;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;
@@ -1606,6 +1611,26 @@ public final class NotificationChannel implements Parcelable {
        return sb.toString();
        return sb.toString();
    }
    }


    /**
     * Get the reserved bundle channel ID for an Adjustment type
     * @param the Adjustment type
     * @return the channel ID, or null if type is invalid
     * @hide
     */
    public static @Nullable String getChannelIdForBundleType(@Adjustment.Types int type) {
        switch (type) {
            case TYPE_CONTENT_RECOMMENDATION:
                return RECS_ID;
            case TYPE_NEWS:
                return NEWS_ID;
            case TYPE_PROMOTION:
                return PROMOTIONS_ID;
            case TYPE_SOCIAL_MEDIA:
                return SOCIAL_MEDIA_ID;
        }
        return null;
    }

    public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR =
    public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR =
            new Creator<NotificationChannel>() {
            new Creator<NotificationChannel>() {
        @Override
        @Override
+0 −6
Original line number Original line Diff line number Diff line
@@ -244,10 +244,4 @@ interface IStatusBarService


    /** Shows rear display educational dialog */
    /** Shows rear display educational dialog */
    void showRearDisplayDialog(int currentBaseState);
    void showRearDisplayDialog(int currentBaseState);

    /** Unbundle a categorized notification */
    void unbundleNotification(String key);

    /** Rebundle an (un)categorized notification */
    void rebundleNotification(String key);
}
}
+0 −4
Original line number Original line Diff line number Diff line
@@ -433,10 +433,6 @@ class FakeStatusBarService : IStatusBarService.Stub() {


    override fun showRearDisplayDialog(currentBaseState: Int) {}
    override fun showRearDisplayDialog(currentBaseState: Int) {}


    override fun unbundleNotification(key: String) {}

    override fun rebundleNotification(key: String) {}

    companion object {
    companion object {
        const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
        const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
        const val SECONDARY_DISPLAY_ID = 2
        const val SECONDARY_DISPLAY_ID = 2
+0 −11
Original line number Original line Diff line number Diff line
@@ -101,15 +101,4 @@ public interface NotificationDelegate {
    void onNotificationFeedbackReceived(String key, Bundle feedback);
    void onNotificationFeedbackReceived(String key, Bundle feedback);


    void prepareForPossibleShutdown();
    void prepareForPossibleShutdown();

    /**
     *  Called when the notification should be unbundled.
     * @param key the notification key
     */
    void unbundleNotification(String key);
    /**
     *  Called when the notification should be rebundled.
     * @param key the notification key
     */
    void rebundleNotification(String key);
}
}
+194 −57
Original line number Original line Diff line number Diff line
@@ -290,6 +290,7 @@ import android.permission.PermissionManager;
import android.provider.Settings;
import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
import android.service.notification.Adjustment;
import android.service.notification.Adjustment.Types;
import android.service.notification.Condition;
import android.service.notification.Condition;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.ConversationChannelWrapper;
import android.service.notification.DeviceEffectsApplier;
import android.service.notification.DeviceEffectsApplier;
@@ -417,6 +418,7 @@ import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Collectors;
/** {@hide} */
/** {@hide} */
@@ -1865,20 +1867,62 @@ public class NotificationManagerService extends SystemService {
                mAssistants.notifyAssistantFeedbackReceived(r, feedback);
                mAssistants.notifyAssistantFeedbackReceived(r, feedback);
            }
            }
        }
        }
    };
        @Override
    private void unclassifyNotificationsForUser(final int userId) {
        public void unbundleNotification(String key) {
        if (DBG) {
            if (!(notificationClassification() && notificationRegroupOnClassification())) {
            Slog.v(TAG, "unclassifyForUser: " + userId);
        }
        unclassifyNotificationsFiltered((r) -> r.getUserId() == userId);
    }
    private void unclassifyNotificationsForUid(final int userId, @NonNull final String pkg) {
        if (DBG) {
            Slog.v(TAG, "unclassifyForUid userId: " + userId + " pkg: " + pkg);
        }
        unclassifyNotificationsFiltered((r) ->
                r.getUserId() == userId
                && Objects.equals(r.getSbn().getPackageName(), pkg));
    }
    private void unclassifyNotificationsForUserAndType(final int userId,
            final @Types int bundleType) {
        if (DBG) {
            Slog.v(TAG,
                    "unclassifyForUserAndType userId: " + userId + " bundleType: " + bundleType);
        }
        final String bundleChannelId = NotificationChannel.getChannelIdForBundleType(bundleType);
        unclassifyNotificationsFiltered((r) ->
                r.getUserId() == userId
                && r.getChannel() != null
                && Objects.equals(bundleChannelId, r.getChannel().getId()));
    }
    private void unclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) {
        if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
            return;
            return;
        }
        }
        synchronized (mNotificationLock) {
        synchronized (mNotificationLock) {
                NotificationRecord r = mNotificationsByKey.get(key);
            for (int i = 0; i < mEnqueuedNotifications.size(); i++) {
                if (r == null) {
                final NotificationRecord r = mEnqueuedNotifications.get(i);
                    return;
                if (filter.test(r)) {
                    unclassifyNotificationLocked(r);
                }
            }
            for (int i = 0; i < mNotificationList.size(); i++) {
                final NotificationRecord r = mNotificationList.get(i);
                if (filter.test(r)) {
                    unclassifyNotificationLocked(r);
                }
            }
        }
    }
    }
    @GuardedBy("mNotificationLock")
    private void unclassifyNotificationLocked(@NonNull final NotificationRecord r) {
        if (DBG) {
        if (DBG) {
                    Slog.v(TAG, "unbundleNotification: " + r);
            Slog.v(TAG, "unclassifyNotification: " + r);
        }
        }
        boolean hasOriginalSummary = false;
        boolean hasOriginalSummary = false;
@@ -1896,16 +1940,31 @@ public class NotificationManagerService extends SystemService {
        String origChannelId = r.getNotification().getChannelId();
        String origChannelId = r.getNotification().getChannelId();
        NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
        NotificationChannel originalChannel = mPreferencesHelper.getNotificationChannel(
                r.getSbn().getPackageName(), r.getUid(), origChannelId, false);
                r.getSbn().getPackageName(), r.getUid(), origChannelId, false);
                if (originalChannel != null && !origChannelId.equals(r.getChannel().getId())) {
        String currChannelId = r.getChannel().getId();
        boolean isBundled = NotificationChannel.SYSTEM_RESERVED_IDS.contains(currChannelId);
        if (originalChannel != null && !origChannelId.equals(currChannelId) && isBundled) {
            r.updateNotificationChannel(originalChannel);
            r.updateNotificationChannel(originalChannel);
            mGroupHelper.onNotificationUnbundled(r, hasOriginalSummary);
            mGroupHelper.onNotificationUnbundled(r, hasOriginalSummary);
        }
        }
    }
    }
    @VisibleForTesting
    void unclassifyNotification(final String key) {
        if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
            return;
        }
        synchronized (mNotificationLock) {
            NotificationRecord r = mNotificationsByKey.get(key);
            if (r == null) {
                return;
            }
            unclassifyNotificationLocked(r);
        }
    }
    }
        @Override
    @VisibleForTesting
        public void rebundleNotification(String key) {
    void reclassifyNotification(String key) {
            if (!(notificationClassification() && notificationRegroupOnClassification())) {
        if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
            return;
            return;
        }
        }
        synchronized (mNotificationLock) {
        synchronized (mNotificationLock) {
@@ -1913,26 +1972,78 @@ public class NotificationManagerService extends SystemService {
            if (r == null) {
            if (r == null) {
                return;
                return;
            }
            }
            reclassifyNotificationLocked(r, true);
        }
    }
    private void reclassifyNotificationsFiltered(Predicate<NotificationRecord> filter) {
        if (!(notificationClassificationUi() && notificationRegroupOnClassification())) {
            return;
        }
        synchronized (mNotificationLock) {
            for (int i = 0; i < mEnqueuedNotifications.size(); i++) {
                final NotificationRecord r = mEnqueuedNotifications.get(i);
                if (filter.test(r)) {
                    reclassifyNotificationLocked(r, false);
                }
            }
            for (int i = 0; i < mNotificationList.size(); i++) {
                final NotificationRecord r = mNotificationList.get(i);
                if (filter.test(r)) {
                    reclassifyNotificationLocked(r, true);
                }
            }
        }
    }
    private void reclassifyNotificationsForUserAndType(final int userId,
            final @Types int bundleType) {
        if (DBG) {
            Slog.v(TAG, "reclassifyNotificationsForUserAndType userId: " + userId + " bundleType: "
                    + bundleType);
        }
        reclassifyNotificationsFiltered(
                (r) -> r.getUserId() == userId && r.getBundleType() == bundleType);
    }
    private void reclassifyNotificationsForUid(final int userId, final String pkg) {
        if (DBG) {
            Slog.v(TAG, "reclassifyNotificationsForUid userId: " + userId + " pkg: " + pkg);
        }
        reclassifyNotificationsFiltered((r) ->
                r.getUserId() == userId && Objects.equals(r.getSbn().getPackageName(), pkg));
    }
    private void reclassifyNotificationsForUser(final int userId) {
        if (DBG) {
            Slog.v(TAG, "reclassifyAllNotificationsForUser: " + userId);
        }
        reclassifyNotificationsFiltered((r) -> r.getUserId() == userId);
    }
    @GuardedBy("mNotificationLock")
    private void reclassifyNotificationLocked(@NonNull final NotificationRecord r,
            final boolean isPosted) {
        if (DBG) {
        if (DBG) {
                    Slog.v(TAG, "rebundleNotification: " + r);
            Slog.v(TAG, "reclassifyNotification: " + r);
        }
        }
                if (r.getBundleType() != Adjustment.TYPE_OTHER) {
        boolean isBundled = NotificationChannel.SYSTEM_RESERVED_IDS.contains(
                r.getChannel().getId());
        if (r.getBundleType() != Adjustment.TYPE_OTHER && !isBundled) {
            final Bundle classifBundle = new Bundle();
            final Bundle classifBundle = new Bundle();
            classifBundle.putInt(KEY_TYPE, r.getBundleType());
            classifBundle.putInt(KEY_TYPE, r.getBundleType());
            Adjustment adj = new Adjustment(r.getSbn().getPackageName(), r.getKey(),
            Adjustment adj = new Adjustment(r.getSbn().getPackageName(), r.getKey(),
                            classifBundle, "rebundle", r.getUserId());
                    classifBundle, "reclassify", r.getUserId());
                    applyAdjustmentLocked(r, adj, /* isPosted= */ true);
            applyAdjustmentLocked(r, adj, isPosted);
            mRankingHandler.requestSort();
            mRankingHandler.requestSort();
        } else {
        } else {
            if (DBG) {
            if (DBG) {
                        Slog.w(TAG, "Can't rebundle. No valid bundle type for: " + r);
                Slog.w(TAG, "Can't reclassify. No valid bundle type or already bundled: " + r);
                    }
            }
            }
        }
        }
    }
    }
    };
    NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() {
    NotificationManagerPrivate mNotificationManagerPrivate = new NotificationManagerPrivate() {
        @Nullable
        @Nullable
@@ -4370,7 +4481,11 @@ public class NotificationManagerService extends SystemService {
        public void allowAssistantAdjustment(String adjustmentType) {
        public void allowAssistantAdjustment(String adjustmentType) {
            checkCallerIsSystemOrSystemUiOrShell();
            checkCallerIsSystemOrSystemUiOrShell();
            mAssistants.allowAdjustmentType(adjustmentType);
            mAssistants.allowAdjustmentType(adjustmentType);
            if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
                if (KEY_TYPE.equals(adjustmentType)) {
                    reclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid()));
                }
            }
            handleSavePolicyFile();
            handleSavePolicyFile();
        }
        }
@@ -4379,7 +4494,11 @@ public class NotificationManagerService extends SystemService {
        public void disallowAssistantAdjustment(String adjustmentType) {
        public void disallowAssistantAdjustment(String adjustmentType) {
            checkCallerIsSystemOrSystemUiOrShell();
            checkCallerIsSystemOrSystemUiOrShell();
            mAssistants.disallowAdjustmentType(adjustmentType);
            mAssistants.disallowAdjustmentType(adjustmentType);
            if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
                if (KEY_TYPE.equals(adjustmentType)) {
                    unclassifyNotificationsForUser(UserHandle.getUserId(Binder.getCallingUid()));
                }
            }
            handleSavePolicyFile();
            handleSavePolicyFile();
        }
        }
@@ -4424,7 +4543,15 @@ public class NotificationManagerService extends SystemService {
        public void setAssistantAdjustmentKeyTypeState(int type, boolean enabled) {
        public void setAssistantAdjustmentKeyTypeState(int type, boolean enabled) {
            checkCallerIsSystemOrSystemUiOrShell();
            checkCallerIsSystemOrSystemUiOrShell();
            mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled);
            mAssistants.setAssistantAdjustmentKeyTypeState(type, enabled);
            if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
                if (enabled) {
                    reclassifyNotificationsForUserAndType(
                            UserHandle.getUserId(Binder.getCallingUid()), type);
                } else {
                    unclassifyNotificationsForUserAndType(
                            UserHandle.getUserId(Binder.getCallingUid()), type);
                }
            }
            handleSavePolicyFile();
            handleSavePolicyFile();
        }
        }
@@ -4440,7 +4567,15 @@ public class NotificationManagerService extends SystemService {
        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
        public void setTypeAdjustmentForPackageState(String pkg, boolean enabled) {
            checkCallerIsSystemOrSystemUiOrShell();
            checkCallerIsSystemOrSystemUiOrShell();
            mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
            mAssistants.setTypeAdjustmentForPackageState(pkg, enabled);
            if ((notificationClassificationUi() && notificationRegroupOnClassification())) {
                if (enabled) {
                    reclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()),
                            pkg);
                } else {
                    unclassifyNotificationsForUid(UserHandle.getUserId(Binder.getCallingUid()),
                            pkg);
                }
            }
            handleSavePolicyFile();
            handleSavePolicyFile();
        }
        }
@@ -7238,6 +7373,10 @@ public class NotificationManagerService extends SystemService {
        if (adjustment.getSignals() != null) {
        if (adjustment.getSignals() != null) {
            final Bundle adjustments = adjustment.getSignals();
            final Bundle adjustments = adjustment.getSignals();
            Bundle.setDefusable(adjustments, true);
            Bundle.setDefusable(adjustments, true);
            // Save classification even if the adjustment is disabled, in case user enables it later
            if (notificationClassification() && adjustments.containsKey(KEY_TYPE)) {
                r.setBundleType(adjustments.getInt(KEY_TYPE));
            }
            List<String> toRemove = new ArrayList<>();
            List<String> toRemove = new ArrayList<>();
            for (String potentialKey : adjustments.keySet()) {
            for (String potentialKey : adjustments.keySet()) {
                if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
                if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
@@ -7267,9 +7406,7 @@ public class NotificationManagerService extends SystemService {
                    int classification = adjustments.getInt(KEY_TYPE);
                    int classification = adjustments.getInt(KEY_TYPE);
                    // swap app provided type with the real thing
                    // swap app provided type with the real thing
                    adjustments.putParcelable(KEY_TYPE, newChannel);
                    adjustments.putParcelable(KEY_TYPE, newChannel);
                    logClassificationChannelAdjustmentReceived(r, isPosted, classification);
                    logClassificationChannelAdjustmentReceived(r, isPosted, classification);
                    r.setBundleType(classification);
                }
                }
            }
            }
            r.addAdjustment(adjustment);
            r.addAdjustment(adjustment);
Loading