Home | History | Annotate | Download | only in helpers
      1 /*
      2  * Copyright (C) 2016 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 android.system.helpers;
     18 
     19 import android.app.IntentService;
     20 import android.app.Notification;
     21 import android.app.NotificationChannel;
     22 import android.app.NotificationManager;
     23 import android.app.PendingIntent;
     24 import android.app.RemoteInput;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.os.Handler;
     28 import android.service.notification.StatusBarNotification;
     29 import android.support.test.InstrumentationRegistry;
     30 import android.support.test.uiautomator.UiDevice;
     31 import android.util.Log;
     32 import android.widget.Toast;
     33 
     34 import java.util.List;
     35 
     36 /**
     37  * Implement common helper methods for Notification.
     38  */
     39 public class NotificationHelper {
     40     private static final String LOG_TAG = NotificationHelper.class.getSimpleName();
     41     public static final int SHORT_TIMEOUT = 200;
     42     public static final int LONG_TIMEOUT = 2000;
     43     private static NotificationHelper sInstance = null;
     44     private Context mContext = null;
     45     private UiDevice mDevice = null;
     46     private String mCurrentChannelId = NotificationChannel.DEFAULT_CHANNEL_ID;
     47 
     48     public NotificationHelper() {
     49         mContext = InstrumentationRegistry.getTargetContext();
     50         mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
     51     }
     52 
     53     public static NotificationHelper getInstance() {
     54         if (sInstance == null) {
     55             sInstance = new NotificationHelper();
     56         }
     57         return sInstance;
     58     }
     59 
     60     /**
     61      * Creates a notification channel if none exists.
     62      * @param id channel id, must be unique
     63      * @param name channel name
     64      * @param importance channel importance
     65      * @param vibrate vibrate on notification
     66      * @param manager the {@link NotificationManager}
     67      * @throws IllegalArgumentException if the channel id is already in use.
     68      */
     69     public void createChannel(String id, String name, int importance, boolean vibrate,
     70             NotificationManager manager) {
     71         if (manager.getNotificationChannel(id) != null) {
     72             throw new IllegalArgumentException("Channel already exists.");
     73         }
     74         NotificationChannel channel = new NotificationChannel(id, name, importance);
     75         channel.enableVibration(vibrate);
     76         channel.setSound(null, null);
     77         manager.createNotificationChannel(channel);
     78     }
     79 
     80     /**
     81      * Uses this notification channel when using this helper.
     82      * @param id the channel id to use
     83      */
     84     public void useChannel(String id) {
     85         mCurrentChannelId = id;
     86     }
     87 
     88     /**
     89      * Check if a list of notifications exist.
     90      * @param ids list of notification ids
     91      * @param manager the {@link NotificationManager}
     92      * @return true if all notifications exist, false otherwise
     93      * @throws InterruptedException if the running thread is interrupted.
     94      */
     95     public boolean checkNotificationExistence(List<Integer> ids, NotificationManager manager)
     96             throws InterruptedException {
     97         boolean result = true;
     98         for (int id : ids) {
     99             result = result && checkNotificationExistence(id, manager);
    100         }
    101         return result;
    102     }
    103 
    104     /**
    105      * Check if a notification exists.
    106      * @param id notification id
    107      * @param manager the {@link NotificationManager}
    108      * @return true if all notifications exist, false otherwise
    109      * @throws InterruptedException if the running thread is interrupted.
    110      */
    111     public boolean checkNotificationExistence(int id, NotificationManager manager)
    112             throws InterruptedException {
    113         boolean isFound = false;
    114         for (int tries = 3; tries-- > 0;) {
    115             isFound = false;
    116             StatusBarNotification[] sbns = manager.getActiveNotifications();
    117             for (StatusBarNotification sbn : sbns) {
    118                 if (sbn.getId() == id) {
    119                     isFound = true;
    120                     break;
    121                 }
    122             }
    123             if (isFound) {
    124                 break;
    125             }
    126             Thread.sleep(SHORT_TIMEOUT);
    127         }
    128         Log.i(LOG_TAG, String.format("Notification (id=%d) existence = %b", id, isFound));
    129         return isFound;
    130     }
    131 
    132     /**
    133      * send out a group of notifications
    134      * @param lists notification list for a group of notifications which includes two child
    135      *            notifications and one summary notification
    136      * @param groupKey the group key of group notification
    137      * @param mNotificationManager NotificationManager
    138      * @throws Exception
    139      */
    140     public void sendBundlingNotifications(List<Integer> lists, String groupKey,
    141             NotificationManager mNotificationManager) throws Exception {
    142         Notification childNotification = new Notification.Builder(mContext)
    143                 .setChannelId(mCurrentChannelId)
    144                 .setContentTitle(lists.get(1).toString())
    145                 .setSmallIcon(android.R.drawable.stat_notify_chat)
    146                 .setContentText("test1")
    147                 .setWhen(System.currentTimeMillis())
    148                 .setGroup(groupKey)
    149                 .build();
    150         mNotificationManager.notify(lists.get(1),
    151                 childNotification);
    152         childNotification = new Notification.Builder(mContext)
    153                 .setChannelId(mCurrentChannelId)
    154                 .setContentTitle(lists.get(2).toString())
    155                 .setContentText("test2")
    156                 .setSmallIcon(android.R.drawable.stat_notify_chat)
    157                 .setWhen(System.currentTimeMillis())
    158                 .setGroup(groupKey)
    159                 .build();
    160         mNotificationManager.notify(lists.get(2),
    161                 childNotification);
    162         Notification notification = new Notification.Builder(mContext)
    163                 .setChannelId(mCurrentChannelId)
    164                 .setContentTitle(lists.get(0).toString())
    165                 .setSubText(groupKey)
    166                 .setSmallIcon(android.R.drawable.stat_notify_chat)
    167                 .setGroup(groupKey)
    168                 .setGroupSummary(true)
    169                 .build();
    170         mNotificationManager.notify(lists.get(0),
    171                 notification);
    172     }
    173 
    174     /**
    175      * send out a notification with inline reply
    176      * @param notificationId An identifier for this notification
    177      * @param title notification title
    178      * @param inLineReply inline reply text
    179      * @param mNotificationManager NotificationManager
    180      */
    181     public void sendNotificationsWithInLineReply(
    182             int notificationId, String title, String inLineReply, PendingIntent pendingIntent,
    183             NotificationManager mNotificationManager) {
    184         Notification.Action action = new Notification.Action.Builder(
    185                 android.R.drawable.stat_notify_chat, "Reply",
    186                 pendingIntent).addRemoteInput(new RemoteInput.Builder(inLineReply)
    187                         .setLabel("Quick reply").build())
    188                         .build();
    189         Notification.Builder n = new Notification.Builder(mContext)
    190                 .setChannelId(mCurrentChannelId)
    191                 .setContentTitle(Integer.toString(notificationId))
    192                 .setContentText(title)
    193                 .setWhen(System.currentTimeMillis())
    194                 .setSmallIcon(android.R.drawable.stat_notify_chat)
    195                 .addAction(action)
    196                 .setDefaults(Notification.DEFAULT_VIBRATE);
    197         mNotificationManager.notify(notificationId, n.build());
    198     }
    199 
    200     /**
    201      * dismiss notification
    202      * @param mNotificationManager NotificationManager
    203      */
    204     public void dismissNotifications(NotificationManager mNotificationManager){
    205         mNotificationManager.cancelAll();
    206     }
    207 
    208     /**
    209      * open notification shade
    210      */
    211     public void openNotification(){
    212         mDevice.openNotification();
    213     }
    214 
    215     /**
    216      * An {@link IntentService} for creating pending intents that can be used with to send
    217      * notifications with inline reply text content.
    218      */
    219     public static class ToastService extends IntentService {
    220         private Handler mHandler;
    221 
    222         public ToastService() {
    223             super("Toast Service");
    224         }
    225 
    226         @Override
    227         public int onStartCommand(Intent intent, int flags, int startId) {
    228             return super.onStartCommand(intent, flags, startId);
    229         }
    230 
    231         @Override
    232         protected void onHandleIntent(Intent intent) {
    233             if (mHandler == null) {
    234                 mHandler = new Handler();
    235             }
    236             if (intent.hasExtra("text")) {
    237                 mHandler.post(new Runnable() {
    238                     @Override
    239                     public void run() {
    240                         Toast.makeText(
    241                                 ToastService.this, intent.getStringExtra("text"), Toast.LENGTH_LONG)
    242                             .show();
    243                     }
    244                 });
    245             }
    246         }
    247 
    248         /**
    249          * Returns a {@link PendingIntent} for a Toast message.
    250          */
    251         public static PendingIntent getPendingIntent(Context context, String text) {
    252             Intent toastIntent = new Intent(context, ToastService.class);
    253             toastIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    254             toastIntent.setAction("toast:" + text);
    255             toastIntent.putExtra("text", text);
    256             PendingIntent pi = PendingIntent.getService(
    257                     context, 58, toastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    258             return pi;
    259         }
    260     }
    261 }
    262