blob: 7063ddf3e65315873e74a3cd6bab606b2b842678 [file] [log] [blame]
Selim Cinek6fd06b52017-03-07 15:54:10 -08001/*
2 * Copyright (C) 2017 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
17package com.android.systemui.statusbar;
18
Mady Mellorfc02cc32019-04-01 14:47:55 -070019import static android.app.Notification.FLAG_BUBBLE;
Julia Reynolds0abae112018-06-08 10:36:57 -040020import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
Mady Mellorb4991e62019-01-10 15:14:51 -080021import static android.app.NotificationManager.IMPORTANCE_HIGH;
Julia Reynolds0abae112018-06-08 10:36:57 -040022
Selim Cinekc3fec682019-06-06 18:11:07 -070023import static org.mockito.Mockito.mock;
24
Rohan Shah524cf7b2018-03-15 14:40:02 -070025import android.annotation.Nullable;
Selim Cinek6fd06b52017-03-07 15:54:10 -080026import android.app.ActivityManager;
Selim Cinek5ba22542017-04-20 15:16:10 -070027import android.app.Instrumentation;
Selim Cinek6fd06b52017-03-07 15:54:10 -080028import android.app.Notification;
Mark Renouf08bc42a2019-03-07 13:01:59 -050029import android.app.Notification.BubbleMetadata;
Julia Reynolds0abae112018-06-08 10:36:57 -040030import android.app.NotificationChannel;
Mady Mellorb4991e62019-01-10 15:14:51 -080031import android.app.PendingIntent;
Selim Cinek6fd06b52017-03-07 15:54:10 -080032import android.content.Context;
Mady Mellorb4991e62019-01-10 15:14:51 -080033import android.content.Intent;
Mady Mellorc39b4ae2019-01-09 17:11:37 -080034import android.graphics.drawable.Icon;
Selim Cinek6fd06b52017-03-07 15:54:10 -080035import android.os.UserHandle;
36import android.service.notification.StatusBarNotification;
Rohan Shah524cf7b2018-03-15 14:40:02 -070037import android.text.TextUtils;
Selim Cinek6fd06b52017-03-07 15:54:10 -080038import android.view.LayoutInflater;
39import android.widget.RemoteViews;
40
Brett Chabot84151d92019-02-27 15:37:59 -080041import androidx.test.InstrumentationRegistry;
42
Selim Cinek6fd06b52017-03-07 15:54:10 -080043import com.android.systemui.R;
Mark Renoufa9fbb6e2019-02-11 12:48:22 -050044import com.android.systemui.bubbles.BubblesTestActivity;
Selim Cinekc3fec682019-06-06 18:11:07 -070045import com.android.systemui.plugins.statusbar.StatusBarStateController;
Ned Burnsf81c4c42019-01-07 14:10:43 -050046import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Mady Mellorebdbbb92018-11-15 14:36:48 -080047import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Ned Burns1a5e22f2019-02-14 15:11:52 -050048import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
49import com.android.systemui.statusbar.notification.row.NotificationContentInflaterTest;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090050import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
Selim Cinekd21232e2019-06-20 14:15:59 -070051import com.android.systemui.statusbar.phone.KeyguardBypassController;
Selim Cinek6fd06b52017-03-07 15:54:10 -080052import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek5cf1d052017-06-01 17:36:46 -070053import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek6fd06b52017-03-07 15:54:10 -080054
55/**
Rohan Shah524cf7b2018-03-15 14:40:02 -070056 * A helper class to create {@link ExpandableNotificationRow} (for both individual and group
57 * notifications).
Selim Cinek6fd06b52017-03-07 15:54:10 -080058 */
59public class NotificationTestHelper {
60
Rohan Shah20790b82018-07-02 17:21:04 -070061 /** Package name for testing purposes. */
62 public static final String PKG = "com.android.systemui";
63 /** System UI id for testing purposes. */
64 public static final int UID = 1000;
Yohei Yukawa72769462019-01-20 09:28:08 -080065 /** Current {@link UserHandle} of the system. */
66 public static final UserHandle USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser());
Rohan Shah20790b82018-07-02 17:21:04 -070067
Rohan Shah524cf7b2018-03-15 14:40:02 -070068 private static final String GROUP_KEY = "gruKey";
69
Selim Cinek6fd06b52017-03-07 15:54:10 -080070 private final Context mContext;
Selim Cinek5ba22542017-04-20 15:16:10 -070071 private final Instrumentation mInstrumentation;
Selim Cinek6fd06b52017-03-07 15:54:10 -080072 private int mId;
Selim Cinekc3fec682019-06-06 18:11:07 -070073 private final NotificationGroupManager mGroupManager;
Selim Cinek5ba22542017-04-20 15:16:10 -070074 private ExpandableNotificationRow mRow;
Selim Cinekc3fec682019-06-06 18:11:07 -070075 private HeadsUpManagerPhone mHeadsUpManager;
Selim Cinek6fd06b52017-03-07 15:54:10 -080076
77 public NotificationTestHelper(Context context) {
78 mContext = context;
Selim Cinek5ba22542017-04-20 15:16:10 -070079 mInstrumentation = InstrumentationRegistry.getInstrumentation();
Selim Cinekc3fec682019-06-06 18:11:07 -070080 StatusBarStateController stateController = mock(StatusBarStateController.class);
81 mGroupManager = new NotificationGroupManager(stateController);
Selim Cinekd21232e2019-06-20 14:15:59 -070082 mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController,
83 mock(KeyguardBypassController.class));
Selim Cinekc3fec682019-06-06 18:11:07 -070084 mHeadsUpManager.setUp(null, mGroupManager, null, null);
Kevina97ea052018-09-11 13:53:18 -070085 mGroupManager.setHeadsUpManager(mHeadsUpManager);
Selim Cinek6fd06b52017-03-07 15:54:10 -080086 }
87
Kevind4660b22018-09-27 10:57:35 -070088 /**
89 * Creates a generic row.
90 *
91 * @return a generic row with no special properties.
92 * @throws Exception
93 */
Rohan Shah524cf7b2018-03-15 14:40:02 -070094 public ExpandableNotificationRow createRow() throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -080095 return createRow(PKG, UID, USER_HANDLE);
Rohan Shah524cf7b2018-03-15 14:40:02 -070096 }
97
Kevind4660b22018-09-27 10:57:35 -070098 /**
99 * Create a row with the package and user id specified.
100 *
101 * @param pkg package
102 * @param uid user id
103 * @return a row with a notification using the package and user id
104 * @throws Exception
105 */
Yohei Yukawa72769462019-01-20 09:28:08 -0800106 public ExpandableNotificationRow createRow(String pkg, int uid, UserHandle userHandle)
107 throws Exception {
108 return createRow(pkg, uid, userHandle, false /* isGroupSummary */, null /* groupKey */);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700109 }
110
Kevind4660b22018-09-27 10:57:35 -0700111 /**
112 * Creates a row based off the notification given.
113 *
114 * @param notification the notification
115 * @return a row built off the notification
116 * @throws Exception
117 */
Rohan Shah524cf7b2018-03-15 14:40:02 -0700118 public ExpandableNotificationRow createRow(Notification notification) throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800119 return generateRow(notification, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */);
Kevind4660b22018-09-27 10:57:35 -0700120 }
121
122 /**
123 * Create a row with the specified content views inflated in addition to the default.
124 *
125 * @param extraInflationFlags the flags corresponding to the additional content views that
126 * should be inflated
127 * @return a row with the specified content views inflated in addition to the default
128 * @throws Exception
129 */
130 public ExpandableNotificationRow createRow(@InflationFlag int extraInflationFlags)
131 throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800132 return generateRow(createNotification(), PKG, UID, USER_HANDLE, extraInflationFlags);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700133 }
134
135 /**
136 * Returns an {@link ExpandableNotificationRow} group with the given number of child
137 * notifications.
138 */
139 public ExpandableNotificationRow createGroup(int numChildren) throws Exception {
140 ExpandableNotificationRow row = createGroupSummary(GROUP_KEY);
141 for (int i = 0; i < numChildren; i++) {
142 ExpandableNotificationRow childRow = createGroupChild(GROUP_KEY);
143 row.addChildNotification(childRow);
144 }
145 return row;
146 }
147
148 /** Returns a group notification with 2 child notifications. */
149 public ExpandableNotificationRow createGroup() throws Exception {
150 return createGroup(2);
151 }
152
153 private ExpandableNotificationRow createGroupSummary(String groupkey) throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800154 return createRow(PKG, UID, USER_HANDLE, true /* isGroupSummary */, groupkey);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700155 }
156
157 private ExpandableNotificationRow createGroupChild(String groupkey) throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800158 return createRow(PKG, UID, USER_HANDLE, false /* isGroupSummary */, groupkey);
Mady Mellorb4991e62019-01-10 15:14:51 -0800159 }
160
161 /**
162 * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
Mark Renouffec45da2019-03-13 13:24:27 -0400163 */
164 public ExpandableNotificationRow createBubble()
165 throws Exception {
Mady Mellorfc02cc32019-04-01 14:47:55 -0700166 return createBubble(makeBubbleMetadata(null), PKG);
Mark Renouffec45da2019-03-13 13:24:27 -0400167 }
168
169 /**
170 * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
Mark Renouf08bc42a2019-03-07 13:01:59 -0500171 *
172 * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
173 */
174 public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent)
175 throws Exception {
Mady Mellorfc02cc32019-04-01 14:47:55 -0700176 return createBubble(makeBubbleMetadata(deleteIntent), PKG);
Mady Mellore80930e2019-03-21 16:00:45 -0700177 }
178
179 /**
180 * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
181 *
182 * @param bubbleMetadata the {@link BubbleMetadata} to use
183 */
184 public ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata, String pkg)
185 throws Exception {
186 Notification n = createNotification(false /* isGroupSummary */,
187 null /* groupKey */, bubbleMetadata);
Mady Mellorfc02cc32019-04-01 14:47:55 -0700188 n.flags |= FLAG_BUBBLE;
Mady Melloraa8fef22019-04-11 13:36:40 -0700189 ExpandableNotificationRow row = generateRow(n, pkg, UID, USER_HANDLE,
190 0 /* extraInflationFlags */, IMPORTANCE_HIGH);
191 row.getEntry().canBubble = true;
192 return row;
Mady Mellore80930e2019-03-21 16:00:45 -0700193 }
194
195 /**
Rohan Shah524cf7b2018-03-15 14:40:02 -0700196 * Creates a notification row with the given details.
197 *
198 * @param pkg package used for creating a {@link StatusBarNotification}
199 * @param uid uid used for creating a {@link StatusBarNotification}
200 * @param isGroupSummary whether the notification row is a group summary
201 * @param groupKey the group key for the notification group used across notifications
202 * @return a row with that's either a standalone notification or a group notification if the
203 * groupKey is non-null
204 * @throws Exception
205 */
206 private ExpandableNotificationRow createRow(
207 String pkg,
208 int uid,
Yohei Yukawa72769462019-01-20 09:28:08 -0800209 UserHandle userHandle,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700210 boolean isGroupSummary,
Mady Mellorb4991e62019-01-10 15:14:51 -0800211 @Nullable String groupKey)
Rohan Shah524cf7b2018-03-15 14:40:02 -0700212 throws Exception {
Kevind4660b22018-09-27 10:57:35 -0700213 Notification notif = createNotification(isGroupSummary, groupKey);
Yohei Yukawa72769462019-01-20 09:28:08 -0800214 return generateRow(notif, pkg, uid, userHandle, 0 /* inflationFlags */);
Kevind4660b22018-09-27 10:57:35 -0700215 }
216
217 /**
218 * Creates a generic notification.
219 *
220 * @return a notification with no special properties
221 */
Julia Reynolds0c245002019-03-27 16:10:11 -0400222 public Notification createNotification() {
Kevind4660b22018-09-27 10:57:35 -0700223 return createNotification(false /* isGroupSummary */, null /* groupKey */);
224 }
225
226 /**
227 * Creates a notification with the given parameters.
228 *
229 * @param isGroupSummary whether the notification is a group summary
230 * @param groupKey the group key for the notification group used across notifications
231 * @return a notification that is in the group specified or standalone if unspecified
232 */
Mady Mellorb4991e62019-01-10 15:14:51 -0800233 private Notification createNotification(boolean isGroupSummary, @Nullable String groupKey) {
Mady Mellore80930e2019-03-21 16:00:45 -0700234 return createNotification(isGroupSummary, groupKey, null /* bubble metadata */);
Mady Mellorb4991e62019-01-10 15:14:51 -0800235 }
236
237 /**
238 * Creates a notification with the given parameters.
239 *
240 * @param isGroupSummary whether the notification is a group summary
241 * @param groupKey the group key for the notification group used across notifications
Mady Mellore80930e2019-03-21 16:00:45 -0700242 * @param bubbleMetadata the bubble metadata to use for this notification if it exists.
Mady Mellorb4991e62019-01-10 15:14:51 -0800243 * @return a notification that is in the group specified or standalone if unspecified
244 */
Mark Renouf9ba6cea2019-04-17 11:53:50 -0400245 public Notification createNotification(boolean isGroupSummary,
Mady Mellore80930e2019-03-21 16:00:45 -0700246 @Nullable String groupKey, @Nullable BubbleMetadata bubbleMetadata) {
Selim Cinek6fd06b52017-03-07 15:54:10 -0800247 Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
248 R.drawable.ic_person)
249 .setCustomContentView(new RemoteViews(mContext.getPackageName(),
250 R.layout.custom_view_dark))
251 .build();
Kevind4660b22018-09-27 10:57:35 -0700252 Notification.Builder notificationBuilder = new Notification.Builder(mContext, "channelId")
253 .setSmallIcon(R.drawable.ic_person)
254 .setContentTitle("Title")
255 .setContentText("Text")
Kevind5022f92018-10-08 18:30:26 -0700256 .setPublicVersion(publicVersion)
257 .setStyle(new Notification.BigTextStyle().bigText("Big Text"));
Rohan Shah524cf7b2018-03-15 14:40:02 -0700258 if (isGroupSummary) {
259 notificationBuilder.setGroupSummary(true);
260 }
261 if (!TextUtils.isEmpty(groupKey)) {
262 notificationBuilder.setGroup(groupKey);
263 }
Mady Mellore80930e2019-03-21 16:00:45 -0700264 if (bubbleMetadata != null) {
265 notificationBuilder.setBubbleMetadata(bubbleMetadata);
Mady Mellorb4991e62019-01-10 15:14:51 -0800266 }
Kevind4660b22018-09-27 10:57:35 -0700267 return notificationBuilder.build();
Julia Reynoldsfc640012018-02-21 12:25:27 -0500268 }
269
Rohan Shah524cf7b2018-03-15 14:40:02 -0700270 private ExpandableNotificationRow generateRow(
271 Notification notification,
272 String pkg,
273 int uid,
Yohei Yukawa72769462019-01-20 09:28:08 -0800274 UserHandle userHandle,
Mady Mellorb4991e62019-01-10 15:14:51 -0800275 @InflationFlag int extraInflationFlags)
276 throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800277 return generateRow(notification, pkg, uid, userHandle, extraInflationFlags,
278 IMPORTANCE_DEFAULT);
Mady Mellorb4991e62019-01-10 15:14:51 -0800279 }
280
281 private ExpandableNotificationRow generateRow(
282 Notification notification,
283 String pkg,
284 int uid,
Yohei Yukawa72769462019-01-20 09:28:08 -0800285 UserHandle userHandle,
Mady Mellorb4991e62019-01-10 15:14:51 -0800286 @InflationFlag int extraInflationFlags,
287 int importance)
Julia Reynoldsfc640012018-02-21 12:25:27 -0500288 throws Exception {
Selim Cinek10790672017-03-08 16:33:05 -0800289 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
290 mContext.LAYOUT_INFLATER_SERVICE);
Jason Monk6dceace2018-05-15 20:24:07 -0400291 mRow = (ExpandableNotificationRow) inflater.inflate(
292 R.layout.status_bar_notification_row,
293 null /* root */,
294 false /* attachToRoot */);
Selim Cinek5ba22542017-04-20 15:16:10 -0700295 ExpandableNotificationRow row = mRow;
Selim Cinek10790672017-03-08 16:33:05 -0800296 row.setGroupManager(mGroupManager);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700297 row.setHeadsUpManager(mHeadsUpManager);
298 row.setAboveShelfChangedListener(aboveShelf -> {});
Rohan Shah524cf7b2018-03-15 14:40:02 -0700299 StatusBarNotification sbn = new StatusBarNotification(
300 pkg,
301 pkg,
302 mId++,
303 null /* tag */,
304 uid,
305 2000 /* initialPid */,
306 notification,
Yohei Yukawa72769462019-01-20 09:28:08 -0800307 userHandle,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700308 null /* overrideGroupKey */,
309 System.currentTimeMillis());
Ned Burnsf81c4c42019-01-07 14:10:43 -0500310 NotificationEntry entry = new NotificationEntry(sbn);
Evan Laird94492852018-10-25 13:43:01 -0400311 entry.setRow(row);
Selim Cinek5ba22542017-04-20 15:16:10 -0700312 entry.createIcons(mContext, sbn);
Julia Reynolds0abae112018-06-08 10:36:57 -0400313 entry.channel = new NotificationChannel(
Mady Mellorb4991e62019-01-10 15:14:51 -0800314 notification.getChannelId(), notification.getChannelId(), importance);
Julia Reynolds0abae112018-06-08 10:36:57 -0400315 entry.channel.setBlockableSystem(true);
Kevind4660b22018-09-27 10:57:35 -0700316 row.setEntry(entry);
317 row.getNotificationInflater().addInflationFlags(extraInflationFlags);
Ned Burns1a5e22f2019-02-14 15:11:52 -0500318 NotificationContentInflaterTest.runThenWaitForInflation(
Kevind4660b22018-09-27 10:57:35 -0700319 () -> row.inflateViews(),
Selim Cinek5ba22542017-04-20 15:16:10 -0700320 row.getNotificationInflater());
Selim Cinek6fd06b52017-03-07 15:54:10 -0800321
Rohan Shah524cf7b2018-03-15 14:40:02 -0700322 // This would be done as part of onAsyncInflationFinished, but we skip large amounts of
323 // the callback chain, so we need to make up for not adding it to the group manager
324 // here.
325 mGroupManager.onEntryAdded(entry);
Selim Cinek6fd06b52017-03-07 15:54:10 -0800326 return row;
327 }
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800328
Mark Renouf08bc42a2019-03-07 13:01:59 -0500329 private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent) {
Mark Renoufa9fbb6e2019-02-11 12:48:22 -0500330 Intent target = new Intent(mContext, BubblesTestActivity.class);
331 PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
Mark Renouf08bc42a2019-03-07 13:01:59 -0500332
333 return new BubbleMetadata.Builder()
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800334 .setIntent(bubbleIntent)
Mark Renouf08bc42a2019-03-07 13:01:59 -0500335 .setDeleteIntent(deleteIntent)
Mady Mellor9848a6c2019-03-19 15:29:05 -0700336 .setIcon(Icon.createWithResource(mContext, R.drawable.android))
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800337 .setDesiredHeight(314)
338 .build();
339 }
Selim Cinek6fd06b52017-03-07 15:54:10 -0800340}