am 45037622: Merge "Add a test for package priority ranking." into lmp-sprout-dev
* commit '45037622b9b3d05f55499d3128fb301fdde056f0':
Add a test for package priority ranking.
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index b066731..3ccbd07 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1080,6 +1080,15 @@
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
</activity>
+ <activity android:name=".notifications.PackagePriorityVerifierActivity"
+ android:label="@string/package_priority_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+ </activity>
+
<service android:name=".notifications.MockListener"
android:exported="true"
android:label="@string/nls_service_name"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index e687087..429d379 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -968,6 +968,14 @@
itself according to the current rotation of the device.</string>
<string name="test_category_notifications">Notifications</string>
+ <string name="package_priority_test">Notification Package Priority Test</string>
+ <string name="package_priority_info">This test checks that the NotificationManagerService respects
+ user preferences about relative package priorities.
+ </string>
+ <string name="package_priority_high">Find \"%s\" under \"App notifications\" in the \"Sound & notifications\" settings panel, and mark it as having notification priority.</string>
+ <string name="package_priority_default">Find \"%s\" under \"App notifications\" in the \"Sound & notifications\" settings panel, and make sure it has default priority.</string>
+ <string name="package_priority_user_order">Check that ranker respects user priorities.</string>
+
<string name="attention_test">Notification Attention Management Test</string>
<string name="attention_info">This test checks that the NotificationManagerService is
respecting user preferences about notification ranking and filtering.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
index d65af80..b658e4f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/InteractiveVerifierActivity.java
@@ -16,9 +16,7 @@
package com.android.cts.verifier.notifications;
-import android.annotation.SuppressLint;
import android.app.Activity;
-import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
@@ -38,20 +36,12 @@
import android.widget.TextView;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
-import com.android.cts.verifier.nfc.TagVerifierActivity;
-import org.json.JSONException;
-import org.json.JSONObject;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Set;
-import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
-import static com.android.cts.verifier.notifications.MockListener.*;
-
public abstract class InteractiveVerifierActivity extends PassFailButtons.Activity
implements Runnable {
private static final String TAG = "InteractiveVerifier";
@@ -223,17 +213,18 @@
}
protected View createNlsSettingsItem(ViewGroup parent, int messageId) {
- return createUserItem(parent, messageId, R.string.nls_start_settings);
+ return createUserItem(parent, R.string.nls_start_settings, messageId);
}
- protected View createRetryItem(ViewGroup parent, int messageId) {
- return createUserItem(parent, messageId, R.string.attention_ready);
+ protected View createRetryItem(ViewGroup parent, int messageId, Object... messageFormatArgs) {
+ return createUserItem(parent, R.string.attention_ready, messageId, messageFormatArgs);
}
- protected View createUserItem(ViewGroup parent, int messageId, int actionId) {
+ protected View createUserItem(ViewGroup parent, int actionId, int messageId,
+ Object... messageFormatArgs) {
View item = mInflater.inflate(R.layout.nls_item, parent, false);
TextView instructions = (TextView) item.findViewById(R.id.nls_instructions);
- instructions.setText(messageId);
+ instructions.setText(getString(messageId, messageFormatArgs));
Button button = (Button) item.findViewById(R.id.nls_action_button);
button.setText(actionId);
button.setTag(actionId);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index 75eaebd..7207083 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -82,6 +82,7 @@
Log.d(TAG, "created");
mTestPackages.add("com.android.cts.verifier");
+ mTestPackages.add("com.android.cts.robot");
mPosted = new ArrayList<String>();
mRemoved = new ArrayList<String>();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/PackagePriorityVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/PackagePriorityVerifierActivity.java
new file mode 100644
index 0000000..a6affb3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/PackagePriorityVerifierActivity.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2014 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.verifier.notifications;
+
+import android.app.Notification;
+import android.content.Intent;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests that the notification ranker honors user preferences about package priority.
+ * Users can, in Settings, specify a package as being high priority. This should
+ * result in the notificaitons from that package being ranked higher than those from
+ * other packages.
+ */
+public class PackagePriorityVerifierActivity
+ extends InteractiveVerifierActivity {
+ private static final String ACTION_POST = "com.android.cts.robot.ACTION_POST";
+ private static final String ACTION_CANCEL = "com.android.cts.robot.ACTION_CANCEL";
+ private static final String EXTRA_ID = "ID";
+ private static final String EXTRA_NOTIFICATION = "NOTIFICATION";
+ private static final String NOTIFICATION_BOT_PACKAGE = "com.android.cts.robot";
+ private CharSequence mAppLabel;
+
+ @Override
+ int getTitleResource() {
+ return R.string.package_priority_test;
+ }
+
+ @Override
+ int getInstructionsResource() {
+ return R.string.package_priority_info;
+ }
+
+ // Test Setup
+
+ @Override
+ protected List<InteractiveTestCase> createTestItems() {
+ mAppLabel = getString(R.string.app_name);
+ List<InteractiveTestCase> tests = new ArrayList<>(17);
+ tests.add(new IsEnabledTest());
+ tests.add(new ServiceStartedTest());
+ tests.add(new WaitForSetPriorityDefault());
+ tests.add(new DefaultOrderTest());
+ tests.add(new WaitForSetPriorityHigh());
+ tests.add(new PackagePriorityOrderTest());
+ return tests;
+ }
+
+ // Tests
+
+ /** Wait for the user to set the target package priority to default. */
+ protected class WaitForSetPriorityDefault extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createRetryItem(parent, R.string.package_priority_default, mAppLabel);
+ }
+
+ @Override
+ void setUp() {
+ Log.i("WaitForSetPriorityDefault", "waiting for user");
+ status = WAIT_FOR_USER;
+ }
+
+ @Override
+ void test() {
+ status = PASS;
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
+
+ /** Wait for the user to set the target package priority to high. */
+ protected class WaitForSetPriorityHigh extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createRetryItem(parent, R.string.package_priority_high, mAppLabel);
+ }
+
+ @Override
+ void setUp() {
+ Log.i("WaitForSetPriorityHigh", "waiting for user");
+ status = WAIT_FOR_USER;
+ }
+
+ @Override
+ void test() {
+ status = PASS;
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
+
+ /**
+ * With default priority, the notifcations should be reverse-ordered by time.
+ * A is before B, and therefor should B should rank before A.
+ */
+ protected class DefaultOrderTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.attention_default_order);
+ }
+
+ @Override
+ void setUp() {
+ sendNotifications();
+ status = READY;
+ // wait for notifications to move through the system
+ delay();
+ }
+
+ @Override
+ void test() {
+ MockListener.probeListenerOrder(mContext,
+ new MockListener.StringListResultCatcher() {
+ @Override
+ public void accept(List<String> orderedKeys) {
+ int rankA = indexOfPackageInKeys(orderedKeys, getPackageName());
+ int rankB = indexOfPackageInKeys(orderedKeys, NOTIFICATION_BOT_PACKAGE);
+ if (rankB != -1 && rankB < rankA) {
+ status = PASS;
+ } else {
+ logFail("expected rankA (" + rankA + ") > rankB (" + rankB + ")");
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ cancelNotifications();
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
+
+ /**
+ * With higher package priority, A should rank above B.
+ */
+ protected class PackagePriorityOrderTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.package_priority_user_order);
+ }
+
+ @Override
+ void setUp() {
+ sendNotifications();
+ status = READY;
+ // wait for notifications to move through the system
+ delay();
+ }
+
+ @Override
+ void test() {
+ MockListener.probeListenerOrder(mContext,
+ new MockListener.StringListResultCatcher() {
+ @Override
+ public void accept(List<String> orderedKeys) {
+ int rankA = indexOfPackageInKeys(orderedKeys, getPackageName());
+ int rankB = indexOfPackageInKeys(orderedKeys, NOTIFICATION_BOT_PACKAGE);
+ if (rankA != -1 && rankA < rankB) {
+ status = PASS;
+ } else {
+ logFail("expected rankA (" + rankA + ") < rankB (" + rankB + ")");
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ cancelNotifications();
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
+ // Utilities
+
+ private void sendNotifications() {
+ // post ours first, with an explicit time in the past to avoid any races.
+ Notification.Builder alice = new Notification.Builder(mContext)
+ .setContentTitle("alice title")
+ .setContentText("alice content")
+ .setSmallIcon(R.drawable.ic_stat_alice)
+ .setWhen(System.currentTimeMillis() - 10000L)
+ .setPriority(Notification.PRIORITY_DEFAULT);
+ mNm.notify(0, alice.build());
+
+ // then post theirs, so it should be higher by default due to recency
+ Notification.Builder bob = new Notification.Builder(mContext)
+ .setContentTitle("bob title")
+ .setContentText("bob content")
+ .setSmallIcon(android.R.drawable.stat_notify_error) // must be global resource
+ .setWhen(System.currentTimeMillis())
+ .setPriority(Notification.PRIORITY_DEFAULT);
+ Intent postIntent = new Intent(ACTION_POST);
+ postIntent.setPackage(NOTIFICATION_BOT_PACKAGE);
+ postIntent.putExtra(EXTRA_ID, 0);
+ postIntent.putExtra(EXTRA_NOTIFICATION, bob.build());
+ sendBroadcast(postIntent);
+ }
+
+ private void cancelNotifications() {
+ //cancel ours
+ mNm.cancelAll();
+ //cancel theirs
+ Intent cancelIntent = new Intent(ACTION_CANCEL);
+ cancelIntent.setPackage(NOTIFICATION_BOT_PACKAGE);
+ cancelIntent.putExtra(EXTRA_ID, 0);
+ sendBroadcast(cancelIntent);
+ }
+
+ /** Search a list of notification keys for a given packageName. */
+ private int indexOfPackageInKeys(List<String> orderedKeys, String packageName) {
+ for (int i = 0; i < orderedKeys.size(); i++) {
+ if (orderedKeys.get(i).contains(packageName)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}