blob: b40ecc6b2ebe33e1c9b4886f737510a02025c0f1 [file] [log] [blame]
/*
* 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.content.pm.PackageManager;
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";
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 CheckForBot());
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
/** Make sure the helper package is installed. */
protected class CheckForBot extends InteractiveTestCase {
@Override
View inflate(ViewGroup parent) {
return createAutoItem(parent, R.string.package_priority_bot);
}
@Override
void test() {
PackageManager pm = mContext.getPackageManager();
try {
pm.getPackageInfo(NOTIFICATION_BOT_PACKAGE, 0);
status = PASS;
} catch (PackageManager.NameNotFoundException e) {
status = FAIL;
logFail("You must install the CTS Robot helper, aka " + NOTIFICATION_BOT_PACKAGE);
}
next();
}
}
/** 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());
postIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
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);
cancelIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
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;
}
}