• 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 com.android.notification.functional;
18 
19 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
20 import static android.app.NotificationManager.IMPORTANCE_LOW;
21 
22 import android.app.Instrumentation;
23 import android.app.IntentService;
24 import android.app.KeyguardManager;
25 import android.app.Notification;
26 import android.app.NotificationChannel;
27 import android.app.NotificationManager;
28 import android.app.PendingIntent;
29 import android.app.RemoteInput;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.graphics.Typeface;
33 import android.os.Handler;
34 import android.os.RemoteException;
35 import android.provider.Settings;
36 import android.service.notification.StatusBarNotification;
37 import android.support.test.uiautomator.By;
38 import android.support.test.uiautomator.UiDevice;
39 import android.support.test.uiautomator.UiObject2;
40 import android.support.test.uiautomator.UiObjectNotFoundException;
41 import android.support.test.uiautomator.UiSelector;
42 import android.support.test.uiautomator.Until;
43 import android.text.SpannableStringBuilder;
44 import android.text.style.StyleSpan;
45 import android.util.Log;
46 import android.widget.EditText;
47 import android.widget.ListView;
48 import android.widget.TextView;
49 import android.widget.Toast;
50 
51 import com.android.notification.functional.R;
52 
53 import java.lang.InterruptedException;
54 import java.util.List;
55 import java.util.Map;
56 
57 
58 public class NotificationHelper {
59 
60     private static final String LOG_TAG = NotificationHelper.class.getSimpleName();
61     private static final int LONG_TIMEOUT = 2500;
62     private static final int SHORT_TIMEOUT = 200;
63     private static final String KEY_QUICK_REPLY_TEXT = "quick_reply";
64     private static final UiSelector LIST_VIEW = new UiSelector().className(ListView.class);
65     private static final UiSelector LIST_ITEM_VALUE = new UiSelector().className(TextView.class);
66     public static final String FIRST_ACTION = "FIRST ACTION";
67     public static final String SECOND_ACTION = "SECOND ACTION";
68     public static final String CONTENT_TITLE = "THIS IS A NOTIFICATION";
69     private static final String BUZZY_CHANNEL_ID = "com.android.notification.functional.buzzy";
70     private static final String QUIET_CHANNEL_ID = "com.android.notification.functional.quiet";
71     private NotificationChannel mBuzzyChannel;
72     private NotificationChannel mQuietChannel;
73 
74     private UiDevice mDevice;
75     private Instrumentation mInst;
76     private NotificationManager mNotificationManager = null;
77     private Context mContext = null;
78 
NotificationHelper(UiDevice device, Instrumentation inst, NotificationManager nm)79     public NotificationHelper(UiDevice device, Instrumentation inst, NotificationManager nm) {
80         this.mDevice = device;
81         mInst = inst;
82         mNotificationManager = nm;
83         mContext = inst.getContext();
84 
85         // create the channels we need
86         mBuzzyChannel = getChannel(true);
87         mQuietChannel = getChannel(false);
88     }
89 
sleepAndWakeUpDevice()90     public void sleepAndWakeUpDevice() throws RemoteException, InterruptedException {
91         mDevice.sleep();
92         Thread.sleep(LONG_TIMEOUT);
93         mDevice.wakeUp();
94     }
95 
launchSettingsPage(Context ctx, String pageName)96     public static void launchSettingsPage(Context ctx, String pageName) throws Exception {
97         Intent intent = new Intent(pageName);
98         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
99         ctx.startActivity(intent);
100         Thread.sleep(LONG_TIMEOUT * 2);
101     }
102 
enableNotificationViaAdb(boolean isShow)103     public void enableNotificationViaAdb(boolean isShow) {
104         String command = String.format(" %s %s %s %s %s", "settings", "put", "secure",
105                 "lock_screen_show_notifications",
106                 isShow ? "1" : "0");
107         executeAdbCommand(command);
108     }
109 
executeAdbCommand(String command)110     public void executeAdbCommand(String command) {
111         Log.i(LOG_TAG, String.format("executing - %s", command));
112         mInst.getUiAutomation().executeShellCommand(command);
113         mDevice.waitForIdle();
114     }
115 
navigateToScreenLock()116     private void navigateToScreenLock() throws Exception {
117         launchSettingsPage(mInst.getContext(), Settings.ACTION_SECURITY_SETTINGS);
118         mDevice.wait(Until.findObject(By.text("Screen lock")), LONG_TIMEOUT).click();
119     }
120 
sendNotification(int id, int visibility, String title)121     public void sendNotification(int id, int visibility, String title) throws Exception {
122         sendNotification(id, visibility, title, false);
123     }
124 
sendNotification(int id, int visibility, String title, boolean buzz)125     public void sendNotification(int id, int visibility, String title, boolean buzz)
126             throws Exception {
127         Log.v(LOG_TAG, "Sending out notification...");
128         PendingIntent emptyIntent = PendingIntent.getBroadcast(mContext, 0,
129                 new Intent("an.action.that.nobody.will.be.listening.for"),
130                 PendingIntent.FLAG_IMMUTABLE);
131         Intent intent = new Intent(Intent.ACTION_VIEW);
132         PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent,
133                 PendingIntent.FLAG_IMMUTABLE);
134         CharSequence subtitle = String.valueOf(System.currentTimeMillis());
135         Notification.Builder notification = new Notification.Builder(mContext)
136                 .setSmallIcon(R.drawable.stat_notify_email)
137                 .setWhen(System.currentTimeMillis())
138                 .setContentTitle(title)
139                 .setContentText(subtitle)
140                 .setContentIntent(pendingIntent)
141                 .setVisibility(visibility)
142                 .setChannelId(buzz ? BUZZY_CHANNEL_ID : QUIET_CHANNEL_ID)
143                 .addAction(new Notification.Action.Builder(R.drawable.stat_notify_email,
144                         FIRST_ACTION, emptyIntent)
145                         .build())
146                 .addAction(new Notification.Action.Builder(R.drawable.stat_notify_email,
147                         SECOND_ACTION, emptyIntent)
148                         .build())
149                 .setAutoCancel(false);
150         mNotificationManager.notify(id, notification.build());
151         Thread.sleep(LONG_TIMEOUT);
152     }
153 
sendNotifications(Map<Integer, String> lists, boolean withDelay)154     public void sendNotifications(Map<Integer, String> lists, boolean withDelay) throws Exception {
155         Log.v(LOG_TAG, "Sending out notification...");
156         CharSequence subtitle = String.valueOf(System.currentTimeMillis());
157         for (Map.Entry<Integer, String> l : lists.entrySet()) {
158             Notification.Builder notification = new Notification.Builder(mContext)
159                     .setSmallIcon(R.drawable.stat_notify_email)
160                     .setWhen(System.currentTimeMillis()).setContentTitle(l.getValue())
161                     .setContentTitle(CONTENT_TITLE)
162                     .setContentText(subtitle);
163             mNotificationManager.notify(l.getKey(), notification.build());
164             if (withDelay) {
165                 Thread.sleep(SHORT_TIMEOUT);
166             }
167         }
168         Thread.sleep(LONG_TIMEOUT);
169     }
170 
sendBundlingNotifications(List<Integer> lists, String groupKey)171     public void sendBundlingNotifications(List<Integer> lists, String groupKey) throws Exception {
172         Notification childNotification = new Notification.Builder(mContext)
173                 .setContentTitle(lists.get(1).toString())
174                 .setSmallIcon(R.drawable.stat_notify_email)
175                 .setGroup(groupKey)
176                 .build();
177         mNotificationManager.notify(lists.get(1),
178                 childNotification);
179         childNotification = new Notification.Builder(mContext)
180                 .setContentText(lists.get(2).toString())
181                 .setSmallIcon(R.drawable.stat_notify_email)
182                 .setGroup(groupKey)
183                 .build();
184         mNotificationManager.notify(lists.get(2),
185                 childNotification);
186         Notification notification = new Notification.Builder(mContext)
187                 .setContentTitle(lists.get(0).toString())
188                 .setSubText(groupKey)
189                 .setSmallIcon(R.drawable.stat_notify_email)
190                 .setGroup(groupKey)
191                 .setGroupSummary(true)
192                 .build();
193         mNotificationManager.notify(lists.get(0),
194                 notification);
195     }
196 
BOLD(CharSequence str)197     static SpannableStringBuilder BOLD(CharSequence str) {
198         final SpannableStringBuilder ssb = new SpannableStringBuilder(str);
199         ssb.setSpan(new StyleSpan(Typeface.BOLD), 0, ssb.length(), 0);
200         return ssb;
201     }
202 
checkNotificationExistence(int id, boolean exists)203     public boolean checkNotificationExistence(int id, boolean exists) throws Exception {
204         boolean isFound = false;
205         for (int tries = 3; tries-- > 0;) {
206             isFound = false;
207             StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
208             for (StatusBarNotification sbn : sbns) {
209                 if (sbn.getId() == id) {
210                     isFound = true;
211                     break;
212                 }
213             }
214             if (isFound == exists) {
215                 break;
216             }
217             Thread.sleep(SHORT_TIMEOUT);
218         }
219         Log.i(LOG_TAG, "checkNotificationExistence..." + isFound);
220         return isFound == exists;
221     }
222 
getStatusBarNotification(int id)223     public StatusBarNotification getStatusBarNotification(int id) {
224         StatusBarNotification[] sbns = mNotificationManager.getActiveNotifications();
225         StatusBarNotification n = null;
226         for (StatusBarNotification sbn : sbns) {
227             if (sbn.getId() == id) {
228                 n = sbn;
229                 break;
230             }
231         }
232         return n;
233     }
234 
swipeUp()235     public void swipeUp() throws Exception {
236         mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight()*3/4,
237                 mDevice.getDisplayWidth() / 2, 0, 30);
238         Thread.sleep(SHORT_TIMEOUT);
239     }
240 
swipeDown()241     public void swipeDown() throws Exception {
242         mDevice.swipe(mDevice.getDisplayWidth() / 2, 0, mDevice.getDisplayWidth() / 2,
243                 mDevice.getDisplayHeight() / 2 + 50, 20);
244         Thread.sleep(SHORT_TIMEOUT);
245     }
246 
unlockScreen()247     public void unlockScreen() throws Exception {
248         KeyguardManager myKM = (KeyguardManager) mContext
249                 .getSystemService(Context.KEYGUARD_SERVICE);
250         if (myKM.inKeyguardRestrictedInputMode()) {
251             // it is locked
252             swipeUp();
253         }
254     }
255 
showAppNotificationSettings(Context context)256     public void showAppNotificationSettings(Context context) throws Exception {
257         Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
258         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
259         intent.putExtra(Settings.EXTRA_APP_PACKAGE, mContext.getPackageName());
260         intent.putExtra(Settings.EXTRA_APP_UID, mContext.getApplicationInfo().uid);
261         context.startActivity(intent);
262         Thread.sleep(LONG_TIMEOUT * 2);
263     }
264 
sendNotificationsWithInlineReply(int notificationId, boolean isHeadsUp)265     public void sendNotificationsWithInlineReply(int notificationId, boolean isHeadsUp) {
266         Notification.Action action = new Notification.Action.Builder(
267                 R.drawable.stat_notify_email, "Reply", ToastService.getPendingIntent(mContext,
268                         "inline reply test"))
269                                 .addRemoteInput(new RemoteInput.Builder(KEY_QUICK_REPLY_TEXT)
270                                         .setLabel("Quick reply").build())
271                                 .build();
272         Notification.Builder n = new Notification.Builder(mContext)
273                 .setContentTitle(Integer.toString(notificationId))
274                 .setContentText("INLINE REPLY TEST")
275                 .setWhen(System.currentTimeMillis())
276                 .setSmallIcon(R.drawable.stat_notify_email)
277                 .addAction(action);
278         if (isHeadsUp) {
279             n.setPriority(Notification.PRIORITY_HIGH)
280                     .setDefaults(Notification.DEFAULT_VIBRATE);
281         }
282         mNotificationManager.notify(notificationId, n.build());
283     }
284 
getDefaultChannel()285     public NotificationChannel getDefaultChannel() {
286         return mNotificationManager.getNotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID);
287     }
288 
getChannel(boolean buzz)289     public NotificationChannel getChannel(boolean buzz) {
290         String id = (buzz ? BUZZY_CHANNEL_ID : QUIET_CHANNEL_ID);
291         String name = (buzz ? "This channel is buzzy" : "This channel is quiet");
292         int importance = (buzz ? IMPORTANCE_DEFAULT : IMPORTANCE_LOW);
293 
294         NotificationChannel channel = (buzz ? mBuzzyChannel : mQuietChannel);
295         if (channel == null) {
296             channel = mNotificationManager.getNotificationChannel(id);
297         }
298         if (channel == null){
299             channel = new NotificationChannel(id, name, importance);
300             if (buzz) {
301                 channel.enableVibration(true);
302                 channel.setSound(null, null);
303             }
304             mNotificationManager.createNotificationChannel(channel);
305         }
306         return channel;
307     }
308 
309     public static class ToastService extends IntentService {
310         private static final String TAG = "ToastService";
311         private static final String ACTION_TOAST = "toast";
312         private Handler handler;
313 
ToastService()314         public ToastService() {
315             super(TAG);
316         }
317 
ToastService(String name)318         public ToastService(String name) {
319             super(name);
320         }
321 
322         @Override
onStartCommand(Intent intent, int flags, int startId)323         public int onStartCommand(Intent intent, int flags, int startId) {
324             handler = new Handler();
325             return super.onStartCommand(intent, flags, startId);
326         }
327 
328         @Override
onHandleIntent(Intent intent)329         protected void onHandleIntent(Intent intent) {
330             if (intent.hasExtra("text")) {
331                 final String text = intent.getStringExtra("text");
332                 handler.post(new Runnable() {
333                     @Override
334                     public void run() {
335                         Toast.makeText(ToastService.this, text, Toast.LENGTH_LONG).show();
336                         Log.v(TAG, "toast " + text);
337                     }
338                 });
339             }
340         }
341 
getPendingIntent(Context context, String text)342         public static PendingIntent getPendingIntent(Context context, String text) {
343             Intent toastIntent = new Intent(context, ToastService.class);
344             toastIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
345             toastIntent.setAction(ACTION_TOAST + ":" + text); // one per toast message
346             toastIntent.putExtra("text", text);
347             PendingIntent pi = PendingIntent.getService(
348                     context, 58, toastIntent,
349                     PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
350             return pi;
351         }
352     }
353 }
354