diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml
index c7978f8775..0598a3b02a 100644
--- a/tests/cts/hostside/app/AndroidManifest.xml
+++ b/tests/cts/hostside/app/AndroidManifest.xml
@@ -31,6 +31,14 @@
+
+
+
+
+
0) {
+ listeners.append(":");
+ }
+ listeners.append(MyNotificationListenerService.getId());
+ executeShellCommand("settings put secure enabled_notification_listeners " + listeners);
+ final String newListeners = getNotificationListenerServices();
+ assertEquals("Failed to set 'enabled_notification_listeners'",
+ listeners.toString(), newListeners);
+ }
+
+ private String getNotificationListenerServices() throws Exception {
+ return executeShellCommand("settings get secure enabled_notification_listeners");
+ }
+
+ protected void setPendingIntentWhitelistDuration(int durationMs) throws Exception {
+ final String command = String.format(
+ "settings put global device_idle_constants %s=%d",
+ "notification_whitelist_duration", durationMs);
+ executeSilentShellCommand(command);
+ }
+
+ protected void resetDeviceIdleSettings() throws Exception {
+ executeShellCommand("settings delete global device_idle_constants");
+ }
+
protected void startForegroundService() throws Exception {
executeShellCommand(
"am startservice -f 1 com.android.cts.net.hostside.app2/.MyForegroundService");
@@ -667,6 +704,13 @@ abstract class AbstractRestrictBackgroundNetworkTestCase extends Instrumentation
+ "--receiver-foreground --receiver-registered-only");
}
+ protected void sendNotification(int notificationId) {
+ final Intent intent = new Intent(ACTION_SEND_NOTIFICATION);
+ intent.putExtra(EXTRA_NOTIFICATION_ID, notificationId);
+ Log.d(TAG, "Sending broadcast: " + intent);
+ mContext.sendBroadcast(intent);
+ }
+
private String toString(int status) {
switch (status) {
case RESTRICT_BACKGROUND_STATUS_DISABLED:
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java
new file mode 100644
index 0000000000..b9c303107c
--- /dev/null
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.net.hostside;
+
+import android.app.Notification;
+import android.app.PendingIntent.CanceledException;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.util.Log;
+
+/**
+ * NotificationListenerService implementation that executes the notification actions once they're
+ * created.
+ */
+public class MyNotificationListenerService extends NotificationListenerService {
+ private static final String TAG = "MyNotificationListenerService";
+
+ @Override
+ public void onListenerConnected() {
+ Log.d(TAG, "onListenerConnected()");
+ }
+
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn) {
+ Log.d(TAG, "onNotificationPosted(): " + sbn);
+ if (!sbn.getPackageName().startsWith(getPackageName())) {
+ Log.v(TAG, "ignoring notification from a different package");
+ return;
+ }
+ final Notification notification = sbn.getNotification();
+ if (notification.actions == null) {
+ Log.w(TAG, "ignoring notification without an action");
+ }
+ for (Notification.Action action : notification.actions) {
+ Log.i(TAG, "Sending pending intent " + action.actionIntent);
+ try {
+ action.actionIntent.send();
+ } catch (CanceledException e) {
+ Log.w(TAG, "Pending Intent canceled");
+ }
+ }
+ }
+
+ static String getId() {
+ return String.format("%s/%s", MyNotificationListenerService.class.getPackage().getName(),
+ MyNotificationListenerService.class.getName());
+ }
+}
diff --git a/tests/cts/hostside/app2/AndroidManifest.xml b/tests/cts/hostside/app2/AndroidManifest.xml
index 80b669d4eb..1fa49ba837 100644
--- a/tests/cts/hostside/app2/AndroidManifest.xml
+++ b/tests/cts/hostside/app2/AndroidManifest.xml
@@ -45,7 +45,8 @@
-
+
+
diff --git a/tests/cts/hostside/app2/res/drawable/ic_notification.png b/tests/cts/hostside/app2/res/drawable/ic_notification.png
new file mode 100644
index 0000000000..6ae570b4db
Binary files /dev/null and b/tests/cts/hostside/app2/res/drawable/ic_notification.png differ
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
index d827921654..f02f651f06 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -36,9 +36,13 @@ public final class Common {
"com.android.cts.net.hostside.app2.action.RECEIVER_READY";
static final String ACTION_FINISH_ACTIVITY =
"com.android.cts.net.hostside.app2.action.FINISH_ACTIVITY";
+ static final String ACTION_SEND_NOTIFICATION =
+ "com.android.cts.net.hostside.app2.action.SEND_NOTIFICATION";
static final String EXTRA_ACTION = "com.android.cts.net.hostside.app2.extra.ACTION";
static final String EXTRA_RECEIVER_NAME =
"com.android.cts.net.hostside.app2.extra.RECEIVER_NAME";
+ static final String EXTRA_NOTIFICATION_ID =
+ "com.android.cts.net.hostside.app2.extra.NOTIFICATION_ID";
static int getUid(Context context) {
final String packageName = context.getPackageName();
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
index 114d5c11d9..96e9d2bab4 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
@@ -22,17 +22,17 @@ import static com.android.cts.net.hostside.app2.Common.ACTION_CHECK_NETWORK;
import static com.android.cts.net.hostside.app2.Common.ACTION_GET_COUNTERS;
import static com.android.cts.net.hostside.app2.Common.ACTION_GET_RESTRICT_BACKGROUND_STATUS;
import static com.android.cts.net.hostside.app2.Common.ACTION_RECEIVER_READY;
+import static com.android.cts.net.hostside.app2.Common.ACTION_SEND_NOTIFICATION;
import static com.android.cts.net.hostside.app2.Common.EXTRA_ACTION;
+import static com.android.cts.net.hostside.app2.Common.EXTRA_NOTIFICATION_ID;
import static com.android.cts.net.hostside.app2.Common.EXTRA_RECEIVER_NAME;
import static com.android.cts.net.hostside.app2.Common.MANIFEST_RECEIVER;
import static com.android.cts.net.hostside.app2.Common.TAG;
import static com.android.cts.net.hostside.app2.Common.getUid;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -41,6 +41,11 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
/**
* Receiver used to:
*
@@ -85,6 +90,9 @@ public class MyBroadcastReceiver extends BroadcastReceiver {
Log.d(TAG, message);
setResultData(message);
break;
+ case ACTION_SEND_NOTIFICATION:
+ sendNotification(context, intent);
+ break;
default:
Log.e(TAG, "received unexpected action: " + action);
}
@@ -213,4 +221,23 @@ public class MyBroadcastReceiver extends BroadcastReceiver {
final int counter = getCounter(context, action, receiverName);
setResultData(String.valueOf(counter));
}
+
+ /**
+ * Sends a system notification containing actions with pending intents to launch the app's
+ * main activitiy or service.
+ */
+ private void sendNotification(Context context, Intent intent) {
+ final int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
+ final Intent serviceIntent = new Intent(context, MyService.class);
+ final PendingIntent pendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0);
+
+ final Notification notification = new Notification.Builder(context)
+ .setSmallIcon(R.drawable.ic_notification)
+ .setContentTitle("Light, Cameras...")
+ .setContentIntent(pendingIntent)
+ .addAction(R.drawable.ic_notification, "ACTION", pendingIntent)
+ .build();
+ ((NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE))
+ .notify(notificationId, notification);
+ }
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index 8152e55297..c741b12fd0 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -184,6 +184,11 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC
"testBackgroundNetworkAccess_enabled");
}
+ public void testDozeModeMetered_enabledButWhitelistedOnNotificationAction() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
+ "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction");
+ }
+
// TODO: currently power-save mode and idle uses the same whitelist, so this test would be
// redundant (as it would be testing the same as testBatterySaverMode_reinstall())
// public void testDozeMode_reinstall() throws Exception {
@@ -204,6 +209,12 @@ public class HostsideRestrictBackgroundNetworkTests extends HostsideNetworkTestC
"testBackgroundNetworkAccess_enabled");
}
+ public void testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction()
+ throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
+ "testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction");
+ }
+
/**********************
* Mixed modes tests. *
**********************/