blob: de155055b76b1f572b1495793144ddac9317f803 [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
Julia Reynolds0abae112018-06-08 10:36:57 -040019import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
Mady Mellorb4991e62019-01-10 15:14:51 -080020import static android.app.NotificationManager.IMPORTANCE_HIGH;
Julia Reynolds0abae112018-06-08 10:36:57 -040021
Rohan Shah524cf7b2018-03-15 14:40:02 -070022import android.annotation.Nullable;
Selim Cinek6fd06b52017-03-07 15:54:10 -080023import android.app.ActivityManager;
Selim Cinek5ba22542017-04-20 15:16:10 -070024import android.app.Instrumentation;
Selim Cinek6fd06b52017-03-07 15:54:10 -080025import android.app.Notification;
Mark Renouf08bc42a2019-03-07 13:01:59 -050026import android.app.Notification.BubbleMetadata;
Julia Reynolds0abae112018-06-08 10:36:57 -040027import android.app.NotificationChannel;
Mady Mellorb4991e62019-01-10 15:14:51 -080028import android.app.PendingIntent;
Selim Cinek6fd06b52017-03-07 15:54:10 -080029import android.content.Context;
Mady Mellorb4991e62019-01-10 15:14:51 -080030import android.content.Intent;
Mady Mellorc39b4ae2019-01-09 17:11:37 -080031import android.graphics.drawable.Icon;
Selim Cinek6fd06b52017-03-07 15:54:10 -080032import android.os.UserHandle;
33import android.service.notification.StatusBarNotification;
Rohan Shah524cf7b2018-03-15 14:40:02 -070034import android.text.TextUtils;
Selim Cinek6fd06b52017-03-07 15:54:10 -080035import android.view.LayoutInflater;
36import android.widget.RemoteViews;
37
Brett Chabot84151d92019-02-27 15:37:59 -080038import androidx.test.InstrumentationRegistry;
39
Selim Cinek6fd06b52017-03-07 15:54:10 -080040import com.android.systemui.R;
Mark Renoufa9fbb6e2019-02-11 12:48:22 -050041import com.android.systemui.bubbles.BubblesTestActivity;
Ned Burnsf81c4c42019-01-07 14:10:43 -050042import com.android.systemui.statusbar.notification.collection.NotificationEntry;
Mady Mellorebdbbb92018-11-15 14:36:48 -080043import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
Ned Burns1a5e22f2019-02-14 15:11:52 -050044import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
45import com.android.systemui.statusbar.notification.row.NotificationContentInflaterTest;
yoshiki iguchi4e30e762018-02-06 12:09:23 +090046import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
Selim Cinek6fd06b52017-03-07 15:54:10 -080047import com.android.systemui.statusbar.phone.NotificationGroupManager;
Selim Cinek5cf1d052017-06-01 17:36:46 -070048import com.android.systemui.statusbar.policy.HeadsUpManager;
Selim Cinek6fd06b52017-03-07 15:54:10 -080049
50/**
Rohan Shah524cf7b2018-03-15 14:40:02 -070051 * A helper class to create {@link ExpandableNotificationRow} (for both individual and group
52 * notifications).
Selim Cinek6fd06b52017-03-07 15:54:10 -080053 */
54public class NotificationTestHelper {
55
Rohan Shah20790b82018-07-02 17:21:04 -070056 /** Package name for testing purposes. */
57 public static final String PKG = "com.android.systemui";
58 /** System UI id for testing purposes. */
59 public static final int UID = 1000;
Yohei Yukawa72769462019-01-20 09:28:08 -080060 /** Current {@link UserHandle} of the system. */
61 public static final UserHandle USER_HANDLE = UserHandle.of(ActivityManager.getCurrentUser());
Rohan Shah20790b82018-07-02 17:21:04 -070062
Rohan Shah524cf7b2018-03-15 14:40:02 -070063 private static final String GROUP_KEY = "gruKey";
64
Selim Cinek6fd06b52017-03-07 15:54:10 -080065 private final Context mContext;
Selim Cinek5ba22542017-04-20 15:16:10 -070066 private final Instrumentation mInstrumentation;
Selim Cinek6fd06b52017-03-07 15:54:10 -080067 private int mId;
68 private final NotificationGroupManager mGroupManager = new NotificationGroupManager();
Selim Cinek5ba22542017-04-20 15:16:10 -070069 private ExpandableNotificationRow mRow;
Selim Cinek5cf1d052017-06-01 17:36:46 -070070 private HeadsUpManager mHeadsUpManager;
Selim Cinek6fd06b52017-03-07 15:54:10 -080071
72 public NotificationTestHelper(Context context) {
73 mContext = context;
Selim Cinek5ba22542017-04-20 15:16:10 -070074 mInstrumentation = InstrumentationRegistry.getInstrumentation();
yoshiki iguchi4e30e762018-02-06 12:09:23 +090075 mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null);
Kevina97ea052018-09-11 13:53:18 -070076 mGroupManager.setHeadsUpManager(mHeadsUpManager);
Selim Cinek6fd06b52017-03-07 15:54:10 -080077 }
78
Kevind4660b22018-09-27 10:57:35 -070079 /**
80 * Creates a generic row.
81 *
82 * @return a generic row with no special properties.
83 * @throws Exception
84 */
Rohan Shah524cf7b2018-03-15 14:40:02 -070085 public ExpandableNotificationRow createRow() throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -080086 return createRow(PKG, UID, USER_HANDLE);
Rohan Shah524cf7b2018-03-15 14:40:02 -070087 }
88
Kevind4660b22018-09-27 10:57:35 -070089 /**
90 * Create a row with the package and user id specified.
91 *
92 * @param pkg package
93 * @param uid user id
94 * @return a row with a notification using the package and user id
95 * @throws Exception
96 */
Yohei Yukawa72769462019-01-20 09:28:08 -080097 public ExpandableNotificationRow createRow(String pkg, int uid, UserHandle userHandle)
98 throws Exception {
99 return createRow(pkg, uid, userHandle, false /* isGroupSummary */, null /* groupKey */);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700100 }
101
Kevind4660b22018-09-27 10:57:35 -0700102 /**
103 * Creates a row based off the notification given.
104 *
105 * @param notification the notification
106 * @return a row built off the notification
107 * @throws Exception
108 */
Rohan Shah524cf7b2018-03-15 14:40:02 -0700109 public ExpandableNotificationRow createRow(Notification notification) throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800110 return generateRow(notification, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */);
Kevind4660b22018-09-27 10:57:35 -0700111 }
112
113 /**
114 * Create a row with the specified content views inflated in addition to the default.
115 *
116 * @param extraInflationFlags the flags corresponding to the additional content views that
117 * should be inflated
118 * @return a row with the specified content views inflated in addition to the default
119 * @throws Exception
120 */
121 public ExpandableNotificationRow createRow(@InflationFlag int extraInflationFlags)
122 throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800123 return generateRow(createNotification(), PKG, UID, USER_HANDLE, extraInflationFlags);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700124 }
125
126 /**
127 * Returns an {@link ExpandableNotificationRow} group with the given number of child
128 * notifications.
129 */
130 public ExpandableNotificationRow createGroup(int numChildren) throws Exception {
131 ExpandableNotificationRow row = createGroupSummary(GROUP_KEY);
132 for (int i = 0; i < numChildren; i++) {
133 ExpandableNotificationRow childRow = createGroupChild(GROUP_KEY);
134 row.addChildNotification(childRow);
135 }
136 return row;
137 }
138
139 /** Returns a group notification with 2 child notifications. */
140 public ExpandableNotificationRow createGroup() throws Exception {
141 return createGroup(2);
142 }
143
144 private ExpandableNotificationRow createGroupSummary(String groupkey) throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800145 return createRow(PKG, UID, USER_HANDLE, true /* isGroupSummary */, groupkey);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700146 }
147
148 private ExpandableNotificationRow createGroupChild(String groupkey) throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800149 return createRow(PKG, UID, USER_HANDLE, false /* isGroupSummary */, groupkey);
Mady Mellorb4991e62019-01-10 15:14:51 -0800150 }
151
152 /**
153 * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
154 */
155 public ExpandableNotificationRow createBubble() throws Exception {
Mark Renouf08bc42a2019-03-07 13:01:59 -0500156 return createBubble(null);
157 }
158
159 /**
160 * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble.
161 *
162 * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
163 */
164 public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent)
165 throws Exception {
Mady Mellorb4991e62019-01-10 15:14:51 -0800166 Notification n = createNotification(false /* isGroupSummary */,
Mark Renouf08bc42a2019-03-07 13:01:59 -0500167 null /* groupKey */, true /* isBubble */, deleteIntent);
Yohei Yukawa72769462019-01-20 09:28:08 -0800168 return generateRow(n, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH);
Rohan Shah524cf7b2018-03-15 14:40:02 -0700169 }
170
171 /**
172 * Creates a notification row with the given details.
173 *
174 * @param pkg package used for creating a {@link StatusBarNotification}
175 * @param uid uid used for creating a {@link StatusBarNotification}
176 * @param isGroupSummary whether the notification row is a group summary
177 * @param groupKey the group key for the notification group used across notifications
178 * @return a row with that's either a standalone notification or a group notification if the
179 * groupKey is non-null
180 * @throws Exception
181 */
182 private ExpandableNotificationRow createRow(
183 String pkg,
184 int uid,
Yohei Yukawa72769462019-01-20 09:28:08 -0800185 UserHandle userHandle,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700186 boolean isGroupSummary,
Mady Mellorb4991e62019-01-10 15:14:51 -0800187 @Nullable String groupKey)
Rohan Shah524cf7b2018-03-15 14:40:02 -0700188 throws Exception {
Kevind4660b22018-09-27 10:57:35 -0700189 Notification notif = createNotification(isGroupSummary, groupKey);
Yohei Yukawa72769462019-01-20 09:28:08 -0800190 return generateRow(notif, pkg, uid, userHandle, 0 /* inflationFlags */);
Kevind4660b22018-09-27 10:57:35 -0700191 }
192
193 /**
194 * Creates a generic notification.
195 *
196 * @return a notification with no special properties
197 */
198 private Notification createNotification() {
199 return createNotification(false /* isGroupSummary */, null /* groupKey */);
200 }
201
202 /**
203 * Creates a notification with the given parameters.
204 *
205 * @param isGroupSummary whether the notification is a group summary
206 * @param groupKey the group key for the notification group used across notifications
207 * @return a notification that is in the group specified or standalone if unspecified
208 */
Mady Mellorb4991e62019-01-10 15:14:51 -0800209 private Notification createNotification(boolean isGroupSummary, @Nullable String groupKey) {
Mark Renouf08bc42a2019-03-07 13:01:59 -0500210 return createNotification(isGroupSummary, groupKey, false /* isBubble */,
211 null /* bubbleDeleteIntent */);
Mady Mellorb4991e62019-01-10 15:14:51 -0800212 }
213
214 /**
215 * Creates a notification with the given parameters.
216 *
217 * @param isGroupSummary whether the notification is a group summary
218 * @param groupKey the group key for the notification group used across notifications
219 * @param isBubble whether this notification should bubble
220 * @return a notification that is in the group specified or standalone if unspecified
221 */
Kevind4660b22018-09-27 10:57:35 -0700222 private Notification createNotification(boolean isGroupSummary,
Mark Renouf08bc42a2019-03-07 13:01:59 -0500223 @Nullable String groupKey, boolean isBubble,
224 @Nullable PendingIntent bubbleDeleteIntent) {
Selim Cinek6fd06b52017-03-07 15:54:10 -0800225 Notification publicVersion = new Notification.Builder(mContext).setSmallIcon(
226 R.drawable.ic_person)
227 .setCustomContentView(new RemoteViews(mContext.getPackageName(),
228 R.layout.custom_view_dark))
229 .build();
Kevind4660b22018-09-27 10:57:35 -0700230 Notification.Builder notificationBuilder = new Notification.Builder(mContext, "channelId")
231 .setSmallIcon(R.drawable.ic_person)
232 .setContentTitle("Title")
233 .setContentText("Text")
Kevind5022f92018-10-08 18:30:26 -0700234 .setPublicVersion(publicVersion)
235 .setStyle(new Notification.BigTextStyle().bigText("Big Text"));
Rohan Shah524cf7b2018-03-15 14:40:02 -0700236 if (isGroupSummary) {
237 notificationBuilder.setGroupSummary(true);
238 }
239 if (!TextUtils.isEmpty(groupKey)) {
240 notificationBuilder.setGroup(groupKey);
241 }
Mady Mellorb4991e62019-01-10 15:14:51 -0800242 if (isBubble) {
Mark Renouf08bc42a2019-03-07 13:01:59 -0500243 BubbleMetadata metadata = makeBubbleMetadata(bubbleDeleteIntent);
244 notificationBuilder.setBubbleMetadata(metadata);
Mady Mellorb4991e62019-01-10 15:14:51 -0800245 }
Kevind4660b22018-09-27 10:57:35 -0700246 return notificationBuilder.build();
Julia Reynoldsfc640012018-02-21 12:25:27 -0500247 }
248
Rohan Shah524cf7b2018-03-15 14:40:02 -0700249 private ExpandableNotificationRow generateRow(
250 Notification notification,
251 String pkg,
252 int uid,
Yohei Yukawa72769462019-01-20 09:28:08 -0800253 UserHandle userHandle,
Mady Mellorb4991e62019-01-10 15:14:51 -0800254 @InflationFlag int extraInflationFlags)
255 throws Exception {
Yohei Yukawa72769462019-01-20 09:28:08 -0800256 return generateRow(notification, pkg, uid, userHandle, extraInflationFlags,
257 IMPORTANCE_DEFAULT);
Mady Mellorb4991e62019-01-10 15:14:51 -0800258 }
259
260 private ExpandableNotificationRow generateRow(
261 Notification notification,
262 String pkg,
263 int uid,
Yohei Yukawa72769462019-01-20 09:28:08 -0800264 UserHandle userHandle,
Mady Mellorb4991e62019-01-10 15:14:51 -0800265 @InflationFlag int extraInflationFlags,
266 int importance)
Julia Reynoldsfc640012018-02-21 12:25:27 -0500267 throws Exception {
Selim Cinek10790672017-03-08 16:33:05 -0800268 LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
269 mContext.LAYOUT_INFLATER_SERVICE);
Jason Monk6dceace2018-05-15 20:24:07 -0400270 mRow = (ExpandableNotificationRow) inflater.inflate(
271 R.layout.status_bar_notification_row,
272 null /* root */,
273 false /* attachToRoot */);
Selim Cinek5ba22542017-04-20 15:16:10 -0700274 ExpandableNotificationRow row = mRow;
Selim Cinek10790672017-03-08 16:33:05 -0800275 row.setGroupManager(mGroupManager);
Selim Cinek5cf1d052017-06-01 17:36:46 -0700276 row.setHeadsUpManager(mHeadsUpManager);
277 row.setAboveShelfChangedListener(aboveShelf -> {});
Rohan Shah524cf7b2018-03-15 14:40:02 -0700278 StatusBarNotification sbn = new StatusBarNotification(
279 pkg,
280 pkg,
281 mId++,
282 null /* tag */,
283 uid,
284 2000 /* initialPid */,
285 notification,
Yohei Yukawa72769462019-01-20 09:28:08 -0800286 userHandle,
Rohan Shah524cf7b2018-03-15 14:40:02 -0700287 null /* overrideGroupKey */,
288 System.currentTimeMillis());
Ned Burnsf81c4c42019-01-07 14:10:43 -0500289 NotificationEntry entry = new NotificationEntry(sbn);
Evan Laird94492852018-10-25 13:43:01 -0400290 entry.setRow(row);
Selim Cinek5ba22542017-04-20 15:16:10 -0700291 entry.createIcons(mContext, sbn);
Julia Reynolds0abae112018-06-08 10:36:57 -0400292 entry.channel = new NotificationChannel(
Mady Mellorb4991e62019-01-10 15:14:51 -0800293 notification.getChannelId(), notification.getChannelId(), importance);
Julia Reynolds0abae112018-06-08 10:36:57 -0400294 entry.channel.setBlockableSystem(true);
Kevind4660b22018-09-27 10:57:35 -0700295 row.setEntry(entry);
296 row.getNotificationInflater().addInflationFlags(extraInflationFlags);
Ned Burns1a5e22f2019-02-14 15:11:52 -0500297 NotificationContentInflaterTest.runThenWaitForInflation(
Kevind4660b22018-09-27 10:57:35 -0700298 () -> row.inflateViews(),
Selim Cinek5ba22542017-04-20 15:16:10 -0700299 row.getNotificationInflater());
Selim Cinek6fd06b52017-03-07 15:54:10 -0800300
Rohan Shah524cf7b2018-03-15 14:40:02 -0700301 // This would be done as part of onAsyncInflationFinished, but we skip large amounts of
302 // the callback chain, so we need to make up for not adding it to the group manager
303 // here.
304 mGroupManager.onEntryAdded(entry);
Selim Cinek6fd06b52017-03-07 15:54:10 -0800305 return row;
306 }
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800307
Mark Renouf08bc42a2019-03-07 13:01:59 -0500308 private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent) {
Mark Renoufa9fbb6e2019-02-11 12:48:22 -0500309 Intent target = new Intent(mContext, BubblesTestActivity.class);
310 PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0);
Mark Renouf08bc42a2019-03-07 13:01:59 -0500311
312 return new BubbleMetadata.Builder()
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800313 .setIntent(bubbleIntent)
Mark Renouf08bc42a2019-03-07 13:01:59 -0500314 .setDeleteIntent(deleteIntent)
Mady Mellorc39b4ae2019-01-09 17:11:37 -0800315 .setTitle("bubble title")
316 .setIcon(Icon.createWithResource(mContext, 1))
317 .setDesiredHeight(314)
318 .build();
319 }
Selim Cinek6fd06b52017-03-07 15:54:10 -0800320}