diff options
author | Julia Reynolds <juliacr@google.com> | 2017-07-05 08:47:03 -0400 |
---|---|---|
committer | Julia Reynolds <juliacr@google.com> | 2017-07-10 09:42:24 -0400 |
commit | 6ad0aecf99d4dc823935987dc2daff07ef465ac1 (patch) | |
tree | 951fa7e22dd05d97da18cbb769a4650e58721188 | |
parent | 5f8e0b881e9a878ad0cfb4b216fbdf892badd219 (diff) |
Limit the number of notis an app can enqueue
In addition to the number they can post. Also decrease
the number of posts per second to 5, but allow finished
progress notifications through.
Fixes: 63173849
Fixes: 63167456
Test: runtests systemui-notification & simultaneously
downloading 5 files.
Change-Id: I0c8ea35b3d9d38b000ea5fe383515e1d5a26bac7
5 files changed, 766 insertions, 660 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 32f01a0d885b..46e597aada56 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2541,6 +2541,22 @@ public class Notification implements Parcelable } } + /** + * @hide + */ + public boolean hasCompletedProgress() { + // not a progress notification; can't be complete + if (!extras.containsKey(EXTRA_PROGRESS) + || !extras.containsKey(EXTRA_PROGRESS_MAX)) { + return false; + } + // many apps use max 0 for 'indeterminate'; not complete + if (extras.getInt(EXTRA_PROGRESS_MAX) == 0) { + return false; + } + return extras.getInt(EXTRA_PROGRESS) == extras.getInt(EXTRA_PROGRESS_MAX); + } + /** @removed */ @Deprecated public String getChannel() { diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index bc41922b7df1..5457713112fe 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -99,6 +99,45 @@ public class NotificationTest { assertTrue(satisfiesTextContrast(secondaryTextColor, backgroundColor)); } + @Test + public void testHasCompletedProgress_noProgress() { + Notification n = new Notification.Builder(mContext).build(); + + assertFalse(n.hasCompletedProgress()); + } + + @Test + public void testHasCompletedProgress_complete() { + Notification n = new Notification.Builder(mContext) + .setProgress(100, 100, true) + .build(); + Notification n2 = new Notification.Builder(mContext) + .setProgress(10, 10, false) + .build(); + assertTrue(n.hasCompletedProgress()); + assertTrue(n2.hasCompletedProgress()); + } + + @Test + public void testHasCompletedProgress_notComplete() { + Notification n = new Notification.Builder(mContext) + .setProgress(100, 99, true) + .build(); + Notification n2 = new Notification.Builder(mContext) + .setProgress(10, 4, false) + .build(); + assertFalse(n.hasCompletedProgress()); + assertFalse(n2.hasCompletedProgress()); + } + + @Test + public void testHasCompletedProgress_zeroMax() { + Notification n = new Notification.Builder(mContext) + .setProgress(0, 0, true) + .build(); + assertFalse(n.hasCompletedProgress()); + } + private Notification.Builder getMediaNotification() { MediaSession session = new MediaSession(mContext, "test"); return new Notification.Builder(mContext, "color") diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 861c6d5bdf7b..57605bb73d50 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -209,7 +209,7 @@ public class NotificationManagerService extends SystemService { = SystemProperties.getBoolean("debug.child_notifs", true); static final int MAX_PACKAGE_NOTIFICATIONS = 50; - static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f; + static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f; // message codes static final int MESSAGE_TIMEOUT = 2; @@ -3292,8 +3292,19 @@ public class NotificationManagerService extends SystemService { // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. if (!isSystemNotification && !isNotificationFromListener) { synchronized (mNotificationLock) { - if (mNotificationsByKey.get(r.sbn.getKey()) != null) { - // this is an update, rate limit updates only + if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) { + // Ephemeral apps have some special constraints for notifications. + // They are not allowed to create new notifications however they are allowed to + // update notifications created by the system (e.g. a foreground service + // notification). + throw new SecurityException("Instant app " + pkg + + " cannot create notifications"); + } + + // rate limit updates that aren't completed progress notifications + if (mNotificationsByKey.get(r.sbn.getKey()) != null + && !r.getNotification().hasCompletedProgress()) { + final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg); if (appEnqueueRate > mMaxPackageEnqueueRate) { mUsageStats.registerOverRateQuota(pkg); @@ -3305,33 +3316,15 @@ public class NotificationManagerService extends SystemService { } return false; } - } else if (isCallerInstantApp(pkg)) { - // Ephemeral apps have some special constraints for notifications. - // They are not allowed to create new notifications however they are allowed to - // update notifications created by the system (e.g. a foreground service - // notification). - throw new SecurityException("Instant app " + pkg - + " cannot create notifications"); } - int count = 0; - final int N = mNotificationList.size(); - for (int i=0; i<N; i++) { - final NotificationRecord existing = mNotificationList.get(i); - if (existing.sbn.getPackageName().equals(pkg) - && existing.sbn.getUserId() == userId) { - if (existing.sbn.getId() == id - && TextUtils.equals(existing.sbn.getTag(), tag)) { - break; // Allow updating existing notification - } - count++; - if (count >= MAX_PACKAGE_NOTIFICATIONS) { - mUsageStats.registerOverCountQuota(pkg); - Slog.e(TAG, "Package has already posted " + count - + " notifications. Not showing more. package=" + pkg); - return false; - } - } + // limit the number of outstanding notificationrecords an app can have + int count = getNotificationCountLocked(pkg, userId, id, tag); + if (count >= MAX_PACKAGE_NOTIFICATIONS) { + mUsageStats.registerOverCountQuota(pkg); + Slog.e(TAG, "Package has already posted or enqueued " + count + + " notifications. Not showing more. package=" + pkg); + return false; } } } @@ -3358,6 +3351,32 @@ public class NotificationManagerService extends SystemService { return true; } + protected int getNotificationCountLocked(String pkg, int userId, int excludedId, + String excludedTag) { + int count = 0; + final int N = mNotificationList.size(); + for (int i = 0; i < N; i++) { + final NotificationRecord existing = mNotificationList.get(i); + if (existing.sbn.getPackageName().equals(pkg) + && existing.sbn.getUserId() == userId) { + if (existing.sbn.getId() == excludedId + && TextUtils.equals(existing.sbn.getTag(), excludedTag)) { + continue; + } + count++; + } + } + final int M = mEnqueuedNotifications.size(); + for (int i = 0; i < M; i++) { + final NotificationRecord existing = mEnqueuedNotifications.get(i); + if (existing.sbn.getPackageName().equals(pkg) + && existing.sbn.getUserId() == userId) { + count++; + } + } + return count; + } + protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) { final String pkg = r.sbn.getPackageName(); final int callingUid = r.sbn.getUid(); diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java index 77953fa0fa30..2e96f6fb888b 100644 --- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -984,4 +984,37 @@ public class NotificationManagerServiceTest extends NotificationTestCase { assertFalse(posted.getNotification().isColorized()); } + + @Test + public void testGetNotificationCountLocked() throws Exception { + for (int i = 0; i < 20; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, null, false); + mNotificationManagerService.addEnqueuedNotification(r); + } + for (int i = 0; i < 20; i++) { + NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, null, false); + mNotificationManagerService.addNotification(r); + } + + // another package + Notification n = + new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .build(); + + StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", uid, 0, + n, new UserHandle(uid), null, 0); + NotificationRecord otherPackage = + new NotificationRecord(mContext, sbn, mTestNotificationChannel); + mNotificationManagerService.addEnqueuedNotification(otherPackage); + mNotificationManagerService.addNotification(otherPackage); + + // Same notifications are enqueued as posted, everything counts b/c id and tag don't match + assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, new UserHandle(uid).getIdentifier(), 0, null)); + assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, new UserHandle(uid).getIdentifier(), 0, "tag2")); + assertEquals(2, mNotificationManagerService.getNotificationCountLocked("a", new UserHandle(uid).getIdentifier(), 0, "banana")); + + // exclude a known notification - it's excluded from only the posted list, not enqueued + assertEquals(39, mNotificationManagerService.getNotificationCountLocked(PKG, new UserHandle(uid).getIdentifier(), 0, "tag")); + } } diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java index fc68183b5970..82104034ca6e 100644 --- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java +++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java @@ -62,16 +62,16 @@ public class NotificationTestList extends TestActivity boolean mProgressDone = true; final int[] kNumberedIconResIDs = { - R.drawable.notification0, - R.drawable.notification1, - R.drawable.notification2, - R.drawable.notification3, - R.drawable.notification4, - R.drawable.notification5, - R.drawable.notification6, - R.drawable.notification7, - R.drawable.notification8, - R.drawable.notification9 + R.drawable.notification0, + R.drawable.notification1, + R.drawable.notification2, + R.drawable.notification3, + R.drawable.notification4, + R.drawable.notification5, + R.drawable.notification6, + R.drawable.notification7, + R.drawable.notification8, + R.drawable.notification9 }; final int kUnnumberedIconResID = R.drawable.notificationx; @@ -438,85 +438,85 @@ public class NotificationTestList extends TestActivity mNM.notify("cancel_madness", 7014, n); } }, - new Test("Off") { - public void run() { - PowerManager pm = (PowerManager) NotificationTestList.this.getSystemService( - Context.POWER_SERVICE); - PowerManager.WakeLock wl = + new Test("Off") { + public void run() { + PowerManager pm = (PowerManager) NotificationTestList.this.getSystemService( + Context.POWER_SERVICE); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "sound"); - wl.acquire(); + wl.acquire(); - pm.goToSleep(SystemClock.uptimeMillis()); + pm.goToSleep(SystemClock.uptimeMillis()); - Notification n = new Notification.Builder(NotificationTestList.this, "default") - .setSmallIcon(R.drawable.stat_sys_phone) - .setContentTitle(name) - .build(); - Log.d(TAG, "n.sound=" + n.sound); + Notification n = new Notification.Builder(NotificationTestList.this, "default") + .setSmallIcon(R.drawable.stat_sys_phone) + .setContentTitle(name) + .build(); + Log.d(TAG, "n.sound=" + n.sound); - mNM.notify(1, n); + mNM.notify(1, n); - Log.d(TAG, "releasing wake lock"); - wl.release(); - Log.d(TAG, "released wake lock"); - } - }, + Log.d(TAG, "releasing wake lock"); + wl.release(); + Log.d(TAG, "released wake lock"); + } + }, - new Test("Cancel #1") { - public void run() - { - mNM.cancel(1); - } - }, + new Test("Cancel #1") { + public void run() + { + mNM.cancel(1); + } + }, - new Test("Custom Button") { - public void run() { - RemoteViews view = new RemoteViews(getPackageName(), R.layout.button_notification); - view.setOnClickPendingIntent(R.id.button, makeIntent2()); - Notification n = new Notification.Builder(NotificationTestList.this, "default") - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setOngoing(true) - .setCustomContentView(view) - .build(); - - mNM.notify(1, n); - } - }, + new Test("Custom Button") { + public void run() { + RemoteViews view = new RemoteViews(getPackageName(), R.layout.button_notification); + view.setOnClickPendingIntent(R.id.button, makeIntent2()); + Notification n = new Notification.Builder(NotificationTestList.this, "default") + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setOngoing(true) + .setCustomContentView(view) + .build(); - new Test("Action Button") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "default") - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setOngoing(true) - .addAction(new Notification.Action.Builder( - Icon.createWithResource(NotificationTestList.this, - R.drawable.ic_statusbar_chat), - "Button", makeIntent2()) - .build()) - .build(); - - mNM.notify(1, n); - } - }, + mNM.notify(1, n); + } + }, - new Test("with intent") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "default") - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle("Persistent #1") - .setContentText("This is a notification!!!") - .setContentIntent(makeIntent2()) - .setOngoing(true) - .build(); - - mNM.notify(1, n); - } - }, + new Test("Action Button") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "default") + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setOngoing(true) + .addAction(new Notification.Action.Builder( + Icon.createWithResource(NotificationTestList.this, + R.drawable.ic_statusbar_chat), + "Button", makeIntent2()) + .build()) + .build(); + + mNM.notify(1, n); + } + }, + + new Test("with intent") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "default") + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle("Persistent #1") + .setContentText("This is a notification!!!") + .setContentIntent(makeIntent2()) + .setOngoing(true) + .build(); + + mNM.notify(1, n); + } + }, new Test("Is blocked?") { public void run() { @@ -534,484 +534,484 @@ public class NotificationTestList extends TestActivity } }, - new Test("Whens") { - public void run() - { - Notification.Builder n = new Notification.Builder( - NotificationTestList.this, "default") - .setSmallIcon(R.drawable.icon1) - .setContentTitle(name) - .setOngoing(true); - - mNM.notify(1, n.setContentTitle("(453) 123-2328") - .setWhen(System.currentTimeMillis()-(1000*60*60*24)) - .build()); - - mNM.notify(1, n.setContentTitle("Mark Willem, Me (2)") - .setWhen(System.currentTimeMillis()) - .build()); + new Test("Whens") { + public void run() + { + Notification.Builder n = new Notification.Builder( + NotificationTestList.this, "default") + .setSmallIcon(R.drawable.icon1) + .setContentTitle(name) + .setOngoing(true); + + mNM.notify(1, n.setContentTitle("(453) 123-2328") + .setWhen(System.currentTimeMillis()-(1000*60*60*24)) + .build()); + + mNM.notify(1, n.setContentTitle("Mark Willem, Me (2)") + .setWhen(System.currentTimeMillis()) + .build()); + + mNM.notify(1, n.setContentTitle("Sophia Winterlanden") + .setWhen(System.currentTimeMillis() + (1000 * 60 * 60 * 24)) + .build()); + } + }, - mNM.notify(1, n.setContentTitle("Sophia Winterlanden") - .setWhen(System.currentTimeMillis() + (1000 * 60 * 60 * 24)) - .build()); - } - }, + new Test("Bad Icon #1 (when=create)") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.layout.chrono_notification /* not an icon */) + .setWhen(mActivityCreateTime) + .setContentTitle("Persistent #1") + .setContentText("This is the same notification!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(1, n); + } + }, - new Test("Bad Icon #1 (when=create)") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.layout.chrono_notification /* not an icon */) - .setWhen(mActivityCreateTime) - .setContentTitle("Persistent #1") - .setContentText("This is the same notification!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(1, n); - } - }, + new Test("Bad Icon #1 (when=now)") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.layout.chrono_notification /* not an icon */) + .setWhen(System.currentTimeMillis()) + .setContentTitle("Persistent #1") + .setContentText("This is the same notification!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(1, n); + } + }, - new Test("Bad Icon #1 (when=now)") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.layout.chrono_notification /* not an icon */) - .setWhen(System.currentTimeMillis()) - .setContentTitle("Persistent #1") - .setContentText("This is the same notification!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(1, n); - } - }, + new Test("Null Icon #1 (when=now)") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(0) + .setWhen(System.currentTimeMillis()) + .setContentTitle("Persistent #1") + .setContentText("This is the same notification!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(1, n); + } + }, - new Test("Null Icon #1 (when=now)") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(0) - .setWhen(System.currentTimeMillis()) - .setContentTitle("Persistent #1") - .setContentText("This is the same notification!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(1, n); - } - }, + new Test("Bad resource #1 (when=create)") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon2) + .setWhen(mActivityCreateTime) + .setContentTitle("Persistent #1") + .setContentText("This is the same notification!!") + .setContentIntent(makeIntent()) + .build(); + n.contentView.setInt(1 /*bogus*/, "bogus method", 666); + mNM.notify(1, n); + } + }, - new Test("Bad resource #1 (when=create)") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon2) - .setWhen(mActivityCreateTime) - .setContentTitle("Persistent #1") - .setContentText("This is the same notification!!") - .setContentIntent(makeIntent()) - .build(); - n.contentView.setInt(1 /*bogus*/, "bogus method", 666); - mNM.notify(1, n); - } - }, + new Test("Bad resource #1 (when=now)") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon2) + .setWhen(System.currentTimeMillis()) + .setContentTitle("Persistent #1") + .setContentText("This is the same notification!!") + .setContentIntent(makeIntent()) + .build(); + n.contentView.setInt(1 /*bogus*/, "bogus method", 666); + mNM.notify(1, n); + } + }, - new Test("Bad resource #1 (when=now)") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon2) - .setWhen(System.currentTimeMillis()) - .setContentTitle("Persistent #1") - .setContentText("This is the same notification!!") - .setContentIntent(makeIntent()) - .build(); - n.contentView.setInt(1 /*bogus*/, "bogus method", 666); - mNM.notify(1, n); - } - }, - - new Test("Times") { - public void run() - { - long now = System.currentTimeMillis(); - - timeNotification(7, "24 hours from now", now+(1000*60*60*24)); - timeNotification(6, "12:01:00 from now", now+(1000*60*60*12)+(60*1000)); - timeNotification(5, "12 hours from now", now+(1000*60*60*12)); - timeNotification(4, "now", now); - timeNotification(3, "11:59:00 ago", now-((1000*60*60*12)-(60*1000))); - timeNotification(2, "12 hours ago", now-(1000*60*60*12)); - timeNotification(1, "24 hours ago", now-(1000*60*60*24)); - } - }, - new StateStress("Stress - Ongoing / Latest", 100, 100, new Runnable[] { - new Runnable() { - public void run() { - Log.d(TAG, "Stress - Ongoing/Latest 0"); - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon3) - .setWhen(System.currentTimeMillis()) - .setContentTitle("Stress - Ongoing") - .setContentText("Notify me!!!") - .setOngoing(true) - .build(); - mNM.notify(1, n); - } - }, - new Runnable() { - public void run() { - Log.d(TAG, "Stress - Ongoing/Latest 1"); - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon4) - .setWhen(System.currentTimeMillis()) - .setContentTitle("Stress - Latest") - .setContentText("Notify me!!!") - .build(); - mNM.notify(1, n); - } + new Test("Times") { + public void run() + { + long now = System.currentTimeMillis(); + + timeNotification(7, "24 hours from now", now+(1000*60*60*24)); + timeNotification(6, "12:01:00 from now", now+(1000*60*60*12)+(60*1000)); + timeNotification(5, "12 hours from now", now+(1000*60*60*12)); + timeNotification(4, "now", now); + timeNotification(3, "11:59:00 ago", now-((1000*60*60*12)-(60*1000))); + timeNotification(2, "12 hours ago", now-(1000*60*60*12)); + timeNotification(1, "24 hours ago", now-(1000*60*60*24)); } + }, + new StateStress("Stress - Ongoing / Latest", 100, 100, new Runnable[] { + new Runnable() { + public void run() { + Log.d(TAG, "Stress - Ongoing/Latest 0"); + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon3) + .setWhen(System.currentTimeMillis()) + .setContentTitle("Stress - Ongoing") + .setContentText("Notify me!!!") + .setOngoing(true) + .build(); + mNM.notify(1, n); + } + }, + new Runnable() { + public void run() { + Log.d(TAG, "Stress - Ongoing/Latest 1"); + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon4) + .setWhen(System.currentTimeMillis()) + .setContentTitle("Stress - Latest") + .setContentText("Notify me!!!") + .build(); + mNM.notify(1, n); + } + } }), - new Test("Long") { - public void run() - { - NotificationChannel channel = new NotificationChannel("v. noisy", - "channel for sound and a custom vibration", IMPORTANCE_DEFAULT); - channel.enableVibration(true); - channel.setVibrationPattern(new long[] { - 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, - 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, - 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 }); - mNM.createNotificationChannel(channel); - - Notification n = new Notification.Builder(NotificationTestList.this, "v. noisy") - .setSmallIcon(R.drawable.icon1) - .setContentTitle(name) - .build(); - mNM.notify(1, n); - } - }, + new Test("Long") { + public void run() + { + NotificationChannel channel = new NotificationChannel("v. noisy", + "channel for sound and a custom vibration", IMPORTANCE_DEFAULT); + channel.enableVibration(true); + channel.setVibrationPattern(new long[] { + 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, + 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, + 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 }); + mNM.createNotificationChannel(channel); - new Test("Progress #1") { - public void run() { - final boolean PROGRESS_UPDATES_WHEN = true; - if (!mProgressDone) return; - mProgressDone = false; - Thread t = new Thread() { - public void run() { - int x = 0; - final Notification.Builder n = new Notification.Builder( - NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon1) - .setContentTitle(name) - .setOngoing(true); - - while (!mProgressDone) { - n.setWhen(PROGRESS_UPDATES_WHEN - ? System.currentTimeMillis() - : mActivityCreateTime); - n.setProgress(100, x, false); - n.setContentText("Progress: " + x + "%"); - - mNM.notify(500, n.build()); - x = (x + 7) % 100; - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; + Notification n = new Notification.Builder(NotificationTestList.this, "v. noisy") + .setSmallIcon(R.drawable.icon1) + .setContentTitle(name) + .build(); + mNM.notify(1, n); + } + }, + + new Test("Progress #1") { + public void run() { + final boolean PROGRESS_UPDATES_WHEN = true; + if (!mProgressDone) return; + mProgressDone = false; + Thread t = new Thread() { + public void run() { + int x = 0; + final Notification.Builder n = new Notification.Builder( + NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon1) + .setContentTitle(name) + .setOngoing(true); + + while (!mProgressDone) { + n.setWhen(PROGRESS_UPDATES_WHEN + ? System.currentTimeMillis() + : mActivityCreateTime); + n.setProgress(100, x, false); + n.setContentText("Progress: " + x + "%"); + + mNM.notify(500, n.build()); + x = (x + 7) % 100; + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } } } - } - }; - t.start(); - } - }, + }; + t.start(); + } + }, - new Test("Stop Progress") { - public void run() { - mProgressDone = true; - mNM.cancel(500); - } - }, - - new Test("Blue Lights") { - public void run() - { - NotificationChannel channel = new NotificationChannel("blue", - "blue", IMPORTANCE_DEFAULT); - channel.enableLights(true); - channel.setLightColor(0xff0000ff); - mNM.createNotificationChannel(channel); - - Notification n = new Notification.Builder(NotificationTestList.this, "blue") - .setSmallIcon(R.drawable.icon2) - .setContentTitle(name) - .build(); - mNM.notify(1, n); - } - }, - - new Test("Red Lights") { - public void run() - { - NotificationChannel channel = new NotificationChannel("red", - "red", IMPORTANCE_DEFAULT); - channel.enableLights(true); - channel.setLightColor(0xffff0000); - mNM.createNotificationChannel(channel); - - Notification n = new Notification.Builder(NotificationTestList.this, "red") - .setSmallIcon(R.drawable.icon2) - .setContentTitle(name) - .build(); - mNM.notify(1, n); - } - }, - - new Test("Lights off") { - public void run() - { - Notification n = new Notification.Builder(NotificationTestList.this, "default") - .setSmallIcon(R.drawable.icon2) - .setContentTitle(name) - .build(); - mNM.notify(1, n); - } - }, - - new Test("Alert once") { - public void run() - { - Notification n = new Notification.Builder(NotificationTestList.this, "high") - .setSmallIcon(R.drawable.icon2) - .setContentTitle(name) - .setOnlyAlertOnce(true) - .build(); - mNM.notify(1, n); - } - }, - - new Test("Resource Sound") { - public void run() - { - NotificationChannel channel = new NotificationChannel("res_sound", - "resource sound", IMPORTANCE_DEFAULT); - channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + - getPackageName() + "/raw/ringer"), Notification.AUDIO_ATTRIBUTES_DEFAULT); - mNM.createNotificationChannel(channel); - - Notification n = new Notification.Builder(NotificationTestList.this, "res_sound") - .setSmallIcon(R.drawable.stat_sys_phone) - .setContentTitle(name) - .build(); - Log.d(TAG, "n.sound=" + n.sound); - - mNM.notify(1, n); - } - }, - - new Test("Sound and Cancel") { - public void run() - { - NotificationChannel channel = new NotificationChannel("res_sound", - "resource sound", IMPORTANCE_DEFAULT); - channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + - getPackageName() + "/raw/ringer"), Notification.AUDIO_ATTRIBUTES_DEFAULT); - mNM.createNotificationChannel(channel); - - Notification n = new Notification.Builder(NotificationTestList.this, "res_sound") - .setSmallIcon(R.drawable.stat_sys_phone) - .setContentTitle(name) - .build(); - - mNM.notify(1, n); - SystemClock.sleep(600); - mNM.cancel(1); - } - }, - - new Test("Vibrate and cancel") { - public void run() - { - NotificationChannel channel = new NotificationChannel("vibrate", - "vibrate", IMPORTANCE_DEFAULT); - channel.enableVibration(true); - channel.setVibrationPattern(new long[] {0, 700, 500, 1000, 0, 700, 500, 1000, - 0, 700, 500, 1000, 0, 700, 500, 1000, 0, 700, 500, 1000, 0, 700, 500, 1000, - 0, 700, 500, 1000, 0, 700, 500, 1000}); - mNM.createNotificationChannel(channel); - - Notification n = new Notification.Builder(NotificationTestList.this, "vibrate") - .setSmallIcon(R.drawable.stat_sys_phone) - .setContentTitle(name) - .build(); - - mNM.notify(1, n); - SystemClock.sleep(500); - mNM.cancel(1); - } - }, + new Test("Stop Progress") { + public void run() { + mProgressDone = true; + mNM.cancel(500); + } + }, - new Test("Vibrate pattern") { - public void run() - { - mVibrator.vibrate(new long[] { 250, 1000, 500, 2000 }, -1); - } - }, + new Test("Blue Lights") { + public void run() + { + NotificationChannel channel = new NotificationChannel("blue", + "blue", IMPORTANCE_DEFAULT); + channel.enableLights(true); + channel.setLightColor(0xff0000ff); + mNM.createNotificationChannel(channel); - new Test("Vibrate pattern repeating") { - public void run() - { - mVibrator.vibrate(new long[] { 250, 1000, 500 }, 1); - } - }, + Notification n = new Notification.Builder(NotificationTestList.this, "blue") + .setSmallIcon(R.drawable.icon2) + .setContentTitle(name) + .build(); + mNM.notify(1, n); + } + }, - new Test("Vibrate 3s") { - public void run() - { - mVibrator.vibrate(3000); - } - }, + new Test("Red Lights") { + public void run() + { + NotificationChannel channel = new NotificationChannel("red", + "red", IMPORTANCE_DEFAULT); + channel.enableLights(true); + channel.setLightColor(0xffff0000); + mNM.createNotificationChannel(channel); - new Test("Vibrate 100s") { - public void run() - { - mVibrator.vibrate(100000); - } - }, + Notification n = new Notification.Builder(NotificationTestList.this, "red") + .setSmallIcon(R.drawable.icon2) + .setContentTitle(name) + .build(); + mNM.notify(1, n); + } + }, - new Test("Vibrate off") { - public void run() - { - mVibrator.cancel(); - } - }, + new Test("Lights off") { + public void run() + { + Notification n = new Notification.Builder(NotificationTestList.this, "default") + .setSmallIcon(R.drawable.icon2) + .setContentTitle(name) + .build(); + mNM.notify(1, n); + } + }, - new Test("Cancel #1") { - public void run() { - mNM.cancel(1); - } - }, + new Test("Alert once") { + public void run() + { + Notification n = new Notification.Builder(NotificationTestList.this, "high") + .setSmallIcon(R.drawable.icon2) + .setContentTitle(name) + .setOnlyAlertOnce(true) + .build(); + mNM.notify(1, n); + } + }, - new Test("Cancel #1 in 3 sec") { - public void run() { - mHandler.postDelayed(new Runnable() { - public void run() { - Log.d(TAG, "Cancelling now..."); - mNM.cancel(1); - } - }, 3000); - } - }, + new Test("Resource Sound") { + public void run() + { + NotificationChannel channel = new NotificationChannel("res_sound", + "resource sound", IMPORTANCE_DEFAULT); + channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + + getPackageName() + "/raw/ringer"), Notification.AUDIO_ATTRIBUTES_DEFAULT); + mNM.createNotificationChannel(channel); + + Notification n = new Notification.Builder(NotificationTestList.this, "res_sound") + .setSmallIcon(R.drawable.stat_sys_phone) + .setContentTitle(name) + .build(); + Log.d(TAG, "n.sound=" + n.sound); - new Test("Cancel #2") { - public void run() { - mNM.cancel(2); - } - }, + mNM.notify(1, n); + } + }, - new Test("Persistent #1") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this) - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setContentText("This is a notification!!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(1, n); - } - }, + new Test("Sound and Cancel") { + public void run() + { + NotificationChannel channel = new NotificationChannel("res_sound", + "resource sound", IMPORTANCE_DEFAULT); + channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + + getPackageName() + "/raw/ringer"), Notification.AUDIO_ATTRIBUTES_DEFAULT); + mNM.createNotificationChannel(channel); + + Notification n = new Notification.Builder(NotificationTestList.this, "res_sound") + .setSmallIcon(R.drawable.stat_sys_phone) + .setContentTitle(name) + .build(); - new Test("Persistent #1 in 3 sec") { - public void run() { - mHandler.postDelayed(new Runnable() { - public void run() { - String message = " " - + "tick tock tick tock\n\nSometimes notifications can " - + "be really long and wrap to more than one line.\n" - + "Sometimes." - + "Ohandwhathappensifwehaveonereallylongstringarewesure" - + "thatwesegmentitcorrectly?\n"; - Notification n = new Notification.Builder( - NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon1) - .setContentTitle(name) - .setContentText("This is still a notification!!!") - .setContentIntent(makeIntent()) - .setStyle(new Notification.BigTextStyle().bigText(message)) - .build(); - mNM.notify(1, n); - } - }, 3000); - } - }, + mNM.notify(1, n); + SystemClock.sleep(600); + mNM.cancel(1); + } + }, - new Test("Persistent #2") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setContentText("This is a notification!!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(2, n); - } - }, + new Test("Vibrate and cancel") { + public void run() + { + NotificationChannel channel = new NotificationChannel("vibrate", + "vibrate", IMPORTANCE_DEFAULT); + channel.enableVibration(true); + channel.setVibrationPattern(new long[] {0, 700, 500, 1000, 0, 700, 500, 1000, + 0, 700, 500, 1000, 0, 700, 500, 1000, 0, 700, 500, 1000, 0, 700, 500, 1000, + 0, 700, 500, 1000, 0, 700, 500, 1000}); + mNM.createNotificationChannel(channel); + + Notification n = new Notification.Builder(NotificationTestList.this, "vibrate") + .setSmallIcon(R.drawable.stat_sys_phone) + .setContentTitle(name) + .build(); - new Test("Persistent #3") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setContentText("This is a notification!!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(3, n); - } - }, + mNM.notify(1, n); + SystemClock.sleep(500); + mNM.cancel(1); + } + }, - new Test("Persistent #2 Vibrate") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon1) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setContentText("This is a notification!!!") - .setContentIntent(makeIntent()) - .setDefaults(Notification.DEFAULT_VIBRATE) - .build(); - mNM.notify(2, n); - } - }, + new Test("Vibrate pattern") { + public void run() + { + mVibrator.vibrate(new long[] { 250, 1000, 500, 2000 }, -1); + } + }, - new Test("Persistent #1 - different icon") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon2) - .setWhen(mActivityCreateTime) - .setContentTitle(name) - .setContentText("This is a notification!!!") - .setContentIntent(makeIntent()) - .build(); - mNM.notify(1, n); - } - }, + new Test("Vibrate pattern repeating") { + public void run() + { + mVibrator.vibrate(new long[] { 250, 1000, 500 }, 1); + } + }, - new Test("Chronometer Start") { - public void run() { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(R.drawable.icon1) - .setWhen(System.currentTimeMillis()) - .setContentTitle(name) - .setContentIntent(makeIntent()) - .setOngoing(true) - .setUsesChronometer(true) - .build(); - mNM.notify(2, n); - } - }, + new Test("Vibrate 3s") { + public void run() + { + mVibrator.vibrate(3000); + } + }, - new Test("Chronometer Stop") { - public void run() { - mHandler.postDelayed(new Runnable() { + new Test("Vibrate 100s") { + public void run() + { + mVibrator.vibrate(100000); + } + }, + + new Test("Vibrate off") { + public void run() + { + mVibrator.cancel(); + } + }, + + new Test("Cancel #1") { + public void run() { + mNM.cancel(1); + } + }, + + new Test("Cancel #1 in 3 sec") { + public void run() { + mHandler.postDelayed(new Runnable() { + public void run() { + Log.d(TAG, "Cancelling now..."); + mNM.cancel(1); + } + }, 3000); + } + }, + + new Test("Cancel #2") { + public void run() { + mNM.cancel(2); + } + }, + + new Test("Persistent #1") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this) + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setContentText("This is a notification!!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(1, n); + } + }, + + new Test("Persistent #1 in 3 sec") { + public void run() { + mHandler.postDelayed(new Runnable() { + public void run() { + String message = " " + + "tick tock tick tock\n\nSometimes notifications can " + + "be really long and wrap to more than one line.\n" + + "Sometimes." + + "Ohandwhathappensifwehaveonereallylongstringarewesure" + + "thatwesegmentitcorrectly?\n"; + Notification n = new Notification.Builder( + NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon1) + .setContentTitle(name) + .setContentText("This is still a notification!!!") + .setContentIntent(makeIntent()) + .setStyle(new Notification.BigTextStyle().bigText(message)) + .build(); + mNM.notify(1, n); + } + }, 3000); + } + }, + + new Test("Persistent #2") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setContentText("This is a notification!!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(2, n); + } + }, + + new Test("Persistent #3") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setContentText("This is a notification!!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(3, n); + } + }, + + new Test("Persistent #2 Vibrate") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon1) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setContentText("This is a notification!!!") + .setContentIntent(makeIntent()) + .setDefaults(Notification.DEFAULT_VIBRATE) + .build(); + mNM.notify(2, n); + } + }, + + new Test("Persistent #1 - different icon") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon2) + .setWhen(mActivityCreateTime) + .setContentTitle(name) + .setContentText("This is a notification!!!") + .setContentIntent(makeIntent()) + .build(); + mNM.notify(1, n); + } + }, + + new Test("Chronometer Start") { + public void run() { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(R.drawable.icon1) + .setWhen(System.currentTimeMillis()) + .setContentTitle(name) + .setContentIntent(makeIntent()) + .setOngoing(true) + .setUsesChronometer(true) + .build(); + mNM.notify(2, n); + } + }, + + new Test("Chronometer Stop") { + public void run() { + mHandler.postDelayed(new Runnable() { public void run() { Log.d(TAG, "Chronometer Stop"); Notification n = new Notification.Builder( @@ -1024,121 +1024,121 @@ public class NotificationTestList extends TestActivity mNM.notify(2, n); } }, 3000); - } - }, + } + }, - new Test("Sequential Persistent") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 1)); - mNM.notify(2, notificationWithNumbers(name, 2)); - } - }, + new Test("Sequential Persistent") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 1)); + mNM.notify(2, notificationWithNumbers(name, 2)); + } + }, - new Test("Replace Persistent") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 1)); - mNM.notify(1, notificationWithNumbers(name, 1)); - } - }, + new Test("Replace Persistent") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 1)); + mNM.notify(1, notificationWithNumbers(name, 1)); + } + }, - new Test("Run and Cancel (n=1)") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 1)); - mNM.cancel(1); - } - }, + new Test("Run and Cancel (n=1)") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 1)); + mNM.cancel(1); + } + }, - new Test("Run an Cancel (n=2)") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 1)); - mNM.notify(2, notificationWithNumbers(name, 2)); - mNM.cancel(2); - } - }, + new Test("Run an Cancel (n=2)") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 1)); + mNM.notify(2, notificationWithNumbers(name, 2)); + mNM.cancel(2); + } + }, - // Repeatedly notify and cancel -- triggers bug #670627 - new Test("Bug 670627") { - public void run() { - for (int i = 0; i < 10; i++) { - Log.d(TAG, "Add two notifications"); - mNM.notify(1, notificationWithNumbers(name, 1)); - mNM.notify(2, notificationWithNumbers(name, 2)); - Log.d(TAG, "Cancel two notifications"); - mNM.cancel(1); - mNM.cancel(2); + // Repeatedly notify and cancel -- triggers bug #670627 + new Test("Bug 670627") { + public void run() { + for (int i = 0; i < 10; i++) { + Log.d(TAG, "Add two notifications"); + mNM.notify(1, notificationWithNumbers(name, 1)); + mNM.notify(2, notificationWithNumbers(name, 2)); + Log.d(TAG, "Cancel two notifications"); + mNM.cancel(1); + mNM.cancel(2); + } } - } - }, + }, - new Test("Ten Notifications") { - public void run() { - for (int i = 0; i < 10; i++) { - Notification n = new Notification.Builder(NotificationTestList.this, "low") - .setSmallIcon(kNumberedIconResIDs[i]) - .setContentTitle("Persistent #" + i) - .setContentText("Notify me!!!" + i) - .setOngoing(i < 2) - .setNumber(i) - .build(); - mNM.notify((i+1)*10, n); + new Test("Ten Notifications") { + public void run() { + for (int i = 0; i < 10; i++) { + Notification n = new Notification.Builder(NotificationTestList.this, "low") + .setSmallIcon(kNumberedIconResIDs[i]) + .setContentTitle("Persistent #" + i) + .setContentText("Notify me!!!" + i) + .setOngoing(i < 2) + .setNumber(i) + .build(); + mNM.notify((i+1)*10, n); + } } - } - }, - - new Test("Cancel eight notifications") { - public void run() { - for (int i = 1; i < 9; i++) { - mNM.cancel((i+1)*10); + }, + + new Test("Cancel eight notifications") { + public void run() { + for (int i = 1; i < 9; i++) { + mNM.cancel((i+1)*10); + } } - } - }, - - new Test("Cancel the other two notifications") { - public void run() { - mNM.cancel(10); - mNM.cancel(100); - } - }, - - new Test("Persistent with numbers 1") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 1)); - } - }, + }, - new Test("Persistent with numbers 22") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 22)); - } - }, + new Test("Cancel the other two notifications") { + public void run() { + mNM.cancel(10); + mNM.cancel(100); + } + }, - new Test("Persistent with numbers 333") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 333)); - } - }, + new Test("Persistent with numbers 1") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 1)); + } + }, - new Test("Persistent with numbers 4444") { - public void run() { - mNM.notify(1, notificationWithNumbers(name, 4444)); - } - }, - - new Test("Crash") { - public void run() - { - PowerManager.WakeLock wl = - ((PowerManager) NotificationTestList.this.getSystemService(Context.POWER_SERVICE)) - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher"); - wl.acquire(); - mHandler.postDelayed(new Runnable() { - public void run() { - throw new RuntimeException("Die!"); - } - }, 10000); + new Test("Persistent with numbers 22") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 22)); + } + }, - } - }, + new Test("Persistent with numbers 333") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 333)); + } + }, + + new Test("Persistent with numbers 4444") { + public void run() { + mNM.notify(1, notificationWithNumbers(name, 4444)); + } + }, + + new Test("Crash") { + public void run() + { + PowerManager.WakeLock wl = + ((PowerManager) NotificationTestList.this.getSystemService(Context.POWER_SERVICE)) + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher"); + wl.acquire(); + mHandler.postDelayed(new Runnable() { + public void run() { + throw new RuntimeException("Die!"); + } + }, 10000); + + } + }, }; @@ -1212,4 +1212,3 @@ public class NotificationTestList extends TestActivity return Bitmap.createBitmap(bd.getBitmap()); } } - |