Loading core/java/android/app/Notification.java +4 −18 Original line number Diff line number Diff line Loading @@ -2676,7 +2676,8 @@ public class Notification implements Parcelable return true; } for (int i = 0; i < firstAs.length; i++) { if (!Objects.equals(firstAs[i].title, secondAs[i].title)) { if (!Objects.equals(String.valueOf(firstAs[i].title), String.valueOf(secondAs[i].title))) { return true; } RemoteInput[] firstRs = firstAs[i].getRemoteInputs(); Loading @@ -2691,25 +2692,10 @@ public class Notification implements Parcelable return true; } for (int j = 0; j < firstRs.length; j++) { if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) { if (!Objects.equals(String.valueOf(firstRs[j].getLabel()), String.valueOf(secondRs[j].getLabel()))) { return true; } CharSequence[] firstCs = firstRs[j].getChoices(); CharSequence[] secondCs = secondRs[j].getChoices(); if (firstCs == null) { firstCs = new CharSequence[0]; } if (secondCs == null) { secondCs = new CharSequence[0]; } if (firstCs.length != secondCs.length) { return true; } for (int k = 0; k < firstCs.length; k++) { if (!Objects.equals(firstCs[k], secondCs[k])) { return true; } } } } } Loading services/core/java/com/android/server/notification/NotificationManagerService.java +19 −2 Original line number Diff line number Diff line Loading @@ -4443,7 +4443,7 @@ public class NotificationManagerService extends SystemService { if (index < 0) { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); r.setInterruptive(true); r.setInterruptive(isVisuallyInterruptive(null, r)); } else { old = mNotificationList.get(index); mNotificationList.set(index, r); Loading Loading @@ -4530,6 +4530,14 @@ public class NotificationManagerService extends SystemService { return true; } if (r == null) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " + r.getKey() + " is not interruptive: null"); } return false; } Notification oldN = old.sbn.getNotification(); Notification newN = r.sbn.getNotification(); Loading @@ -4543,7 +4551,7 @@ public class NotificationManagerService extends SystemService { // Ignore visual interruptions from foreground services because users // consider them one 'session'. Count them for everything else. if (r != null && (r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " + r.getKey() + " is not interruptive: foreground service"); Loading @@ -4551,6 +4559,15 @@ public class NotificationManagerService extends SystemService { return false; } // Ignore summary updates because we don't display most of the information. if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " + r.getKey() + " is not interruptive: summary"); } return false; } final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); if (!Objects.equals(oldTitle, newTitle)) { Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -2918,6 +2918,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertFalse(mService.isVisuallyInterruptive(r1, r2)); } @Test public void testVisualDifference_summary() { Notification.Builder nb1 = new Notification.Builder(mContext, "") .setGroup("bananas") .setFlag(Notification.FLAG_GROUP_SUMMARY, true) .setContentText("foo"); StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, nb1.build(), new UserHandle(mUid), null, 0); NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); Notification.Builder nb2 = new Notification.Builder(mContext, "") .setGroup("bananas") .setFlag(Notification.FLAG_GROUP_SUMMARY, true) .setContentText("bar"); StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, nb2.build(), new UserHandle(mUid), null, 0); NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); assertFalse(mService.isVisuallyInterruptive(r1, r2)); } @Test public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { // post 2 notification from this package Loading services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java +22 −21 Original line number Diff line number Diff line Loading @@ -39,11 +39,15 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.StyleSpan; import android.widget.RemoteViews; import com.android.server.UiServiceTestCase; Loading Loading @@ -465,61 +469,58 @@ public class NotificationTest extends UiServiceTestCase { } @Test public void testActionsDifferentNumber() { public void testActionsDifferentSpannables() { PendingIntent intent = mock(PendingIntent.class); Icon icon = mock(Icon.class); Notification n1 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .addAction(new Notification.Action.Builder(icon, new SpannableStringBuilder().append("test1", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE), intent).build()) .build(); Notification n2 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) .addAction(new Notification.Action.Builder(icon, "test1", intent).build()) .build(); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); } @Test public void testActionsDifferentIntent() { PendingIntent intent1 = mock(PendingIntent.class); PendingIntent intent2 = mock(PendingIntent.class); public void testActionsDifferentNumber() { PendingIntent intent = mock(PendingIntent.class); Icon icon = mock(Icon.class); Notification n1 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .build(); Notification n2 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) .build(); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); } @Test public void testActionsMoreOptionsThanChoices() { public void testActionsDifferentIntent() { PendingIntent intent1 = mock(PendingIntent.class); PendingIntent intent2 = mock(PendingIntent.class); Icon icon = mock(Icon.class); Notification n1 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1) .addRemoteInput(new RemoteInput.Builder("a") .setChoices(new CharSequence[] {"i", "m"}) .build()) .build()) .build(); Notification n2 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1).build()) .build(); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); } @Test public void testActionsDifferentRemoteInputs() { public void testActionsIgnoresRemoteInputs() { PendingIntent intent = mock(PendingIntent.class); Icon icon = mock(Icon.class); Loading @@ -538,7 +539,7 @@ public class NotificationTest extends UiServiceTestCase { .build()) .build(); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); } } Loading
core/java/android/app/Notification.java +4 −18 Original line number Diff line number Diff line Loading @@ -2676,7 +2676,8 @@ public class Notification implements Parcelable return true; } for (int i = 0; i < firstAs.length; i++) { if (!Objects.equals(firstAs[i].title, secondAs[i].title)) { if (!Objects.equals(String.valueOf(firstAs[i].title), String.valueOf(secondAs[i].title))) { return true; } RemoteInput[] firstRs = firstAs[i].getRemoteInputs(); Loading @@ -2691,25 +2692,10 @@ public class Notification implements Parcelable return true; } for (int j = 0; j < firstRs.length; j++) { if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) { if (!Objects.equals(String.valueOf(firstRs[j].getLabel()), String.valueOf(secondRs[j].getLabel()))) { return true; } CharSequence[] firstCs = firstRs[j].getChoices(); CharSequence[] secondCs = secondRs[j].getChoices(); if (firstCs == null) { firstCs = new CharSequence[0]; } if (secondCs == null) { secondCs = new CharSequence[0]; } if (firstCs.length != secondCs.length) { return true; } for (int k = 0; k < firstCs.length; k++) { if (!Objects.equals(firstCs[k], secondCs[k])) { return true; } } } } } Loading
services/core/java/com/android/server/notification/NotificationManagerService.java +19 −2 Original line number Diff line number Diff line Loading @@ -4443,7 +4443,7 @@ public class NotificationManagerService extends SystemService { if (index < 0) { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); r.setInterruptive(true); r.setInterruptive(isVisuallyInterruptive(null, r)); } else { old = mNotificationList.get(index); mNotificationList.set(index, r); Loading Loading @@ -4530,6 +4530,14 @@ public class NotificationManagerService extends SystemService { return true; } if (r == null) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " + r.getKey() + " is not interruptive: null"); } return false; } Notification oldN = old.sbn.getNotification(); Notification newN = r.sbn.getNotification(); Loading @@ -4543,7 +4551,7 @@ public class NotificationManagerService extends SystemService { // Ignore visual interruptions from foreground services because users // consider them one 'session'. Count them for everything else. if (r != null && (r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " + r.getKey() + " is not interruptive: foreground service"); Loading @@ -4551,6 +4559,15 @@ public class NotificationManagerService extends SystemService { return false; } // Ignore summary updates because we don't display most of the information. if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) { if (DEBUG_INTERRUPTIVENESS) { Log.v(TAG, "INTERRUPTIVENESS: " + r.getKey() + " is not interruptive: summary"); } return false; } final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE)); final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE)); if (!Objects.equals(oldTitle, newTitle)) { Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -2918,6 +2918,29 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertFalse(mService.isVisuallyInterruptive(r1, r2)); } @Test public void testVisualDifference_summary() { Notification.Builder nb1 = new Notification.Builder(mContext, "") .setGroup("bananas") .setFlag(Notification.FLAG_GROUP_SUMMARY, true) .setContentText("foo"); StatusBarNotification sbn1 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, nb1.build(), new UserHandle(mUid), null, 0); NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); Notification.Builder nb2 = new Notification.Builder(mContext, "") .setGroup("bananas") .setFlag(Notification.FLAG_GROUP_SUMMARY, true) .setContentText("bar"); StatusBarNotification sbn2 = new StatusBarNotification(PKG, PKG, 0, "tag", mUid, 0, nb2.build(), new UserHandle(mUid), null, 0); NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); assertFalse(mService.isVisuallyInterruptive(r1, r2)); } @Test public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { // post 2 notification from this package Loading
services/tests/uiservicestests/src/com/android/server/notification/NotificationTest.java +22 −21 Original line number Diff line number Diff line Loading @@ -39,11 +39,15 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Typeface; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Build; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.StyleSpan; import android.widget.RemoteViews; import com.android.server.UiServiceTestCase; Loading Loading @@ -465,61 +469,58 @@ public class NotificationTest extends UiServiceTestCase { } @Test public void testActionsDifferentNumber() { public void testActionsDifferentSpannables() { PendingIntent intent = mock(PendingIntent.class); Icon icon = mock(Icon.class); Notification n1 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .addAction(new Notification.Action.Builder(icon, new SpannableStringBuilder().append("test1", new StyleSpan(Typeface.BOLD), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE), intent).build()) .build(); Notification n2 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) .addAction(new Notification.Action.Builder(icon, "test1", intent).build()) .build(); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); } @Test public void testActionsDifferentIntent() { PendingIntent intent1 = mock(PendingIntent.class); PendingIntent intent2 = mock(PendingIntent.class); public void testActionsDifferentNumber() { PendingIntent intent = mock(PendingIntent.class); Icon icon = mock(Icon.class); Notification n1 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .build(); Notification n2 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build()) .build(); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); } @Test public void testActionsMoreOptionsThanChoices() { public void testActionsDifferentIntent() { PendingIntent intent1 = mock(PendingIntent.class); PendingIntent intent2 = mock(PendingIntent.class); Icon icon = mock(Icon.class); Notification n1 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent1).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1) .addRemoteInput(new RemoteInput.Builder("a") .setChoices(new CharSequence[] {"i", "m"}) .build()) .build()) .build(); Notification n2 = new Notification.Builder(mContext, "test") .addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build()) .addAction(new Notification.Action.Builder(icon, "TEXT 2", intent1).build()) .build(); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); } @Test public void testActionsDifferentRemoteInputs() { public void testActionsIgnoresRemoteInputs() { PendingIntent intent = mock(PendingIntent.class); Icon icon = mock(Icon.class); Loading @@ -538,7 +539,7 @@ public class NotificationTest extends UiServiceTestCase { .build()) .build(); assertTrue(Notification.areActionsVisiblyDifferent(n1, n2)); assertFalse(Notification.areActionsVisiblyDifferent(n1, n2)); } }