diff options
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()); } } - |