Loading core/java/android/app/Notification.java +25 −0 Original line number Diff line number Diff line Loading @@ -4358,6 +4358,7 @@ public class Notification implements Parcelable /** * @hide */ // TODO: b/425364383 - Remove when inlining public boolean hasCompletedProgress() { // not a progress notification; can't be complete if (!extras.containsKey(EXTRA_PROGRESS) Loading @@ -4371,6 +4372,30 @@ public class Notification implements Parcelable return extras.getInt(EXTRA_PROGRESS) == extras.getInt(EXTRA_PROGRESS_MAX); } /** @hide */ public static final int PROGRESS_STATE_NONE = 0; /** @hide */ public static final int PROGRESS_STATE_ONGOING = 1; /** @hide */ public static final int PROGRESS_STATE_COMPLETE = 2; /** @hide */ @FlaggedApi(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public int getProgressState() { final int progress = extras.getInt(EXTRA_PROGRESS, 0); final int max = extras.getInt(EXTRA_PROGRESS_MAX, 0); final boolean ind = extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE); if (max != 0 || ind) { if (progress == max && !ind) { return PROGRESS_STATE_COMPLETE; } else { return PROGRESS_STATE_ONGOING; } } else { return PROGRESS_STATE_NONE; } } /** @removed */ @Deprecated public String getChannel() { Loading core/java/android/app/NotificationManager.java +33 −14 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Set; import java.util.concurrent.Executor; Loading Loading @@ -688,8 +689,10 @@ public class NotificationManager { private final RateLimiter mUnnecessaryCancelRateLimiter = new RateLimiter("cancel (dupe)", "notifications.value_client_throttled_cancel_duplicate", MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE); // Value is KNOWN_STATUS_ENQUEUED/_CANCELLED private final LruCache<NotificationKey, Integer> mKnownNotifications = new LruCache<>(100); // KnownStatus is KNOWN_STATUS_ENQUEUED/_CANCELLED private record KnownNotification(int knownStatus, OptionalInt progressState) {} private final LruCache<NotificationKey, KnownNotification> mKnownNotifications = new LruCache<>(100); private final Object mThrottleLock = new Object(); @UnsupportedAppUsage Loading Loading @@ -848,8 +851,20 @@ public class NotificationManager { if (Flags.nmBinderPerfThrottleNotify()) { NotificationKey key = new NotificationKey(user, pkg, tag, id); synchronized (mThrottleLock) { Integer status = mKnownNotifications.get(key); if (status != null && status == KNOWN_STATUS_ENQUEUED KnownNotification status = mKnownNotifications.get(key); if (Flags.notificationUpdateSheddingAllowProgressCompletion()) { if (status != null && status.knownStatus == KNOWN_STATUS_ENQUEUED && status.progressState.orElse(-1) == notification.getProgressState()) { if (mUpdateRateLimiter.eventExceedsRate()) { mUpdateRateLimiter.recordRejected(key); return true; } mUpdateRateLimiter.recordAccepted(); } mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_ENQUEUED, OptionalInt.of(notification.getProgressState()))); } else { if (status != null && status.knownStatus == KNOWN_STATUS_ENQUEUED && !notification.hasCompletedProgress()) { if (mUpdateRateLimiter.eventExceedsRate()) { mUpdateRateLimiter.recordRejected(key); Loading @@ -857,7 +872,9 @@ public class NotificationManager { } mUpdateRateLimiter.recordAccepted(); } mKnownNotifications.put(key, KNOWN_STATUS_ENQUEUED); mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_ENQUEUED, OptionalInt.empty())); } } } Loading Loading @@ -1047,15 +1064,16 @@ public class NotificationManager { if (Flags.nmBinderPerfThrottleNotify()) { NotificationKey key = new NotificationKey(user, pkg, tag, id); synchronized (mThrottleLock) { Integer status = mKnownNotifications.get(key); if (status != null && status == KNOWN_STATUS_CANCELLED) { KnownNotification status = mKnownNotifications.get(key); if (status != null && status.knownStatus == KNOWN_STATUS_CANCELLED) { if (mUnnecessaryCancelRateLimiter.eventExceedsRate()) { mUnnecessaryCancelRateLimiter.recordRejected(key); return true; } mUnnecessaryCancelRateLimiter.recordAccepted(); } mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED); mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_CANCELLED, OptionalInt.empty())); } } Loading @@ -1076,7 +1094,8 @@ public class NotificationManager { synchronized (mThrottleLock) { for (NotificationKey key : mKnownNotifications.snapshot().keySet()) { if (key.pkg.equals(pkg) && key.user.equals(user)) { mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED); mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_CANCELLED, OptionalInt.empty())); } } } Loading core/java/android/app/notification.aconfig +9 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,15 @@ flag { } } flag { name: "notification_update_shedding_allow_progress_completion" namespace: "systemui" description: "When throttling notification updates, specifically allow the progress -> no_progress transition" bug: "425364383" metadata { purpose: PURPOSE_BUGFIX } } # Start: exported flags that cannot be removed Loading core/tests/coretests/src/android/app/NotificationManagerTest.java +75 −3 Original line number Diff line number Diff line Loading @@ -141,6 +141,78 @@ public class NotificationManagerTest { eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION}) public void notifyAsPackage_advanceProgress_isThrottled() throws Exception { for (int i = 0; i < 100; i++) { Notification advance = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .setProgress(200, i, false) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, advance); mClock.advanceByMillis(5); } verify(mNotificationManager.mBackendService, atLeast(20)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION}) public void notifyAsPackage_completesProgress_isNotThrottled() throws Exception { for (int i = 0; i < 100; i++) { Notification advance = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .setProgress(200, i, false) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, advance); mClock.advanceByMillis(5); } verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); // Now, post one more notification that brings the progress bar to the end. Notification finished = new Notification.Builder(mContext, "channel") .setProgress(200, 200, false) .setSmallIcon(android.R.drawable.star_big_on) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, finished); verify(mNotificationManager.mBackendService).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), eq(finished), anyInt()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION}) public void notifyAsPackage_removesProgress_isNotThrottled() throws Exception { for (int i = 0; i < 100; i++) { Notification advance = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .setProgress(200, i, false) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, advance); mClock.advanceByMillis(5); } verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); // Now, post one more notification that removes the progress bar. Notification noProgress = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, noProgress); verify(mNotificationManager.mBackendService).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), eq(noProgress), anyInt()); } @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void cancel_unnecessaryAndRapid_isThrottled() throws Exception { Loading Loading @@ -206,7 +278,7 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void enqueue_afterCancel_isNotUpdateAndIsNotThrottled() throws Exception { public void notify_afterCancel_isNotUpdateAndIsNotThrottled() throws Exception { // First, hit the enqueue threshold. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { Loading @@ -226,7 +298,7 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void enqueue_afterCancelAsPackage_isNotUpdateAndIsNotThrottled() throws Exception { public void notify_afterCancelAsPackage_isNotUpdateAndIsNotThrottled() throws Exception { // First, hit the enqueue threshold. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { Loading @@ -246,7 +318,7 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void enqueue_afterCancelAll_isNotUpdateAndIsNotThrottled() throws Exception { public void notify_afterCancelAll_isNotUpdateAndIsNotThrottled() throws Exception { // First, hit the enqueue threshold. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { Loading core/tests/coretests/src/android/app/NotificationTest.java +38 −3 Original line number Diff line number Diff line Loading @@ -214,11 +214,46 @@ public class NotificationTest { } @Test public void testHasCompletedProgress_zeroMax() { Notification n = new Notification.Builder(mContext) @EnableFlags(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public void getProgressState_indeterminate_ongoing() { Notification n1 = new Notification.Builder(mContext) .setProgress(0, 0, true) .build(); assertFalse(n.hasCompletedProgress()); assertThat(n1.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); // Ignores max and progress. Notification n2 = new Notification.Builder(mContext) .setProgress(100, 100, true) .build(); Notification n3 = new Notification.Builder(mContext) .setProgress(100, 50, true) .build(); assertThat(n2.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); assertThat(n3.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); } @Test @EnableFlags(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public void getProgressState_noProgress_none() { Notification n = new Notification.Builder(mContext).build(); assertThat(n.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_NONE); } @Test @EnableFlags(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public void getProgressState_atMax_complete() { Notification n = new Notification.Builder(mContext) .setProgress(10, 10, false) .build(); assertThat(n.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_COMPLETE); } @Test public void getProgressState_notAtMax_ongoing() { Notification n = new Notification.Builder(mContext) .setProgress(10, 4, false) .build(); assertThat(n.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); } @Test Loading Loading
core/java/android/app/Notification.java +25 −0 Original line number Diff line number Diff line Loading @@ -4358,6 +4358,7 @@ public class Notification implements Parcelable /** * @hide */ // TODO: b/425364383 - Remove when inlining public boolean hasCompletedProgress() { // not a progress notification; can't be complete if (!extras.containsKey(EXTRA_PROGRESS) Loading @@ -4371,6 +4372,30 @@ public class Notification implements Parcelable return extras.getInt(EXTRA_PROGRESS) == extras.getInt(EXTRA_PROGRESS_MAX); } /** @hide */ public static final int PROGRESS_STATE_NONE = 0; /** @hide */ public static final int PROGRESS_STATE_ONGOING = 1; /** @hide */ public static final int PROGRESS_STATE_COMPLETE = 2; /** @hide */ @FlaggedApi(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public int getProgressState() { final int progress = extras.getInt(EXTRA_PROGRESS, 0); final int max = extras.getInt(EXTRA_PROGRESS_MAX, 0); final boolean ind = extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE); if (max != 0 || ind) { if (progress == max && !ind) { return PROGRESS_STATE_COMPLETE; } else { return PROGRESS_STATE_ONGOING; } } else { return PROGRESS_STATE_NONE; } } /** @removed */ @Deprecated public String getChannel() { Loading
core/java/android/app/NotificationManager.java +33 −14 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.OptionalInt; import java.util.Set; import java.util.concurrent.Executor; Loading Loading @@ -688,8 +689,10 @@ public class NotificationManager { private final RateLimiter mUnnecessaryCancelRateLimiter = new RateLimiter("cancel (dupe)", "notifications.value_client_throttled_cancel_duplicate", MAX_NOTIFICATION_UNNECESSARY_CANCEL_RATE); // Value is KNOWN_STATUS_ENQUEUED/_CANCELLED private final LruCache<NotificationKey, Integer> mKnownNotifications = new LruCache<>(100); // KnownStatus is KNOWN_STATUS_ENQUEUED/_CANCELLED private record KnownNotification(int knownStatus, OptionalInt progressState) {} private final LruCache<NotificationKey, KnownNotification> mKnownNotifications = new LruCache<>(100); private final Object mThrottleLock = new Object(); @UnsupportedAppUsage Loading Loading @@ -848,8 +851,20 @@ public class NotificationManager { if (Flags.nmBinderPerfThrottleNotify()) { NotificationKey key = new NotificationKey(user, pkg, tag, id); synchronized (mThrottleLock) { Integer status = mKnownNotifications.get(key); if (status != null && status == KNOWN_STATUS_ENQUEUED KnownNotification status = mKnownNotifications.get(key); if (Flags.notificationUpdateSheddingAllowProgressCompletion()) { if (status != null && status.knownStatus == KNOWN_STATUS_ENQUEUED && status.progressState.orElse(-1) == notification.getProgressState()) { if (mUpdateRateLimiter.eventExceedsRate()) { mUpdateRateLimiter.recordRejected(key); return true; } mUpdateRateLimiter.recordAccepted(); } mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_ENQUEUED, OptionalInt.of(notification.getProgressState()))); } else { if (status != null && status.knownStatus == KNOWN_STATUS_ENQUEUED && !notification.hasCompletedProgress()) { if (mUpdateRateLimiter.eventExceedsRate()) { mUpdateRateLimiter.recordRejected(key); Loading @@ -857,7 +872,9 @@ public class NotificationManager { } mUpdateRateLimiter.recordAccepted(); } mKnownNotifications.put(key, KNOWN_STATUS_ENQUEUED); mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_ENQUEUED, OptionalInt.empty())); } } } Loading Loading @@ -1047,15 +1064,16 @@ public class NotificationManager { if (Flags.nmBinderPerfThrottleNotify()) { NotificationKey key = new NotificationKey(user, pkg, tag, id); synchronized (mThrottleLock) { Integer status = mKnownNotifications.get(key); if (status != null && status == KNOWN_STATUS_CANCELLED) { KnownNotification status = mKnownNotifications.get(key); if (status != null && status.knownStatus == KNOWN_STATUS_CANCELLED) { if (mUnnecessaryCancelRateLimiter.eventExceedsRate()) { mUnnecessaryCancelRateLimiter.recordRejected(key); return true; } mUnnecessaryCancelRateLimiter.recordAccepted(); } mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED); mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_CANCELLED, OptionalInt.empty())); } } Loading @@ -1076,7 +1094,8 @@ public class NotificationManager { synchronized (mThrottleLock) { for (NotificationKey key : mKnownNotifications.snapshot().keySet()) { if (key.pkg.equals(pkg) && key.user.equals(user)) { mKnownNotifications.put(key, KNOWN_STATUS_CANCELLED); mKnownNotifications.put(key, new KnownNotification(KNOWN_STATUS_CANCELLED, OptionalInt.empty())); } } } Loading
core/java/android/app/notification.aconfig +9 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,15 @@ flag { } } flag { name: "notification_update_shedding_allow_progress_completion" namespace: "systemui" description: "When throttling notification updates, specifically allow the progress -> no_progress transition" bug: "425364383" metadata { purpose: PURPOSE_BUGFIX } } # Start: exported flags that cannot be removed Loading
core/tests/coretests/src/android/app/NotificationManagerTest.java +75 −3 Original line number Diff line number Diff line Loading @@ -141,6 +141,78 @@ public class NotificationManagerTest { eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION}) public void notifyAsPackage_advanceProgress_isThrottled() throws Exception { for (int i = 0; i < 100; i++) { Notification advance = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .setProgress(200, i, false) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, advance); mClock.advanceByMillis(5); } verify(mNotificationManager.mBackendService, atLeast(20)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION}) public void notifyAsPackage_completesProgress_isNotThrottled() throws Exception { for (int i = 0; i < 100; i++) { Notification advance = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .setProgress(200, i, false) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, advance); mClock.advanceByMillis(5); } verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); // Now, post one more notification that brings the progress bar to the end. Notification finished = new Notification.Builder(mContext, "channel") .setProgress(200, 200, false) .setSmallIcon(android.R.drawable.star_big_on) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, finished); verify(mNotificationManager.mBackendService).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), eq(finished), anyInt()); } @Test @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY, Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION}) public void notifyAsPackage_removesProgress_isNotThrottled() throws Exception { for (int i = 0; i < 100; i++) { Notification advance = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .setProgress(200, i, false) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, advance); mClock.advanceByMillis(5); } verify(mNotificationManager.mBackendService, atMost(30)).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), any(), anyInt()); // Now, post one more notification that removes the progress bar. Notification noProgress = new Notification.Builder(mContext, "channel") .setSmallIcon(android.R.drawable.star_big_on) .build(); mNotificationManager.notifyAsPackage("some.package.name", "tag", 1, noProgress); verify(mNotificationManager.mBackendService).enqueueNotificationWithTag( eq("some.package.name"), any(), any(), anyInt(), eq(noProgress), anyInt()); } @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void cancel_unnecessaryAndRapid_isThrottled() throws Exception { Loading Loading @@ -206,7 +278,7 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void enqueue_afterCancel_isNotUpdateAndIsNotThrottled() throws Exception { public void notify_afterCancel_isNotUpdateAndIsNotThrottled() throws Exception { // First, hit the enqueue threshold. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { Loading @@ -226,7 +298,7 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void enqueue_afterCancelAsPackage_isNotUpdateAndIsNotThrottled() throws Exception { public void notify_afterCancelAsPackage_isNotUpdateAndIsNotThrottled() throws Exception { // First, hit the enqueue threshold. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { Loading @@ -246,7 +318,7 @@ public class NotificationManagerTest { @Test @EnableFlags(Flags.FLAG_NM_BINDER_PERF_THROTTLE_NOTIFY) public void enqueue_afterCancelAll_isNotUpdateAndIsNotThrottled() throws Exception { public void notify_afterCancelAll_isNotUpdateAndIsNotThrottled() throws Exception { // First, hit the enqueue threshold. Notification n = exampleNotification(); for (int i = 0; i < 100; i++) { Loading
core/tests/coretests/src/android/app/NotificationTest.java +38 −3 Original line number Diff line number Diff line Loading @@ -214,11 +214,46 @@ public class NotificationTest { } @Test public void testHasCompletedProgress_zeroMax() { Notification n = new Notification.Builder(mContext) @EnableFlags(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public void getProgressState_indeterminate_ongoing() { Notification n1 = new Notification.Builder(mContext) .setProgress(0, 0, true) .build(); assertFalse(n.hasCompletedProgress()); assertThat(n1.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); // Ignores max and progress. Notification n2 = new Notification.Builder(mContext) .setProgress(100, 100, true) .build(); Notification n3 = new Notification.Builder(mContext) .setProgress(100, 50, true) .build(); assertThat(n2.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); assertThat(n3.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); } @Test @EnableFlags(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public void getProgressState_noProgress_none() { Notification n = new Notification.Builder(mContext).build(); assertThat(n.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_NONE); } @Test @EnableFlags(Flags.FLAG_NOTIFICATION_UPDATE_SHEDDING_ALLOW_PROGRESS_COMPLETION) public void getProgressState_atMax_complete() { Notification n = new Notification.Builder(mContext) .setProgress(10, 10, false) .build(); assertThat(n.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_COMPLETE); } @Test public void getProgressState_notAtMax_ongoing() { Notification n = new Notification.Builder(mContext) .setProgress(10, 4, false) .build(); assertThat(n.getProgressState()).isEqualTo(Notification.PROGRESS_STATE_ONGOING); } @Test Loading