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