diff options
| author | 2024-10-04 14:24:50 +0000 | |
|---|---|---|
| committer | 2024-10-04 14:24:50 +0000 | |
| commit | f5534e84fb78cbd09f7ae494f0cc667840c183dd (patch) | |
| tree | 656f728a69d03d1e60f6cbd7ecee913f56f6f72b | |
| parent | 6481a94c18e4ae9f8442dec2b95f49556e3a2193 (diff) | |
| parent | bf59facaa34279ff1122f6e505d1bc6c8144c950 (diff) | |
Merge "Schedule regrouping if classification adjustment is after notification polite_notifications_attn_update" into main
7 files changed, 160 insertions, 37 deletions
diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java index e8d14cbde516..9b9be4cd8f3f 100644 --- a/services/core/java/com/android/server/notification/GroupHelper.java +++ b/services/core/java/com/android/server/notification/GroupHelper.java @@ -832,8 +832,9 @@ public class GroupHelper { FullyQualifiedGroupKey newGroup) { } /** - * Called when a notification channel is updated, so that this helper can adjust - * the aggregate groups by moving children if their section has changed. + * Called when a notification channel is updated (channel attributes have changed), + * so that this helper can adjust the aggregate groups by moving children + * if their section has changed. * see {@link #onNotificationPostedWithDelay(NotificationRecord, List, Map)} * @param userId the userId of the channel * @param pkgName the channel's package @@ -853,24 +854,48 @@ public class GroupHelper { } } - // The list of notification operations required after the channel update - final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); + regroupNotifications(userId, pkgName, notificationsToCheck); + } + } - // Check any already auto-grouped notifications that may need to be re-grouped - // after the channel update - notificationsToMove.addAll( - getAutogroupedNotificationsMoveOps(userId, pkgName, - notificationsToCheck)); + /** + * Called when an individuial notification's channel is updated (moved to a new channel), + * so that this helper can adjust the aggregate groups by moving children + * if their section has changed. + * see {@link #onNotificationPostedWithDelay(NotificationRecord, List, Map)} + * + * @param record the notification which had its channel updated + */ + @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING) + public void onChannelUpdated(final NotificationRecord record) { + synchronized (mAggregatedNotifications) { + ArrayMap<String, NotificationRecord> notificationsToCheck = new ArrayMap<>(); + notificationsToCheck.put(record.getKey(), record); + regroupNotifications(record.getUserId(), record.getSbn().getPackageName(), + notificationsToCheck); + } + } + + @GuardedBy("mAggregatedNotifications") + private void regroupNotifications(int userId, String pkgName, + ArrayMap<String, NotificationRecord> notificationsToCheck) { + // The list of notification operations required after the channel update + final ArrayList<NotificationMoveOp> notificationsToMove = new ArrayList<>(); - // Check any ungrouped notifications that may need to be auto-grouped - // after the channel update - notificationsToMove.addAll( - getUngroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); + // Check any already auto-grouped notifications that may need to be re-grouped + // after the channel update + notificationsToMove.addAll( + getAutogroupedNotificationsMoveOps(userId, pkgName, + notificationsToCheck)); - // Batch move to new section - if (!notificationsToMove.isEmpty()) { - moveNotificationsToNewSection(userId, pkgName, notificationsToMove); - } + // Check any ungrouped notifications that may need to be auto-grouped + // after the channel update + notificationsToMove.addAll( + getUngroupedNotificationsMoveOps(userId, pkgName, notificationsToCheck)); + + // Batch move to new section + if (!notificationsToMove.isEmpty()) { + moveNotificationsToNewSection(userId, pkgName, notificationsToMove); } } diff --git a/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java b/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java index 97bbc2338f47..2dd4f8392fdf 100644 --- a/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java +++ b/services/core/java/com/android/server/notification/NotificationAdjustmentExtractor.java @@ -15,6 +15,9 @@ */ package com.android.server.notification; +import static android.service.notification.Adjustment.KEY_TYPE; +import static android.service.notification.Flags.notificationForceGrouping; + import android.content.Context; import android.util.Slog; @@ -24,6 +27,7 @@ import android.util.Slog; public class NotificationAdjustmentExtractor implements NotificationSignalExtractor { private static final String TAG = "AdjustmentExtractor"; private static final boolean DBG = false; + private GroupHelper mGroupHelper; public void initialize(Context ctx, NotificationUsageStats usageStats) { @@ -35,8 +39,27 @@ public class NotificationAdjustmentExtractor implements NotificationSignalExtrac if (DBG) Slog.d(TAG, "skipping empty notification"); return null; } + + final boolean hasAdjustedClassification = record.hasAdjustment(KEY_TYPE); record.applyAdjustments(); + if (notificationForceGrouping() + && android.service.notification.Flags.notificationClassification()) { + // Classification adjustments trigger regrouping + if (mGroupHelper != null && hasAdjustedClassification) { + return new RankingReconsideration(record.getKey(), 0) { + @Override + public void work() { + } + + @Override + public void applyChangesLocked(NotificationRecord record) { + mGroupHelper.onChannelUpdated(record); + } + }; + } + } + return null; } @@ -49,4 +72,9 @@ public class NotificationAdjustmentExtractor implements NotificationSignalExtrac public void setZenHelper(ZenModeHelper helper) { } + + @Override + public void setGroupHelper(GroupHelper groupHelper) { + mGroupHelper = groupHelper; + } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 56e0a8929772..99e66a222370 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -519,6 +519,7 @@ public class NotificationManagerService extends SystemService { private static final long DELAY_FORCE_REGROUP_TIME = 3000; + private static final String ACTION_NOTIFICATION_TIMEOUT = NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; private static final int REQUEST_CODE_TIMEOUT = 1; @@ -2583,7 +2584,7 @@ public class NotificationManagerService extends SystemService { mShowReviewPermissionsNotification, Clock.systemUTC()); mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper, - mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat); + mZenModeHelper, mUsageStats, extractorNames, mPlatformCompat, groupHelper); mSnoozeHelper = snoozeHelper; mGroupHelper = groupHelper; mHistoryManager = historyManager; @@ -6871,22 +6872,9 @@ public class NotificationManagerService extends SystemService { } if (android.service.notification.Flags.notificationClassification() && adjustments.containsKey(KEY_TYPE)) { - NotificationChannel newChannel = null; - int type = adjustments.getInt(KEY_TYPE); - if (TYPE_NEWS == type) { - newChannel = mPreferencesHelper.getNotificationChannel( - r.getSbn().getPackageName(), r.getUid(), NEWS_ID, false); - } else if (TYPE_PROMOTION == type) { - newChannel = mPreferencesHelper.getNotificationChannel( - r.getSbn().getPackageName(), r.getUid(), PROMOTIONS_ID, false); - } else if (TYPE_SOCIAL_MEDIA == type) { - newChannel = mPreferencesHelper.getNotificationChannel( - r.getSbn().getPackageName(), r.getUid(), SOCIAL_MEDIA_ID, false); - } else if (TYPE_CONTENT_RECOMMENDATION == type) { - newChannel = mPreferencesHelper.getNotificationChannel( - r.getSbn().getPackageName(), r.getUid(), RECS_ID, false); - } - if (newChannel == null) { + final NotificationChannel newChannel = getClassificationChannelLocked(r, + adjustments); + if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) { adjustments.remove(KEY_TYPE); } else { // swap app provided type with the real thing @@ -6902,6 +6890,27 @@ public class NotificationManagerService extends SystemService { } } + @GuardedBy("mNotificationLock") + @Nullable + private NotificationChannel getClassificationChannelLocked(NotificationRecord r, + Bundle adjustments) { + int type = adjustments.getInt(KEY_TYPE); + if (TYPE_NEWS == type) { + return mPreferencesHelper.getNotificationChannel( + r.getSbn().getPackageName(), r.getUid(), NEWS_ID, false); + } else if (TYPE_PROMOTION == type) { + return mPreferencesHelper.getNotificationChannel( + r.getSbn().getPackageName(), r.getUid(), PROMOTIONS_ID, false); + } else if (TYPE_SOCIAL_MEDIA == type) { + return mPreferencesHelper.getNotificationChannel( + r.getSbn().getPackageName(), r.getUid(), SOCIAL_MEDIA_ID, false); + } else if (TYPE_CONTENT_RECOMMENDATION == type) { + return mPreferencesHelper.getNotificationChannel( + r.getSbn().getPackageName(), r.getUid(), RECS_ID, false); + } + return null; + } + @SuppressWarnings("GuardedBy") @GuardedBy("mNotificationLock") void addAutogroupKeyLocked(String key, String groupName, boolean requestSort) { diff --git a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java index f0358d1e1d8c..be34beeb1236 100644 --- a/services/core/java/com/android/server/notification/NotificationSignalExtractor.java +++ b/services/core/java/com/android/server/notification/NotificationSignalExtractor.java @@ -55,4 +55,9 @@ public interface NotificationSignalExtractor { void setZenHelper(ZenModeHelper helper); default void setCompatChangeLogger(IPlatformCompat platformCompat){}; + + /** + * @param groupHelper Helper for auto-grouping notifications + */ + default void setGroupHelper(GroupHelper groupHelper){}; } diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 03dd9351efc7..f06d6405b3c2 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -23,7 +23,6 @@ import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.text.TextUtils.formatSimple; import android.annotation.NonNull; -import android.app.NotificationManager; import android.content.Context; import android.service.notification.RankingHelperProto; import android.util.ArrayMap; @@ -61,7 +60,7 @@ public class RankingHelper { }) public RankingHelper(Context context, RankingHandler rankingHandler, RankingConfig config, ZenModeHelper zenHelper, NotificationUsageStats usageStats, String[] extractorNames, - IPlatformCompat platformCompat) { + IPlatformCompat platformCompat, GroupHelper groupHelper) { mContext = context; mRankingHandler = rankingHandler; if (sortSectionByTime()) { @@ -80,6 +79,7 @@ public class RankingHelper { extractor.initialize(mContext, usageStats); extractor.setConfig(config); extractor.setZenHelper(zenHelper); + extractor.setGroupHelper(groupHelper); if (restrictAudioAttributesAlarm() || restrictAudioAttributesMedia() || restrictAudioAttributesCall()) { extractor.setCompatChangeLogger(platformCompat); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java index 18ca09be235c..bf0586ceb32d 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java @@ -18,11 +18,21 @@ package com.android.server.notification; import static android.app.NotificationManager.IMPORTANCE_LOW; +import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; +import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION; +import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING; + +import static com.google.common.truth.Truth.assertThat; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + import android.app.Notification; import android.app.NotificationChannel; import android.app.PendingIntent; @@ -30,12 +40,16 @@ import android.content.Intent; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.service.notification.Adjustment; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; import com.android.server.UiServiceTestCase; +import org.junit.Rule; import org.junit.Test; import java.util.ArrayList; @@ -43,6 +57,9 @@ import java.util.Objects; public class NotificationAdjustmentExtractorTest extends UiServiceTestCase { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); + @Test public void testExtractsAdjustment() { NotificationAdjustmentExtractor extractor = new NotificationAdjustmentExtractor(); @@ -111,6 +128,44 @@ public class NotificationAdjustmentExtractorTest extends UiServiceTestCase { assertEquals(snoozeCriteria, r.getSnoozeCriteria()); } + @Test + @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING}) + public void testClassificationAdjustments_triggerRegrouping() { + GroupHelper groupHelper = mock(GroupHelper.class); + NotificationAdjustmentExtractor extractor = new NotificationAdjustmentExtractor(); + extractor.setGroupHelper(groupHelper); + + NotificationRecord r = generateRecord(); + + Bundle classificationAdj = new Bundle(); + classificationAdj.putParcelable(Adjustment.KEY_TYPE, mock(NotificationChannel.class)); + Adjustment adjustment = new Adjustment("pkg", r.getKey(), classificationAdj, "", 0); + r.addAdjustment(adjustment); + + RankingReconsideration regroupingTask = extractor.process(r); + assertThat(regroupingTask).isNotNull(); + regroupingTask.applyChangesLocked(r); + verify(groupHelper, times(1)).onChannelUpdated(r); + } + + @Test + @DisableFlags({FLAG_NOTIFICATION_CLASSIFICATION, FLAG_NOTIFICATION_FORCE_GROUPING}) + public void testClassificationAdjustments_notTriggerRegrouping_flagsDisabled() { + GroupHelper groupHelper = mock(GroupHelper.class); + NotificationAdjustmentExtractor extractor = new NotificationAdjustmentExtractor(); + extractor.setGroupHelper(groupHelper); + + NotificationRecord r = generateRecord(); + + Bundle classificationAdj = new Bundle(); + classificationAdj.putParcelable(Adjustment.KEY_TYPE, mock(NotificationChannel.class)); + Adjustment adjustment = new Adjustment("pkg", r.getKey(), classificationAdj, "", 0); + r.addAdjustment(adjustment); + + RankingReconsideration regroupingTask = extractor.process(r); + assertThat(regroupingTask).isNull(); + } + private NotificationRecord generateRecord() { NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); final Notification.Builder builder = new Notification.Builder(getContext()) diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java index 9a6e81865947..5d4382a6331c 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java @@ -92,6 +92,7 @@ public class RankingHelperTest extends UiServiceTestCase { @Mock ZenModeHelper mMockZenModeHelper; @Mock RankingConfig mConfig; @Mock Vibrator mVibrator; + @Mock GroupHelper mGroupHelper; private NotificationManager.Policy mTestNotificationPolicy; private Notification mNotiGroupGSortA; @@ -157,7 +158,7 @@ public class RankingHelperTest extends UiServiceTestCase { when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); mHelper = new RankingHelper(getContext(), mHandler, mConfig, mMockZenModeHelper, mUsageStats, new String[] {ImportanceExtractor.class.getName()}, - mock(IPlatformCompat.class)); + mock(IPlatformCompat.class), mGroupHelper); mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID) .setContentTitle("A") |