1 /*
2  * Copyright (C) 2018 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.systemui.statusbar.notification.row;
18 
19 import static android.app.AppOpsManager.OP_CAMERA;
20 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
21 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
22 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
23 import static android.app.NotificationManager.IMPORTANCE_HIGH;
24 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
25 
26 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
27 
28 import static junit.framework.Assert.assertNotNull;
29 import static junit.framework.Assert.assertTrue;
30 
31 import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.fail;
35 import static org.mockito.ArgumentMatchers.any;
36 import static org.mockito.ArgumentMatchers.anyBoolean;
37 import static org.mockito.ArgumentMatchers.anyInt;
38 import static org.mockito.ArgumentMatchers.eq;
39 import static org.mockito.Mockito.doNothing;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.never;
42 import static org.mockito.Mockito.spy;
43 import static org.mockito.Mockito.times;
44 import static org.mockito.Mockito.verify;
45 import static org.mockito.Mockito.when;
46 
47 import android.app.INotificationManager;
48 import android.app.Notification;
49 import android.app.NotificationChannel;
50 import android.content.Intent;
51 import android.content.pm.LauncherApps;
52 import android.content.pm.PackageManager;
53 import android.content.pm.ShortcutManager;
54 import android.graphics.Color;
55 import android.os.Binder;
56 import android.os.Handler;
57 import android.os.UserManager;
58 import android.provider.Settings;
59 import android.service.notification.StatusBarNotification;
60 import android.testing.TestableLooper;
61 import android.util.ArraySet;
62 import android.view.View;
63 import android.view.accessibility.AccessibilityManager;
64 
65 import androidx.test.ext.junit.runners.AndroidJUnit4;
66 import androidx.test.filters.SmallTest;
67 
68 import com.android.internal.logging.MetricsLogger;
69 import com.android.internal.logging.UiEventLogger;
70 import com.android.internal.logging.testing.UiEventLoggerFake;
71 import com.android.internal.statusbar.IStatusBarService;
72 import com.android.systemui.SysuiTestCase;
73 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
74 import com.android.systemui.kosmos.KosmosJavaAdapter;
75 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
76 import com.android.systemui.plugins.ActivityStarter;
77 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
78 import com.android.systemui.plugins.statusbar.StatusBarStateController;
79 import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
80 import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository;
81 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
82 import com.android.systemui.settings.UserContextProvider;
83 import com.android.systemui.shade.ShadeController;
84 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
85 import com.android.systemui.statusbar.NotificationPresenter;
86 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
87 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
88 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
89 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
90 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository;
91 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor;
92 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
93 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
94 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
95 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
96 import com.android.systemui.statusbar.policy.HeadsUpManager;
97 import com.android.systemui.util.concurrency.FakeExecutor;
98 import com.android.systemui.util.kotlin.JavaAdapter;
99 import com.android.systemui.wmshell.BubblesManager;
100 
101 import kotlinx.coroutines.test.TestScope;
102 
103 import org.junit.Before;
104 import org.junit.Rule;
105 import org.junit.Test;
106 import org.junit.runner.RunWith;
107 import org.mockito.ArgumentCaptor;
108 import org.mockito.Mock;
109 import org.mockito.junit.MockitoJUnit;
110 import org.mockito.junit.MockitoRule;
111 
112 import java.util.Optional;
113 
114 /**
115  * Tests for {@link NotificationGutsManager}.
116  */
117 @SmallTest
118 @RunWith(AndroidJUnit4.class)
119 @TestableLooper.RunWithLooper
120 public class NotificationGutsManagerTest extends SysuiTestCase {
121     private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
122 
123     private NotificationChannel mTestNotificationChannel = new NotificationChannel(
124             TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
125 
126     private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
127     private final TestScope mTestScope = mKosmos.getTestScope();
128     private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
129     private final FakeExecutor mExecutor = mKosmos.getFakeExecutor();
130     private final Handler mHandler = mKosmos.getFakeExecutorHandler();
131     private NotificationTestHelper mHelper;
132     private NotificationGutsManager mGutsManager;
133 
134     @Rule public MockitoRule mockito = MockitoJUnit.rule();
135     @Mock private MetricsLogger mMetricsLogger;
136     @Mock private OnUserInteractionCallback mOnUserInteractionCallback;
137     @Mock private NotificationPresenter mPresenter;
138     @Mock private NotificationActivityStarter mNotificationActivityStarter;
139     @Mock private NotificationListContainer mNotificationListContainer;
140     @Mock private OnSettingsClickListener mOnSettingsClickListener;
141     @Mock private DeviceProvisionedController mDeviceProvisionedController;
142     @Mock private AccessibilityManager mAccessibilityManager;
143     @Mock private HighPriorityProvider mHighPriorityProvider;
144     @Mock private INotificationManager mINotificationManager;
145     @Mock private IStatusBarService mBarService;
146     @Mock private LauncherApps mLauncherApps;
147     @Mock private ShortcutManager mShortcutManager;
148     @Mock private ChannelEditorDialogController mChannelEditorDialogController;
149     @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
150     @Mock private UserContextProvider mContextTracker;
151     @Mock private BubblesManager mBubblesManager;
152     @Mock private ShadeController mShadeController;
153     @Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
154     @Mock private AssistantFeedbackController mAssistantFeedbackController;
155     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
156     @Mock private StatusBarStateController mStatusBarStateController;
157     @Mock private HeadsUpManager mHeadsUpManager;
158     @Mock private ActivityStarter mActivityStarter;
159 
160     @Mock private UserManager mUserManager;
161 
162     private final ActiveNotificationListRepository mActiveNotificationListRepository =
163             new ActiveNotificationListRepository();
164     private final ActiveNotificationsInteractor mActiveNotificationsInteractor =
165             new ActiveNotificationsInteractor(mActiveNotificationListRepository,
166                     StandardTestDispatcher(null, null));
167 
168     private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
169 
170     @Before
setUp()171     public void setUp() {
172         allowTestableLooperAsMainThread();
173         mHelper = new NotificationTestHelper(mContext, mDependency);
174         when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
175 
176         mWindowRootViewVisibilityInteractor = new WindowRootViewVisibilityInteractor(
177                 mTestScope.getBackgroundScope(),
178                 new WindowRootViewVisibilityRepository(mBarService, mExecutor),
179                 new FakeKeyguardRepository(),
180                 mHeadsUpManager,
181                 PowerInteractorFactory.create().getPowerInteractor(),
182                 mActiveNotificationsInteractor,
183                 () -> mKosmos.getSceneInteractor()
184         );
185 
186         mGutsManager = new NotificationGutsManager(
187                 mContext,
188                 mHandler,
189                 mHandler,
190                 mJavaAdapter,
191                 mAccessibilityManager,
192                 mHighPriorityProvider,
193                 mINotificationManager,
194                 mUserManager,
195                 mPeopleSpaceWidgetManager,
196                 mLauncherApps,
197                 mShortcutManager,
198                 mChannelEditorDialogController,
199                 mContextTracker,
200                 mAssistantFeedbackController,
201                 Optional.of(mBubblesManager),
202                 new UiEventLoggerFake(),
203                 mOnUserInteractionCallback,
204                 mShadeController,
205                 mWindowRootViewVisibilityInteractor,
206                 mNotificationLockscreenUserManager,
207                 mStatusBarStateController,
208                 mBarService,
209                 mDeviceProvisionedController,
210                 mMetricsLogger,
211                 mHeadsUpManager,
212                 mActivityStarter);
213         mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
214                 mOnSettingsClickListener);
215         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
216         mGutsManager.start();
217     }
218 
219     ////////////////////////////////////////////////////////////////////////////////////////////////
220     // Test methods:
221 
222     @Test
testOpenAndCloseGuts()223     public void testOpenAndCloseGuts() {
224         NotificationGuts guts = spy(new NotificationGuts(mContext));
225         when(guts.post(any())).thenAnswer(invocation -> {
226             mHandler.post(((Runnable) invocation.getArguments()[0]));
227             return null;
228         });
229 
230         // Test doesn't support animation since the guts view is not attached.
231         doNothing().when(guts).openControls(
232                 anyInt(),
233                 anyInt(),
234                 anyBoolean(),
235                 any(Runnable.class));
236 
237         ExpandableNotificationRow realRow = createTestNotificationRow();
238         NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow);
239 
240         ExpandableNotificationRow row = spy(realRow);
241         when(row.getWindowToken()).thenReturn(new Binder());
242         when(row.getGuts()).thenReturn(guts);
243 
244         assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
245         assertEquals(View.INVISIBLE, guts.getVisibility());
246         mExecutor.runAllReady();
247         verify(guts).openControls(
248                 anyInt(),
249                 anyInt(),
250                 anyBoolean(),
251                 any(Runnable.class));
252         verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), true);
253 
254         assertEquals(View.VISIBLE, guts.getVisibility());
255         mGutsManager.closeAndSaveGuts(false, false, true, 0, 0, false);
256 
257         verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
258         verify(row, times(1)).setGutsView(any());
259         mExecutor.runAllReady();
260         verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);
261     }
262 
263     @Test
testLockscreenShadeVisible_visible_gutsNotClosed()264     public void testLockscreenShadeVisible_visible_gutsNotClosed() {
265         // First, start out lockscreen or shade as not visible
266         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
267         mTestScope.getTestScheduler().runCurrent();
268 
269         NotificationGuts guts = mock(NotificationGuts.class);
270         mGutsManager.setExposedGuts(guts);
271 
272         // WHEN the lockscreen or shade becomes visible
273         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
274         mTestScope.getTestScheduler().runCurrent();
275 
276         // THEN the guts are not closed
277         verify(guts, never()).removeCallbacks(any());
278         verify(guts, never()).closeControls(
279                 anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
280     }
281 
282     @Test
testLockscreenShadeVisible_notVisible_gutsClosed()283     public void testLockscreenShadeVisible_notVisible_gutsClosed() {
284         // First, start out lockscreen or shade as visible
285         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
286         mTestScope.getTestScheduler().runCurrent();
287 
288         NotificationGuts guts = mock(NotificationGuts.class);
289         mGutsManager.setExposedGuts(guts);
290 
291         // WHEN the lockscreen or shade is no longer visible
292         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
293         mTestScope.getTestScheduler().runCurrent();
294 
295         // THEN the guts are closed
296         verify(guts).removeCallbacks(any());
297         verify(guts).closeControls(
298                 /* leavebehinds= */ eq(true),
299                 /* controls= */ eq(true),
300                 /* x= */ anyInt(),
301                 /* y= */ anyInt(),
302                 /* force= */ eq(true));
303     }
304 
305     @Test
testLockscreenShadeVisible_notVisible_listContainerReset()306     public void testLockscreenShadeVisible_notVisible_listContainerReset() {
307         // First, start out lockscreen or shade as visible
308         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
309         mTestScope.getTestScheduler().runCurrent();
310 
311         // WHEN the lockscreen or shade is no longer visible
312         mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
313         mTestScope.getTestScheduler().runCurrent();
314 
315         // THEN the list container is reset
316         verify(mNotificationListContainer).resetExposedMenuView(anyBoolean(), anyBoolean());
317     }
318 
319     @Test
testChangeDensityOrFontScale()320     public void testChangeDensityOrFontScale() {
321         NotificationGuts guts = spy(new NotificationGuts(mContext));
322         when(guts.post(any())).thenAnswer(invocation -> {
323             mHandler.post(((Runnable) invocation.getArguments()[0]));
324             return null;
325         });
326 
327         // Test doesn't support animation since the guts view is not attached.
328         doNothing().when(guts).openControls(
329                 anyInt(),
330                 anyInt(),
331                 anyBoolean(),
332                 any(Runnable.class));
333 
334         ExpandableNotificationRow realRow = createTestNotificationRow();
335         NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow);
336 
337         ExpandableNotificationRow row = spy(realRow);
338 
339         when(row.getWindowToken()).thenReturn(new Binder());
340         when(row.getGuts()).thenReturn(guts);
341         doNothing().when(row).ensureGutsInflated();
342 
343         NotificationEntry realEntry = realRow.getEntry();
344         NotificationEntry entry = spy(realEntry);
345 
346         when(entry.getRow()).thenReturn(row);
347         when(entry.getGuts()).thenReturn(guts);
348 
349         assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
350         mExecutor.runAllReady();
351         verify(guts).openControls(
352                 anyInt(),
353                 anyInt(),
354                 anyBoolean(),
355                 any(Runnable.class));
356 
357         // called once by mGutsManager.bindGuts() in mGutsManager.openGuts()
358         verify(row).setGutsView(any());
359 
360         row.onDensityOrFontScaleChanged();
361         mGutsManager.onDensityOrFontScaleChanged(entry);
362 
363         mExecutor.runAllReady();
364 
365         mGutsManager.closeAndSaveGuts(false, false, false, 0, 0, false);
366 
367         verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
368 
369         // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged()
370         verify(row, times(2)).setGutsView(any());
371     }
372 
373     @Test
testAppOpsSettingsIntent_camera()374     public void testAppOpsSettingsIntent_camera() {
375         ArraySet<Integer> ops = new ArraySet<>();
376         ops.add(OP_CAMERA);
377         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
378         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
379         verify(mNotificationActivityStarter, times(1))
380                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
381         assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
382     }
383 
384     @Test
testAppOpsSettingsIntent_mic()385     public void testAppOpsSettingsIntent_mic() {
386         ArraySet<Integer> ops = new ArraySet<>();
387         ops.add(OP_RECORD_AUDIO);
388         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
389         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
390         verify(mNotificationActivityStarter, times(1))
391                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
392         assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
393     }
394 
395     @Test
testAppOpsSettingsIntent_camera_mic()396     public void testAppOpsSettingsIntent_camera_mic() {
397         ArraySet<Integer> ops = new ArraySet<>();
398         ops.add(OP_CAMERA);
399         ops.add(OP_RECORD_AUDIO);
400         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
401         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
402         verify(mNotificationActivityStarter, times(1))
403                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
404         assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
405     }
406 
407     @Test
testAppOpsSettingsIntent_overlay()408     public void testAppOpsSettingsIntent_overlay() {
409         ArraySet<Integer> ops = new ArraySet<>();
410         ops.add(OP_SYSTEM_ALERT_WINDOW);
411         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
412         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
413         verify(mNotificationActivityStarter, times(1))
414                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
415         assertEquals(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION, captor.getValue().getAction());
416     }
417 
418     @Test
testAppOpsSettingsIntent_camera_mic_overlay()419     public void testAppOpsSettingsIntent_camera_mic_overlay() {
420         ArraySet<Integer> ops = new ArraySet<>();
421         ops.add(OP_CAMERA);
422         ops.add(OP_RECORD_AUDIO);
423         ops.add(OP_SYSTEM_ALERT_WINDOW);
424         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
425         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
426         verify(mNotificationActivityStarter, times(1))
427                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
428         assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
429     }
430 
431     @Test
testAppOpsSettingsIntent_camera_overlay()432     public void testAppOpsSettingsIntent_camera_overlay() {
433         ArraySet<Integer> ops = new ArraySet<>();
434         ops.add(OP_CAMERA);
435         ops.add(OP_SYSTEM_ALERT_WINDOW);
436         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
437         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
438         verify(mNotificationActivityStarter, times(1))
439                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
440         assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
441     }
442 
443     @Test
testAppOpsSettingsIntent_mic_overlay()444     public void testAppOpsSettingsIntent_mic_overlay() {
445         ArraySet<Integer> ops = new ArraySet<>();
446         ops.add(OP_RECORD_AUDIO);
447         ops.add(OP_SYSTEM_ALERT_WINDOW);
448         mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
449         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
450         verify(mNotificationActivityStarter, times(1))
451                 .startNotificationGutsIntent(captor.capture(), anyInt(), any());
452         assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
453     }
454 
455     @Test
testInitializeNotificationInfoView_highPriority()456     public void testInitializeNotificationInfoView_highPriority() throws Exception {
457         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
458         ExpandableNotificationRow row = spy(mHelper.createRow());
459         final NotificationEntry entry = row.getEntry();
460         modifyRanking(entry)
461                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
462                 .setImportance(IMPORTANCE_HIGH)
463                 .build();
464 
465         when(row.getIsNonblockable()).thenReturn(false);
466         when(mHighPriorityProvider.isHighPriority(entry)).thenReturn(true);
467         StatusBarNotification statusBarNotification = entry.getSbn();
468         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
469 
470         verify(notificationInfoView).bindNotification(
471                 any(PackageManager.class),
472                 any(INotificationManager.class),
473                 eq(mOnUserInteractionCallback),
474                 eq(mChannelEditorDialogController),
475                 eq(statusBarNotification.getPackageName()),
476                 any(NotificationChannel.class),
477                 eq(entry),
478                 any(NotificationInfo.OnSettingsClickListener.class),
479                 any(NotificationInfo.OnAppSettingsClickListener.class),
480                 any(UiEventLogger.class),
481                 eq(false),
482                 eq(false),
483                 eq(true), /* wasShownHighPriority */
484                 eq(mAssistantFeedbackController),
485                 any(MetricsLogger.class));
486     }
487 
488     @Test
testInitializeNotificationInfoView_PassesAlongProvisionedState()489     public void testInitializeNotificationInfoView_PassesAlongProvisionedState() throws Exception {
490         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
491         ExpandableNotificationRow row = spy(mHelper.createRow());
492         modifyRanking(row.getEntry())
493                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
494                 .build();
495         when(row.getIsNonblockable()).thenReturn(false);
496         StatusBarNotification statusBarNotification = row.getEntry().getSbn();
497         NotificationEntry entry = row.getEntry();
498 
499         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
500 
501         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
502 
503         verify(notificationInfoView).bindNotification(
504                 any(PackageManager.class),
505                 any(INotificationManager.class),
506                 eq(mOnUserInteractionCallback),
507                 eq(mChannelEditorDialogController),
508                 eq(statusBarNotification.getPackageName()),
509                 any(NotificationChannel.class),
510                 eq(entry),
511                 any(NotificationInfo.OnSettingsClickListener.class),
512                 any(NotificationInfo.OnAppSettingsClickListener.class),
513                 any(UiEventLogger.class),
514                 eq(true),
515                 eq(false),
516                 eq(false), /* wasShownHighPriority */
517                 eq(mAssistantFeedbackController),
518                 any(MetricsLogger.class));
519     }
520 
521     @Test
testInitializeNotificationInfoView_withInitialAction()522     public void testInitializeNotificationInfoView_withInitialAction() throws Exception {
523         NotificationInfo notificationInfoView = mock(NotificationInfo.class);
524         ExpandableNotificationRow row = spy(mHelper.createRow());
525         modifyRanking(row.getEntry())
526                 .setUserSentiment(USER_SENTIMENT_NEGATIVE)
527                 .build();
528         when(row.getIsNonblockable()).thenReturn(false);
529         StatusBarNotification statusBarNotification = row.getEntry().getSbn();
530         NotificationEntry entry = row.getEntry();
531 
532         mGutsManager.initializeNotificationInfo(row, notificationInfoView);
533 
534         verify(notificationInfoView).bindNotification(
535                 any(PackageManager.class),
536                 any(INotificationManager.class),
537                 eq(mOnUserInteractionCallback),
538                 eq(mChannelEditorDialogController),
539                 eq(statusBarNotification.getPackageName()),
540                 any(NotificationChannel.class),
541                 eq(entry),
542                 any(NotificationInfo.OnSettingsClickListener.class),
543                 any(NotificationInfo.OnAppSettingsClickListener.class),
544                 any(UiEventLogger.class),
545                 eq(false),
546                 eq(false),
547                 eq(false), /* wasShownHighPriority */
548                 eq(mAssistantFeedbackController),
549                 any(MetricsLogger.class));
550     }
551 
552     ////////////////////////////////////////////////////////////////////////////////////////////////
553     // Utility methods:
554 
createTestNotificationRow()555     private ExpandableNotificationRow createTestNotificationRow() {
556         Notification.Builder nb = new Notification.Builder(mContext,
557                 mTestNotificationChannel.getId())
558                                         .setContentTitle("foo")
559                                         .setColorized(true).setColor(Color.RED)
560                                         .setFlag(Notification.FLAG_CAN_COLORIZE, true)
561                                         .setSmallIcon(android.R.drawable.sym_def_app_icon);
562 
563         try {
564             ExpandableNotificationRow row = mHelper.createRow(nb.build());
565             modifyRanking(row.getEntry())
566                     .setChannel(mTestNotificationChannel)
567                     .build();
568             return row;
569         } catch (Exception e) {
570             fail();
571             return null;
572         }
573     }
574 
createTestMenuItem(ExpandableNotificationRow row)575     private NotificationMenuRowPlugin.MenuItem createTestMenuItem(ExpandableNotificationRow row) {
576         NotificationMenuRowPlugin menuRow =
577                 new NotificationMenuRow(mContext, mPeopleNotificationIdentifier);
578         menuRow.createMenu(row, row.getEntry().getSbn());
579 
580         NotificationMenuRowPlugin.MenuItem menuItem = menuRow.getLongpressMenuItem(mContext);
581         assertNotNull(menuItem);
582         return menuItem;
583     }
584 }
585