Merge "Log visual interruptions to usagestats." into pi-dev
am: 1c7c2bdd0b
Change-Id: I3a6497fbdddc5f728c5702f1a60e479d99fd7277
This commit is contained in:
@@ -5401,6 +5401,7 @@ package android.app {
|
||||
method public android.app.Notification.Builder extend(android.app.Notification.Extender);
|
||||
method public android.os.Bundle getExtras();
|
||||
method public deprecated android.app.Notification getNotification();
|
||||
method public android.app.Notification.Style getStyle();
|
||||
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
|
||||
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
|
||||
method public android.app.Notification.Builder setAutoCancel(boolean);
|
||||
|
||||
@@ -89,6 +89,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -2598,6 +2599,80 @@ public class Notification implements Parcelable
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static boolean areActionsVisiblyDifferent(Notification first, Notification second) {
|
||||
Notification.Action[] firstAs = first.actions;
|
||||
Notification.Action[] secondAs = second.actions;
|
||||
if (firstAs == null && secondAs != null || firstAs != null && secondAs == null) {
|
||||
return true;
|
||||
}
|
||||
if (firstAs != null && secondAs != null) {
|
||||
if (firstAs.length != secondAs.length) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < firstAs.length; i++) {
|
||||
if (!Objects.equals(firstAs[i].title, secondAs[i].title)) {
|
||||
return true;
|
||||
}
|
||||
RemoteInput[] firstRs = firstAs[i].getRemoteInputs();
|
||||
RemoteInput[] secondRs = secondAs[i].getRemoteInputs();
|
||||
if (firstRs == null) {
|
||||
firstRs = new RemoteInput[0];
|
||||
}
|
||||
if (secondRs == null) {
|
||||
secondRs = new RemoteInput[0];
|
||||
}
|
||||
if (firstRs.length != secondRs.length) {
|
||||
return true;
|
||||
}
|
||||
for (int j = 0; j < firstRs.length; j++) {
|
||||
if (!Objects.equals(firstRs[j].getLabel(), secondRs[j].getLabel())) {
|
||||
return true;
|
||||
}
|
||||
CharSequence[] firstCs = firstRs[i].getChoices();
|
||||
CharSequence[] secondCs = secondRs[i].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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static boolean areStyledNotificationsVisiblyDifferent(Builder first, Builder second) {
|
||||
if (first.getStyle() == null) {
|
||||
return second.getStyle() != null;
|
||||
}
|
||||
if (second.getStyle() == null) {
|
||||
return true;
|
||||
}
|
||||
return first.getStyle().areNotificationsVisiblyDifferent(second.getStyle());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static boolean areRemoteViewsChanged(Builder first, Builder second) {
|
||||
return !first.usesStandardHeader() || !second.usesStandardHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcelling creates multiple copies of objects in {@code extras}. Fix them.
|
||||
* <p>
|
||||
@@ -4038,6 +4113,13 @@ public class Notification implements Parcelable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the style set by {@link #setStyle(Style)}.
|
||||
*/
|
||||
public Style getStyle() {
|
||||
return mStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the value of {@link #visibility}.
|
||||
*
|
||||
@@ -5867,6 +5949,11 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
public void validate(Context context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract boolean areNotificationsVisiblyDifferent(Style other);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5919,6 +6006,13 @@ public class Notification implements Parcelable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Bitmap getBigPicture() {
|
||||
return mPicture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the bitmap to be used as the payload for the BigPicture notification.
|
||||
*/
|
||||
@@ -6059,6 +6153,18 @@ public class Notification implements Parcelable
|
||||
public boolean hasSummaryInHeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
BigPictureStyle otherS = (BigPictureStyle) other;
|
||||
return !Objects.equals(getBigPicture(), otherS.getBigPicture());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6119,6 +6225,13 @@ public class Notification implements Parcelable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public CharSequence getBigText() {
|
||||
return mBigText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -6191,6 +6304,18 @@ public class Notification implements Parcelable
|
||||
return contentView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
BigTextStyle newS = (BigTextStyle) other;
|
||||
return !Objects.equals(getBigText(), newS.getBigText());
|
||||
}
|
||||
|
||||
static void applyBigTextContentView(Builder builder,
|
||||
RemoteViews contentView, CharSequence bigTextText) {
|
||||
contentView.setTextViewText(R.id.big_text, builder.processTextSpans(bigTextText));
|
||||
@@ -6533,6 +6658,58 @@ public class Notification implements Parcelable
|
||||
return remoteViews;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
MessagingStyle newS = (MessagingStyle) other;
|
||||
List<MessagingStyle.Message> oldMs = getMessages();
|
||||
List<MessagingStyle.Message> newMs = newS.getMessages();
|
||||
|
||||
if (oldMs == null) {
|
||||
oldMs = new ArrayList<>();
|
||||
}
|
||||
if (newMs == null) {
|
||||
newMs = new ArrayList<>();
|
||||
}
|
||||
|
||||
int n = oldMs.size();
|
||||
if (n != newMs.size()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
MessagingStyle.Message oldM = oldMs.get(i);
|
||||
MessagingStyle.Message newM = newMs.get(i);
|
||||
if (!Objects.equals(oldM.getText(), newM.getText())) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(oldM.getDataUri(), newM.getDataUri())) {
|
||||
return true;
|
||||
}
|
||||
CharSequence oldSender = oldM.getSenderPerson() == null ? oldM.getSender()
|
||||
: oldM.getSenderPerson().getName();
|
||||
CharSequence newSender = newM.getSenderPerson() == null ? newM.getSender()
|
||||
: newM.getSenderPerson().getName();
|
||||
if (!Objects.equals(oldSender, newSender)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String oldKey = oldM.getSenderPerson() == null
|
||||
? null : oldM.getSenderPerson().getKey();
|
||||
String newKey = newM.getSenderPerson() == null
|
||||
? null : newM.getSenderPerson().getKey();
|
||||
if (!Objects.equals(oldKey, newKey)) {
|
||||
return true;
|
||||
}
|
||||
// Other fields (like timestamp) intentionally excluded
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Message findLatestIncomingMessage() {
|
||||
return findLatestIncomingMessage(mMessages);
|
||||
}
|
||||
@@ -6961,6 +7138,13 @@ public class Notification implements Parcelable
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ArrayList<CharSequence> getLines() {
|
||||
return mTexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -7042,6 +7226,18 @@ public class Notification implements Parcelable
|
||||
return contentView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
InboxStyle newS = (InboxStyle) other;
|
||||
return !Objects.equals(getLines(), newS.getLines());
|
||||
}
|
||||
|
||||
private void handleInboxImageMargin(RemoteViews contentView, int id, boolean first) {
|
||||
int endMargin = 0;
|
||||
if (first) {
|
||||
@@ -7205,6 +7401,18 @@ public class Notification implements Parcelable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
// All fields to compare are on the Notification object
|
||||
return false;
|
||||
}
|
||||
|
||||
private RemoteViews generateMediaActionButton(Action action, int color) {
|
||||
final boolean tombstone = (action.actionIntent == null);
|
||||
RemoteViews button = new BuilderRemoteViews(mBuilder.mContext.getApplicationInfo(),
|
||||
@@ -7414,6 +7622,18 @@ public class Notification implements Parcelable
|
||||
}
|
||||
remoteViews.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
// Comparison done for all custom RemoteViews, independent of style
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7504,6 +7724,18 @@ public class Notification implements Parcelable
|
||||
return makeBigContentViewWithCustomContent(customRemoteView);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public boolean areNotificationsVisiblyDifferent(Style other) {
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return true;
|
||||
}
|
||||
// Comparison done for all custom RemoteViews, independent of style
|
||||
return false;
|
||||
}
|
||||
|
||||
private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
|
||||
RemoteViews customContent) {
|
||||
if (customContent != null) {
|
||||
|
||||
@@ -1294,7 +1294,8 @@ public class NotificationManagerService extends SystemService {
|
||||
NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
|
||||
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
|
||||
NotificationUsageStats usageStats, AtomicFile policyFile,
|
||||
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am) {
|
||||
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
|
||||
UsageStatsManagerInternal appUsageStats) {
|
||||
Resources resources = getContext().getResources();
|
||||
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
|
||||
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
|
||||
@@ -1307,7 +1308,7 @@ public class NotificationManagerService extends SystemService {
|
||||
mPackageManagerClient = packageManagerClient;
|
||||
mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
|
||||
mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||
mAppUsageStats = appUsageStats;
|
||||
mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
mCompanionManager = companionManager;
|
||||
mActivityManager = activityManager;
|
||||
@@ -1449,7 +1450,8 @@ public class NotificationManagerService extends SystemService {
|
||||
null, snoozeHelper, new NotificationUsageStats(getContext()),
|
||||
new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
|
||||
(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
|
||||
getGroupHelper(), ActivityManager.getService());
|
||||
getGroupHelper(), ActivityManager.getService(),
|
||||
LocalServices.getService(UsageStatsManagerInternal.class));
|
||||
|
||||
// register for various Intents
|
||||
IntentFilter filter = new IntentFilter();
|
||||
@@ -4300,6 +4302,7 @@ public class NotificationManagerService extends SystemService {
|
||||
if (index < 0) {
|
||||
mNotificationList.add(r);
|
||||
mUsageStats.registerPostedByApp(r);
|
||||
r.setInterruptive(true);
|
||||
} else {
|
||||
old = mNotificationList.get(index);
|
||||
mNotificationList.set(index, r);
|
||||
@@ -4310,6 +4313,7 @@ public class NotificationManagerService extends SystemService {
|
||||
// revoke uri permissions for changed uris
|
||||
revokeUriPermissions(r, old);
|
||||
r.isUpdate = true;
|
||||
r.setInterruptive(isVisuallyInterruptive(old, r));
|
||||
}
|
||||
|
||||
mNotificationsByKey.put(n.getKey(), r);
|
||||
@@ -4375,6 +4379,52 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the notification differs enough visually, consider it a new interruptive notification.
|
||||
*/
|
||||
@GuardedBy("mNotificationLock")
|
||||
@VisibleForTesting
|
||||
protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
|
||||
Notification oldN = old.sbn.getNotification();
|
||||
Notification newN = r.sbn.getNotification();
|
||||
if (oldN.extras == null || newN.extras == null) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TITLE),
|
||||
newN.extras.get(Notification.EXTRA_TITLE))) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(oldN.extras.get(Notification.EXTRA_TEXT),
|
||||
newN.extras.get(Notification.EXTRA_TEXT))) {
|
||||
return true;
|
||||
}
|
||||
if (oldN.extras.containsKey(Notification.EXTRA_PROGRESS) && newN.hasCompletedProgress()) {
|
||||
return true;
|
||||
}
|
||||
// Actions
|
||||
if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
|
||||
Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
|
||||
|
||||
// Style based comparisons
|
||||
if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remote views
|
||||
if (Notification.areRemoteViewsChanged(oldB, newB)) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.w(TAG, "error recovering builder", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps the last 5 packages that have notified, by user.
|
||||
*/
|
||||
|
||||
@@ -68,6 +68,7 @@ import android.app.Notification.MessagingStyle.Message;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationChannelGroup;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.companion.ICompanionDeviceManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -264,7 +265,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
mPackageManager, mPackageManagerClient, mockLightsManager,
|
||||
mListeners, mAssistants, mConditionProviders,
|
||||
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
|
||||
mGroupHelper, mAm);
|
||||
mGroupHelper, mAm, mock(UsageStatsManagerInternal.class));
|
||||
} catch (SecurityException e) {
|
||||
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
|
||||
throw e;
|
||||
@@ -2662,4 +2663,80 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
|
||||
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVisualDifference_diffTitle() {
|
||||
Notification.Builder nb1 = new Notification.Builder(mContext, "")
|
||||
.setContentTitle("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, "")
|
||||
.setContentTitle("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));
|
||||
|
||||
assertTrue(mService.isVisuallyInterruptive(r1, r2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVisualDifference_diffText() {
|
||||
Notification.Builder nb1 = new Notification.Builder(mContext, "")
|
||||
.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, "")
|
||||
.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));
|
||||
|
||||
assertTrue(mService.isVisuallyInterruptive(r1, r2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVisualDifference_diffProgress() {
|
||||
Notification.Builder nb1 = new Notification.Builder(mContext, "")
|
||||
.setProgress(100, 90, false);
|
||||
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, "")
|
||||
.setProgress(100, 100, false);
|
||||
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));
|
||||
|
||||
assertTrue(mService.isVisuallyInterruptive(r1, r2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVisualDifference_diffProgressNotDone() {
|
||||
Notification.Builder nb1 = new Notification.Builder(mContext, "")
|
||||
.setProgress(100, 90, false);
|
||||
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, "")
|
||||
.setProgress(100, 91, false);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,18 +20,27 @@ import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Notification;
|
||||
import android.app.Notification.Person;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.RemoteInput;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
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.widget.RemoteViews;
|
||||
|
||||
import com.android.server.UiServiceTestCase;
|
||||
|
||||
@@ -112,5 +121,272 @@ public class NotificationTest extends UiServiceTestCase {
|
||||
assertEquals(Color.RED, new Notification.CarExtender(before).getColor());
|
||||
assertEquals("dismiss", new Notification.WearableExtender(before).getDismissalId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStyleChangeVisiblyDifferent_noStyles() {
|
||||
Notification.Builder n1 = new Notification.Builder(mContext, "test");
|
||||
Notification.Builder n2 = new Notification.Builder(mContext, "test");
|
||||
|
||||
assertFalse(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStyleChangeVisiblyDifferent_noStyleToStyle() {
|
||||
Notification.Builder n1 = new Notification.Builder(mContext, "test");
|
||||
Notification.Builder n2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigTextStyle());
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStyleChangeVisiblyDifferent_styleToNoStyle() {
|
||||
Notification.Builder n2 = new Notification.Builder(mContext, "test");
|
||||
Notification.Builder n1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigTextStyle());
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStyleChangeVisiblyDifferent_changeStyle() {
|
||||
Notification.Builder n1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.InboxStyle());
|
||||
Notification.Builder n2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigTextStyle());
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInboxTextChange() {
|
||||
Notification.Builder nInbox1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.InboxStyle().addLine("a").addLine("b"));
|
||||
Notification.Builder nInbox2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.InboxStyle().addLine("b").addLine("c"));
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nInbox1, nInbox2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigTextTextChange() {
|
||||
Notification.Builder nBigText1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigTextStyle().bigText("something"));
|
||||
Notification.Builder nBigText2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigTextStyle().bigText("else"));
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigText1, nBigText2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBigPictureChange() {
|
||||
Notification.Builder nBigPic1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigPictureStyle().bigPicture(mock(Bitmap.class)));
|
||||
Notification.Builder nBigPic2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.BigPictureStyle().bigPicture(mock(Bitmap.class)));
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nBigPic1, nBigPic2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagingChange_text() {
|
||||
Notification.Builder nM1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"a", 100, mock(Notification.Person.class))));
|
||||
Notification.Builder nM2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"a", 100, mock(Notification.Person.class)))
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"b", 100, mock(Notification.Person.class)))
|
||||
);
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagingChange_data() {
|
||||
Notification.Builder nM1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"a", 100, mock(Person.class))
|
||||
.setData("text", mock(Uri.class))));
|
||||
Notification.Builder nM2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"a", 100, mock(Person.class))));
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagingChange_sender() {
|
||||
Person a = mock(Person.class);
|
||||
when(a.getName()).thenReturn("A");
|
||||
Person b = mock(Person.class);
|
||||
when(b.getName()).thenReturn("b");
|
||||
Notification.Builder nM1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message("a", 100, b)));
|
||||
Notification.Builder nM2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message("a", 100, a)));
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagingChange_key() {
|
||||
Person a = mock(Person.class);
|
||||
when(a.getKey()).thenReturn("A");
|
||||
Person b = mock(Person.class);
|
||||
when(b.getKey()).thenReturn("b");
|
||||
Notification.Builder nM1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message("a", 100, a)));
|
||||
Notification.Builder nM2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message("a", 100, b)));
|
||||
|
||||
assertTrue(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagingChange_ignoreTimeChange() {
|
||||
Notification.Builder nM1 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"a", 100, mock(Notification.Person.class))));
|
||||
Notification.Builder nM2 = new Notification.Builder(mContext, "test")
|
||||
.setStyle(new Notification.MessagingStyle("")
|
||||
.addMessage(new Notification.MessagingStyle.Message(
|
||||
"a", 1000, mock(Notification.Person.class)))
|
||||
);
|
||||
|
||||
assertFalse(Notification.areStyledNotificationsVisiblyDifferent(nM1, nM2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteViews_nullChange() {
|
||||
Notification.Builder n1 = new Notification.Builder(mContext, "test")
|
||||
.setContent(mock(RemoteViews.class));
|
||||
Notification.Builder n2 = new Notification.Builder(mContext, "test");
|
||||
assertTrue(Notification.areRemoteViewsChanged(n1, n2));
|
||||
|
||||
n1 = new Notification.Builder(mContext, "test");
|
||||
n2 = new Notification.Builder(mContext, "test")
|
||||
.setContent(mock(RemoteViews.class));
|
||||
assertTrue(Notification.areRemoteViewsChanged(n1, n2));
|
||||
|
||||
n1 = new Notification.Builder(mContext, "test")
|
||||
.setCustomBigContentView(mock(RemoteViews.class));
|
||||
n2 = new Notification.Builder(mContext, "test");
|
||||
assertTrue(Notification.areRemoteViewsChanged(n1, n2));
|
||||
|
||||
n1 = new Notification.Builder(mContext, "test");
|
||||
n2 = new Notification.Builder(mContext, "test")
|
||||
.setCustomBigContentView(mock(RemoteViews.class));
|
||||
assertTrue(Notification.areRemoteViewsChanged(n1, n2));
|
||||
|
||||
n1 = new Notification.Builder(mContext, "test");
|
||||
n2 = new Notification.Builder(mContext, "test");
|
||||
assertFalse(Notification.areRemoteViewsChanged(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionsDifferent_null() {
|
||||
Notification n1 = new Notification.Builder(mContext, "test")
|
||||
.build();
|
||||
Notification n2 = new Notification.Builder(mContext, "test")
|
||||
.build();
|
||||
|
||||
assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionsDifferentSame() {
|
||||
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())
|
||||
.build();
|
||||
Notification n2 = new Notification.Builder(mContext, "test")
|
||||
.addAction(new Notification.Action.Builder(icon, "TEXT 1", intent).build())
|
||||
.build();
|
||||
|
||||
assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionsDifferentText() {
|
||||
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())
|
||||
.build();
|
||||
Notification n2 = new Notification.Builder(mContext, "test")
|
||||
.addAction(new Notification.Action.Builder(icon, "TEXT 2", intent).build())
|
||||
.build();
|
||||
|
||||
assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
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", 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())
|
||||
.build();
|
||||
|
||||
assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
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())
|
||||
.build();
|
||||
Notification n2 = new Notification.Builder(mContext, "test")
|
||||
.addAction(new Notification.Action.Builder(icon, "TEXT 1", intent2).build())
|
||||
.build();
|
||||
|
||||
assertFalse(Notification.areActionsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testActionsDifferentRemoteInputs() {
|
||||
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)
|
||||
.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", intent)
|
||||
.addRemoteInput(new RemoteInput.Builder("a")
|
||||
.setChoices(new CharSequence[] {"t", "m"})
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
assertTrue(Notification.areActionsVisiblyDifferent(n1, n2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user