Home | History | Annotate | Download | only in notifications
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.cts.verifier.notifications;
     18 
     19 import android.app.Notification;
     20 import android.content.Intent;
     21 import android.content.pm.PackageManager;
     22 import android.util.Log;
     23 import android.view.View;
     24 import android.view.ViewGroup;
     25 import com.android.cts.verifier.R;
     26 
     27 import java.util.ArrayList;
     28 import java.util.List;
     29 
     30 /**
     31  * Tests that the notification ranker honors user preferences about package priority.
     32  * Users can, in Settings, specify a package as being high priority. This should
     33  * result in the notificaitons from that package being ranked higher than those from
     34  * other packages.
     35  */
     36 public class PackagePriorityVerifierActivity
     37         extends InteractiveVerifierActivity {
     38     private static final String ACTION_POST = "com.android.cts.robot.ACTION_POST";
     39     private static final String ACTION_CANCEL = "com.android.cts.robot.ACTION_CANCEL";
     40     private static final String EXTRA_ID = "ID";
     41     private static final String EXTRA_NOTIFICATION = "NOTIFICATION";
     42     private static final String NOTIFICATION_BOT_PACKAGE = "com.android.cts.robot";
     43     private CharSequence mAppLabel;
     44 
     45     @Override
     46     int getTitleResource() {
     47         return R.string.package_priority_test;
     48     }
     49 
     50     @Override
     51     int getInstructionsResource() {
     52         return R.string.package_priority_info;
     53     }
     54 
     55     // Test Setup
     56 
     57     @Override
     58     protected List<InteractiveTestCase> createTestItems() {
     59         mAppLabel = getString(R.string.app_name);
     60         List<InteractiveTestCase> tests = new ArrayList<>(17);
     61         tests.add(new CheckForBot());
     62         tests.add(new IsEnabledTest());
     63         tests.add(new ServiceStartedTest());
     64         tests.add(new WaitForSetPriorityDefault());
     65         tests.add(new DefaultOrderTest());
     66         tests.add(new WaitForSetPriorityHigh());
     67         tests.add(new PackagePriorityOrderTest());
     68         return tests;
     69     }
     70 
     71     // Tests
     72 
     73     /** Make sure the helper package is installed. */
     74     protected class CheckForBot extends InteractiveTestCase {
     75         @Override
     76         View inflate(ViewGroup parent) {
     77             return createAutoItem(parent, R.string.package_priority_bot);
     78         }
     79 
     80         @Override
     81         void test() {
     82             PackageManager pm = mContext.getPackageManager();
     83             try {
     84                 pm.getPackageInfo(NOTIFICATION_BOT_PACKAGE, 0);
     85                 status = PASS;
     86             } catch (PackageManager.NameNotFoundException e) {
     87                 status = FAIL;
     88                 logFail("You must install the CTS Robot helper, aka " + NOTIFICATION_BOT_PACKAGE);
     89             }
     90             next();
     91         }
     92     }
     93 
     94     /** Wait for the user to set the target package priority to default. */
     95     protected class WaitForSetPriorityDefault extends InteractiveTestCase {
     96         @Override
     97         View inflate(ViewGroup parent) {
     98             return createRetryItem(parent, R.string.package_priority_default, mAppLabel);
     99         }
    100 
    101         @Override
    102         void setUp() {
    103             Log.i("WaitForSetPriorityDefault", "waiting for user");
    104             status = WAIT_FOR_USER;
    105         }
    106 
    107         @Override
    108         void test() {
    109             status = PASS;
    110             next();
    111         }
    112 
    113         @Override
    114         void tearDown() {
    115             MockListener.resetListenerData(mContext);
    116             delay();
    117         }
    118     }
    119 
    120     /** Wait for the user to set the target package priority to high. */
    121     protected class WaitForSetPriorityHigh extends InteractiveTestCase {
    122         @Override
    123         View inflate(ViewGroup parent) {
    124             return createRetryItem(parent, R.string.package_priority_high, mAppLabel);
    125         }
    126 
    127         @Override
    128         void setUp() {
    129             Log.i("WaitForSetPriorityHigh", "waiting for user");
    130             status = WAIT_FOR_USER;
    131         }
    132 
    133         @Override
    134         void test() {
    135             status = PASS;
    136             next();
    137         }
    138 
    139         @Override
    140         void tearDown() {
    141             MockListener.resetListenerData(mContext);
    142             delay();
    143         }
    144     }
    145 
    146     /**
    147      * With default priority, the notifcations should be reverse-ordered by time.
    148      * A is before B, and therefor should B should rank before A.
    149      */
    150     protected class DefaultOrderTest extends InteractiveTestCase {
    151         @Override
    152         View inflate(ViewGroup parent) {
    153             return createAutoItem(parent, R.string.attention_default_order);
    154         }
    155 
    156         @Override
    157         void setUp() {
    158             sendNotifications();
    159             status = READY;
    160             // wait for notifications to move through the system
    161             delay();
    162         }
    163 
    164         @Override
    165         void test() {
    166             MockListener.probeListenerOrder(mContext,
    167                     new MockListener.StringListResultCatcher() {
    168                         @Override
    169                         public void accept(List<String> orderedKeys) {
    170                             int rankA = indexOfPackageInKeys(orderedKeys, getPackageName());
    171                             int rankB = indexOfPackageInKeys(orderedKeys, NOTIFICATION_BOT_PACKAGE);
    172                             if (rankB != -1 && rankB < rankA) {
    173                                 status = PASS;
    174                             } else {
    175                                 logFail("expected rankA (" + rankA + ") > rankB (" + rankB + ")");
    176                                 status = FAIL;
    177                             }
    178                             next();
    179                         }
    180                     });
    181             delay();  // in case the catcher never returns
    182         }
    183 
    184         @Override
    185         void tearDown() {
    186             cancelNotifications();
    187             MockListener.resetListenerData(mContext);
    188             delay();
    189         }
    190     }
    191 
    192     /**
    193      * With higher package priority, A should rank above B.
    194      */
    195     protected class PackagePriorityOrderTest extends InteractiveTestCase {
    196         @Override
    197         View inflate(ViewGroup parent) {
    198             return createAutoItem(parent, R.string.package_priority_user_order);
    199         }
    200 
    201         @Override
    202         void setUp() {
    203             sendNotifications();
    204             status = READY;
    205             // wait for notifications to move through the system
    206             delay();
    207         }
    208 
    209         @Override
    210         void test() {
    211             MockListener.probeListenerOrder(mContext,
    212                     new MockListener.StringListResultCatcher() {
    213                         @Override
    214                         public void accept(List<String> orderedKeys) {
    215                             int rankA = indexOfPackageInKeys(orderedKeys, getPackageName());
    216                             int rankB = indexOfPackageInKeys(orderedKeys, NOTIFICATION_BOT_PACKAGE);
    217                             if (rankA != -1 && rankA < rankB) {
    218                                 status = PASS;
    219                             } else {
    220                                 logFail("expected rankA (" + rankA + ") < rankB (" + rankB + ")");
    221                                 status = FAIL;
    222                             }
    223                             next();
    224                         }
    225                     });
    226             delay();  // in case the catcher never returns
    227         }
    228 
    229         @Override
    230         void tearDown() {
    231             cancelNotifications();
    232             MockListener.resetListenerData(mContext);
    233             delay();
    234         }
    235     }
    236     // Utilities
    237 
    238     private void sendNotifications() {
    239         // post ours first, with an explicit time in the past to avoid any races.
    240         Notification.Builder alice = new Notification.Builder(mContext)
    241                 .setContentTitle("alice title")
    242                 .setContentText("alice content")
    243                 .setSmallIcon(R.drawable.ic_stat_alice)
    244                 .setWhen(System.currentTimeMillis() - 10000L)
    245                 .setPriority(Notification.PRIORITY_DEFAULT);
    246         mNm.notify(0, alice.build());
    247 
    248         // then post theirs, so it should be higher by default due to recency
    249         Notification.Builder bob = new Notification.Builder(mContext)
    250                 .setContentTitle("bob title")
    251                 .setContentText("bob content")
    252                 .setSmallIcon(android.R.drawable.stat_notify_error) // must be global resource
    253                 .setWhen(System.currentTimeMillis())
    254                 .setPriority(Notification.PRIORITY_DEFAULT);
    255         Intent postIntent = new Intent(ACTION_POST);
    256         postIntent.setPackage(NOTIFICATION_BOT_PACKAGE);
    257         postIntent.putExtra(EXTRA_ID, 0);
    258         postIntent.putExtra(EXTRA_NOTIFICATION, bob.build());
    259         postIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
    260         sendBroadcast(postIntent);
    261     }
    262 
    263     private void cancelNotifications() {
    264         //cancel ours
    265         mNm.cancelAll();
    266         //cancel theirs
    267         Intent cancelIntent = new Intent(ACTION_CANCEL);
    268         cancelIntent.setPackage(NOTIFICATION_BOT_PACKAGE);
    269         cancelIntent.putExtra(EXTRA_ID, 0);
    270         cancelIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
    271         sendBroadcast(cancelIntent);
    272     }
    273 
    274     /** Search a list of notification keys for a given packageName. */
    275     private int indexOfPackageInKeys(List<String> orderedKeys, String packageName) {
    276         for (int i = 0; i < orderedKeys.size(); i++) {
    277             if (orderedKeys.get(i).contains(packageName)) {
    278                 return i;
    279             }
    280         }
    281         return -1;
    282     }
    283 }
    284