From 4188bc32d5181b4c3dd5696a714b251a12fd033b Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 23 May 2016 16:10:07 -0700 Subject: [PATCH] Added test for whitelisting pending intent for Doze Mode. BUG: 28818704 Change-Id: I927364e78cd73133899d67be23e0b274829686af --- tests/cts/hostside/app/AndroidManifest.xml | 8 +++ .../hostside/AbstractDozeModeTestCase.java | 20 ++++++ ...ractRestrictBackgroundNetworkTestCase.java | 64 +++++++++++++++--- .../MyNotificationListenerService.java | 61 +++++++++++++++++ tests/cts/hostside/app2/AndroidManifest.xml | 3 +- .../app2/res/drawable/ic_notification.png | Bin 0 -> 3777 bytes .../android/cts/net/hostside/app2/Common.java | 4 ++ .../hostside/app2/MyBroadcastReceiver.java | 37 ++++++++-- ...ostsideRestrictBackgroundNetworkTests.java | 11 +++ 9 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 tests/cts/hostside/app/src/com/android/cts/net/hostside/MyNotificationListenerService.java create mode 100644 tests/cts/hostside/app2/res/drawable/ic_notification.png 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 0000000000000000000000000000000000000000..6ae570b4db4da165fada0650079061cb56aa8793 GIT binary patch literal 3777 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 literal 0 HcmV?d00001 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. * **********************/