Tests for delaying notification posting
Test: make cts-verifier
Change-Id: I9efb7fd738fc103843519fb425ebf82eee7e14be
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 48c4ec7..eeeffbf 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1449,6 +1449,7 @@
<string name="nls_note_received">Check that notification was received.</string>
<string name="nls_payload_intact">Check that notification payload was intact.</string>
<string name="nas_adjustment_payload_intact">Check that the Assistant can adjust notifications.</string>
+ <string name="nas_adjustment_enqueue_payload_intact">Check that the Assistant can adjust notifications on enqueue.</string>
<string name="nas_create_channel">Check that the Assistant can create a Notification Channel for another app.</string>
<string name="nas_update_channel">Check that the Assistant can update a Notification Channel for another app.</string>
<string name="nas_block_channel">Check that the Assistant can block a Notification Channel.</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java
index 1b9c914..5486911 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockAssistant.java
@@ -17,6 +17,7 @@
import android.app.Activity;
import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -34,6 +35,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
public class MockAssistant extends NotificationAssistantService {
@@ -56,6 +58,7 @@
public static final String SERVICE_UPDATE_CHANNEL = SERVICE_BASE + "UPDATE_CHANNEL";
public static final String SERVICE_DELETE_CHANNEL = SERVICE_BASE + "DELETE_CHANNEL";
public static final String SERVICE_CHECK_CHANNELS = SERVICE_BASE + "CHECK_CHANNELS";
+ public static final String SERVICE_ADJUST_ENQUEUE = SERVICE_BASE + "ADJUST_ENQUEUE";
static final String EXTRA_PAYLOAD = "PAYLOAD";
static final String EXTRA_INT = "INT";
@@ -91,6 +94,7 @@
private Set<String> mTestPackages = new HashSet<>();
private BroadcastReceiver mReceiver;
private int mDND = -1;
+ private boolean adjustEnqueue = false;
@Override
public void onCreate() {
@@ -109,35 +113,30 @@
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ Log.d(TAG, action);
if (SERVICE_CHECK.equals(action)) {
- Log.d(TAG, "SERVICE_CHECK");
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_ENQUEUED.equals(action)) {
- Log.d(TAG, "SERVICE_ENQUEUED");
Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mEnqueued);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_POSTED.equals(action)) {
- Log.d(TAG, "SERVICE_POSTED");
Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_DND.equals(action)) {
- Log.d(TAG, "SERVICE_DND");
Bundle bundle = new Bundle();
bundle.putInt(EXTRA_INT, mDND);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_ORDER.equals(action)) {
- Log.d(TAG, "SERVICE_ORDER");
Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_PAYLOADS.equals(action)) {
- Log.d(TAG, "SERVICE_PAYLOADS");
Bundle bundle = new Bundle();
ArrayList<Bundle> payloadData = new ArrayList<>(mNotifications.size());
for (Bundle notiStats : mNotifications.values()) {
@@ -147,13 +146,11 @@
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_REMOVED.equals(action)) {
- Log.d(TAG, "SERVICE_REMOVED");
Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_REMOVED_REASON.equals(action)) {
- Log.d(TAG, "SERVICE_REMOVED_REASON");
Bundle bundle = new Bundle();
ArrayList<Bundle> payloadData = new ArrayList<>(mRemovedReason.size());
for (Bundle notiStats : mRemovedReason.values()) {
@@ -163,7 +160,6 @@
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_CLEAR_ONE.equals(action)) {
- Log.d(TAG, "SERVICE_CLEAR_ONE");
String tag = intent.getStringExtra(EXTRA_TAG);
String key = mNotificationKeys.get(tag);
if (key != null) {
@@ -172,10 +168,8 @@
Log.w(TAG, "Notification does not exist: " + tag);
}
} else if (SERVICE_CLEAR_ALL.equals(action)) {
- Log.d(TAG, "SERVICE_CLEAR_ALL");
MockAssistant.this.cancelAllNotifications();
} else if (SERVICE_RESET.equals(action)) {
- Log.d(TAG, "SERVICE_RESET");
resetData();
} else if (SERVICE_ADJUSTMENT.equals(action)) {
String tag = intent.getStringExtra(EXTRA_TAG);
@@ -209,6 +203,8 @@
String pkg = intent.getStringExtra(EXTRA_PKG);
String id = intent.getStringExtra(EXTRA_TAG);
MockAssistant.this.deleteNotificationChannel(pkg, id);
+ } else if (SERVICE_ADJUST_ENQUEUE.equals(action)) {
+ adjustEnqueue = true;
} else {
Log.w(TAG, "unknown action");
setResultCode(Activity.RESULT_CANCELED);
@@ -232,6 +228,7 @@
filter.addAction(SERVICE_CREATE_CHANNEL);
filter.addAction(SERVICE_DELETE_CHANNEL);
filter.addAction(SERVICE_UPDATE_CHANNEL);
+ filter.addAction(SERVICE_ADJUST_ENQUEUE);
registerReceiver(mReceiver, filter);
}
@@ -294,11 +291,17 @@
public Adjustment onNotificationEnqueued(StatusBarNotification sbn, int importance,
boolean user) {
if (!mTestPackages.contains(sbn.getPackageName())) { return null; }
- Log.d(TAG, "posted: " + sbn.getTag());
+ Log.d(TAG, "enqueued: " + sbn.getTag());
mEnqueued.add(sbn.getTag());
- mNotifications.put(sbn.getKey(), packNotification(sbn));
- mNotificationKeys.put(sbn.getTag(), sbn.getKey());
+ if (adjustEnqueue) {
+ Map<String, Bundle> adjustments =
+ NotificationAssistantVerifierActivity.getAdjustments();
+ Bundle signals = adjustments.get(sbn.getNotification().getSortKey());
+ Adjustment adjustment = new Adjustment(sbn.getPackageName(),
+ sbn.getKey(), signals, "", 0);
+ return adjustment;
+ }
return null;
}
@@ -391,6 +394,10 @@
context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
}
+ public static void adjustEnqueue(Context context) {
+ sendCommand(context, SERVICE_ADJUST_ENQUEUE, null, 0);
+ }
+
public static void clearOne(Context context, String tag, int code) {
sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java
index 2c04b9cb..d208fba 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationAssistantVerifierActivity.java
@@ -44,6 +44,7 @@
import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
import android.service.notification.SnoozeCriterion;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -53,6 +54,7 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -106,11 +108,12 @@
tests.add(new DismissOneTest());
tests.add(new DismissOneWithReasonTest());
tests.add(new DismissAllTest());
- tests.add(new AdjustNotificationTest());
tests.add(new CreateChannelTest());
tests.add(new UpdateChannelTest());
tests.add(new DeleteChannelTest());
tests.add(new UpdateLiveChannelTest());
+ tests.add(new AdjustNotificationTest());
+ tests.add(new AdjustEnqueuedNotificationTest());
tests.add(new IsDisabledTest());
tests.add(new ServiceStoppedTest());
tests.add(new NotificationNotEnqueuedTest());
@@ -146,7 +149,8 @@
mPackageString = "com.android.cts.verifier";
Notification n1 = new Notification.Builder(mContext)
- .setContentTitle("ClearTest 1")
+ .setContentTitle("One")
+ .setSortKey(Adjustment.KEY_CHANNEL_ID)
.setContentText(mTag1.toString())
.setPriority(Notification.PRIORITY_LOW)
.setSmallIcon(mIcon1)
@@ -160,7 +164,8 @@
mFlag1 = Notification.FLAG_ONLY_ALERT_ONCE;
Notification n2 = new Notification.Builder(mContext)
- .setContentTitle("ClearTest 2")
+ .setContentTitle("Two")
+ .setSortKey(Adjustment.KEY_PEOPLE)
.setContentText(mTag2.toString())
.setPriority(Notification.PRIORITY_HIGH)
.setSmallIcon(mIcon2)
@@ -174,7 +179,8 @@
mFlag2 = Notification.FLAG_AUTO_CANCEL;
Notification n3 = new Notification.Builder(mContext)
- .setContentTitle("ClearTest 3")
+ .setContentTitle("Three")
+ .setSortKey(Adjustment.KEY_SNOOZE_CRITERIA)
.setContentText(mTag3.toString())
.setPriority(Notification.PRIORITY_LOW)
.setSmallIcon(mIcon3)
@@ -698,19 +704,13 @@
}
private class AdjustNotificationTest extends InteractiveTestCase {
- private Bundle bundle1 = new Bundle();
- private Bundle bundle2 = new Bundle();
- private Bundle bundle3 = new Bundle();
- private SnoozeCriterion snooze1 = new SnoozeCriterion("id1", "1", "2");
- private SnoozeCriterion snooze2 = new SnoozeCriterion("id2", "2", "3");
- private String people1 = "people1";
- private String people2 = "people2";
private ArrayList<String> people;
private ArrayList<SnoozeCriterion> snooze;
private NotificationChannel originalChannel = new NotificationChannel("original", "new",
NotificationManager.IMPORTANCE_LOW);
private NotificationChannel newChannel = new NotificationChannel("new", "new",
NotificationManager.IMPORTANCE_LOW);
+ private Map<String, Bundle> adjustments;
@Override
View inflate(ViewGroup parent) {
@@ -729,27 +729,38 @@
} catch (Exception e) {
Log.e(TAG, "failed to create channel", e);
}
+ adjustments = getAdjustments();
+ snooze = adjustments.get(Adjustment.KEY_SNOOZE_CRITERIA).getParcelableArrayList(
+ Adjustment.KEY_SNOOZE_CRITERIA);
+ people = adjustments.get(Adjustment.KEY_PEOPLE).getStringArrayList(
+ Adjustment.KEY_PEOPLE);
sendNotifications(originalChannel);
status = READY;
- bundle1.putString(Adjustment.KEY_CHANNEL_ID, newChannel.getId());
- people = new ArrayList<>();
- people.add(people1);
- people.add(people2);
- bundle2.putStringArrayList(Adjustment.KEY_PEOPLE, people);
- snooze = new ArrayList<>();
- snooze.add(snooze1);
- snooze.add(snooze2);
- bundle3.putParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA, snooze);
delay();
}
@Override
void test() {
if (status == READY) {
- MockAssistant.applyAdjustment(mContext, mTag1, bundle1);
- MockAssistant.applyAdjustment(mContext, mTag2, bundle2);
- MockAssistant.applyAdjustment(mContext, mTag3, bundle3);
- status = RETEST;
+ MockAssistant.probeListenerPosted(mContext,
+ new StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result != null && result.size() > 0 && result.contains(mTag1)) {
+ MockAssistant.applyAdjustment(mContext, mTag1,
+ adjustments.get(Adjustment.KEY_CHANNEL_ID));
+ MockAssistant.applyAdjustment(mContext, mTag2,
+ adjustments.get(Adjustment.KEY_PEOPLE));
+ MockAssistant.applyAdjustment(mContext, mTag3,
+ adjustments.get(Adjustment.KEY_SNOOZE_CRITERIA));
+ status = RETEST;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ delay(3000);
+ }
+ });
} else {
MockAssistant.probeListenerPayloads(mContext,
new MockAssistant.BundleListResultCatcher() {
@@ -839,6 +850,177 @@
}
}
+ private class AdjustEnqueuedNotificationTest extends InteractiveTestCase {
+ private ArrayList<String> people;
+ private ArrayList<SnoozeCriterion> snooze;
+ private NotificationChannel originalChannel = new NotificationChannel("original", "new",
+ NotificationManager.IMPORTANCE_LOW);
+ private NotificationChannel newChannel = new NotificationChannel("new", "new",
+ NotificationManager.IMPORTANCE_LOW);
+ private Map<String, Bundle> adjustments;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nas_adjustment_enqueue_payload_intact);
+ }
+
+ @Override
+ void setUp() {
+ MockAssistant.adjustEnqueue(mContext);
+ try {
+ mNm.createNotificationChannel(newChannel, (createdChannel) -> {}, null);
+ } catch (Exception e) {
+ Log.e(TAG, "failed to create channel", e);
+ }
+ try {
+ mNm.createNotificationChannel(originalChannel, (createdChannel) -> {}, null);
+ } catch (Exception e) {
+ Log.e(TAG, "failed to create channel", e);
+ }
+ adjustments = getAdjustments();
+ snooze = adjustments.get(Adjustment.KEY_SNOOZE_CRITERIA).getParcelableArrayList(
+ Adjustment.KEY_SNOOZE_CRITERIA);
+ people = adjustments.get(Adjustment.KEY_PEOPLE).getStringArrayList(
+ Adjustment.KEY_PEOPLE);
+ sendNotifications(originalChannel);
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ if (status == READY) {
+ MockAssistant.probeListenerEnqueued(mContext,
+ new StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result != null && result.size() > 0 && result.contains(mTag1)) {
+ status = RETEST;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ } else {
+ MockAssistant.probeListenerPayloads(mContext,
+ new MockAssistant.BundleListResultCatcher() {
+ @Override
+ public void accept(ArrayList<Parcelable> result) {
+ Set<String> found = new HashSet<>();
+ if (result == null || result.size() == 0) {
+ status = FAIL;
+ return;
+ }
+ boolean pass = true;
+ for (Parcelable payloadData : result) {
+ Bundle payload = (Bundle) payloadData;
+ pass &= checkEquals(mPackageString,
+ payload.getString(KEY_PACKAGE),
+ "data integrity test: notification package (%s, %s)");
+
+ String tag = payload.getString(KEY_TAG);
+ if (mTag1.equals(tag)) {
+ found.add(mTag1);
+ pass &= checkEquals(newChannel.getId(),
+ ((NotificationChannel) payload.getParcelable(
+ KEY_CHANNEL)).getId(),
+ "data integrity test: notification channel ("
+ + "%s, %s)");
+ pass &= checkEquals(null,
+ payload.getStringArray(KEY_PEOPLE),
+ "data integrity test, notification people ("
+ + "%s, %s)");
+ pass &= checkEquals(null,
+ payload.getParcelableArray(KEY_SNOOZE_CRITERIA),
+ "data integrity test, notification snooze ("
+ + "%s, %s)");
+ } else if (mTag2.equals(tag)) {
+ found.add(mTag2);
+ pass &= checkEquals(originalChannel.getId(),
+ ((NotificationChannel) payload.getParcelable(
+ KEY_CHANNEL)).getId(),
+ "data integrity test: notification channel ("
+ + "%s, %s)");
+ pass &= checkEquals(people.toArray(new String[]{}),
+ payload.getStringArray(KEY_PEOPLE),
+ "data integrity test, notification people ("
+ + "%s, %s)");
+ pass &= checkEquals(null,
+ payload.getParcelableArray(KEY_SNOOZE_CRITERIA),
+ "data integrity test, notification snooze ("
+ + "%s, %s)");
+ } else if (mTag3.equals(tag)) {
+ found.add(mTag3);
+ pass &= checkEquals(originalChannel.getId(),
+ ((NotificationChannel) payload.getParcelable(
+ KEY_CHANNEL)).getId(),
+ "data integrity test: notification channel ("
+ + "%s, %s)");
+ pass &= checkEquals(null,
+ payload.getStringArray(KEY_PEOPLE),
+ "data integrity test, notification people ("
+ + "%s, %s)");;
+ pass &= checkEquals(snooze.toArray(new SnoozeCriterion[]{}),
+ payload.getParcelableArray(KEY_SNOOZE_CRITERIA),
+ "data integrity test, notification snooze ("
+ + "%s, %s)");
+ } else {
+ pass = false;
+ logFail("unexpected notification tag: " + tag);
+ }
+ }
+
+ pass &= found.size() == 3;
+ status = pass ? PASS : FAIL;
+ next();
+ }
+ });
+ }
+ delay(6000); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ mNm.cancelAll();
+ mNm.deleteNotificationChannel(originalChannel.getId());
+ mNm.deleteNotificationChannel(newChannel.getId());
+ sleep(1000);
+ MockAssistant.resetListenerData(mContext);
+ delay();
+ }
+ }
+
+ public static Map<String, Bundle> getAdjustments() {
+ Map<String, Bundle> adjustments = new ArrayMap<>();
+ Bundle bundle1 = new Bundle();
+ Bundle bundle2 = new Bundle();
+ Bundle bundle3 = new Bundle();
+ SnoozeCriterion snooze1 = new SnoozeCriterion("id1", "1", "2");
+ SnoozeCriterion snooze2 = new SnoozeCriterion("id2", "2", "3");
+ String people1 = "people1";
+ String people2 = "people2";
+ ArrayList<String> people = new ArrayList<>();
+ ArrayList<SnoozeCriterion> snooze = new ArrayList<>();
+ NotificationChannel newChannel = new NotificationChannel("new", "new",
+ NotificationManager.IMPORTANCE_LOW);
+
+ bundle1.putString(Adjustment.KEY_CHANNEL_ID, newChannel.getId());
+ adjustments.put(Adjustment.KEY_CHANNEL_ID, bundle1);
+
+ people.add(people1);
+ people.add(people2);
+ bundle2.putStringArrayList(Adjustment.KEY_PEOPLE, people);
+ adjustments.put(Adjustment.KEY_PEOPLE, bundle2);
+
+ snooze.add(snooze1);
+ snooze.add(snooze2);
+ bundle3.putParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA, snooze);
+ adjustments.put(Adjustment.KEY_SNOOZE_CRITERIA, bundle3);
+ return adjustments;
+ }
+
private class CreateChannelTest extends InteractiveTestCase {
private NotificationChannel channel = new NotificationChannel("channelForOtherPkg", "new",
NotificationManager.IMPORTANCE_LOW);
@@ -1049,7 +1231,11 @@
@Override
void setUp() {
- MockAssistant.createChannel(mContext, THIS_PKG, channel);
+ try {
+ mNm.createNotificationChannel(channel, (createdChannel) -> {}, null);
+ } catch (Exception e) {
+ Log.e(TAG, "failed to create channel", e);
+ }
sendNotifications(channel);
status = READY;
delay();
@@ -1070,7 +1256,7 @@
logFail();
status = FAIL;
}
- next();
+ delay(3000);
}
});
} else if (status == RETEST) {