Loading core/java/android/app/NotificationChannel.java +25 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading core/java/com/android/internal/statusbar/IStatusBarService.aidl +0 −6 Original line number Original line Diff line number Diff line Loading @@ -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); } } packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt +0 −4 Original line number Original line Diff line number Diff line Loading @@ -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 Loading services/core/java/com/android/server/notification/NotificationDelegate.java +0 −11 Original line number Original line Diff line number Diff line Loading @@ -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); } } services/core/java/com/android/server/notification/NotificationManagerService.java +194 −57 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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} */ Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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 Loading Loading @@ -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(); } } Loading @@ -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(); } } Loading Loading @@ -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(); } } Loading @@ -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(); } } Loading Loading @@ -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)) { Loading Loading @@ -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 Loading
core/java/android/app/NotificationChannel.java +25 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 Loading
core/java/com/android/internal/statusbar/IStatusBarService.aidl +0 −6 Original line number Original line Diff line number Diff line Loading @@ -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); } }
packages/SystemUI/tests/utils/src/android/internal/statusbar/FakeStatusBarService.kt +0 −4 Original line number Original line Diff line number Diff line Loading @@ -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 Loading
services/core/java/com/android/server/notification/NotificationDelegate.java +0 −11 Original line number Original line Diff line number Diff line Loading @@ -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); } }
services/core/java/com/android/server/notification/NotificationManagerService.java +194 −57 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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} */ Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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 Loading Loading @@ -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(); } } Loading @@ -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(); } } Loading Loading @@ -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(); } } Loading @@ -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(); } } Loading Loading @@ -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)) { Loading Loading @@ -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