summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java574
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt584
2 files changed, 584 insertions, 574 deletions
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
deleted file mode 100644
index 0427011c06f6..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.row;
-
-import static android.app.AppOpsManager.OP_CAMERA;
-import static android.app.AppOpsManager.OP_RECORD_AUDIO;
-import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
-
-import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
-
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.INotificationManager;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.content.Intent;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.ShortcutManager;
-import android.graphics.Color;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.service.notification.StatusBarNotification;
-import android.testing.TestableLooper;
-import android.util.ArraySet;
-import android.view.View;
-import android.view.accessibility.AccessibilityManager;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.testing.UiEventLoggerFake;
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository;
-import com.android.systemui.kosmos.KosmosJavaAdapter;
-import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.domain.interactor.PowerInteractorFactory;
-import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository;
-import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
-import com.android.systemui.settings.UserContextProvider;
-import com.android.systemui.shade.ShadeController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationPresenter;
-import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.kotlin.JavaAdapter;
-import com.android.systemui.wmshell.BubblesManager;
-
-import kotlinx.coroutines.test.TestScope;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.Optional;
-
-/**
- * Tests for {@link NotificationGutsManager}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-@TestableLooper.RunWithLooper
-public class NotificationGutsManagerTest extends SysuiTestCase {
- private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
-
- private NotificationChannel mTestNotificationChannel = new NotificationChannel(
- TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
-
- private final KosmosJavaAdapter mKosmos = new KosmosJavaAdapter(this);
- private final TestScope mTestScope = mKosmos.getTestScope();
- private final JavaAdapter mJavaAdapter = new JavaAdapter(mTestScope.getBackgroundScope());
- private final FakeExecutor mExecutor = mKosmos.getFakeExecutor();
- private final Handler mHandler = mKosmos.getFakeExecutorHandler();
- private NotificationTestHelper mHelper;
- private NotificationGutsManager mGutsManager;
-
- @Rule public MockitoRule mockito = MockitoJUnit.rule();
- @Mock private MetricsLogger mMetricsLogger;
- @Mock private OnUserInteractionCallback mOnUserInteractionCallback;
- @Mock private NotificationPresenter mPresenter;
- @Mock private NotificationActivityStarter mNotificationActivityStarter;
- @Mock private NotificationListContainer mNotificationListContainer;
- @Mock private OnSettingsClickListener mOnSettingsClickListener;
- @Mock private DeviceProvisionedController mDeviceProvisionedController;
- @Mock private AccessibilityManager mAccessibilityManager;
- @Mock private HighPriorityProvider mHighPriorityProvider;
- @Mock private INotificationManager mINotificationManager;
- @Mock private IStatusBarService mBarService;
- @Mock private LauncherApps mLauncherApps;
- @Mock private ShortcutManager mShortcutManager;
- @Mock private ChannelEditorDialogController mChannelEditorDialogController;
- @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
- @Mock private UserContextProvider mContextTracker;
- @Mock private BubblesManager mBubblesManager;
- @Mock private ShadeController mShadeController;
- @Mock private PeopleSpaceWidgetManager mPeopleSpaceWidgetManager;
- @Mock private AssistantFeedbackController mAssistantFeedbackController;
- @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
- @Mock private StatusBarStateController mStatusBarStateController;
- @Mock private HeadsUpManager mHeadsUpManager;
- @Mock private ActivityStarter mActivityStarter;
-
- @Mock private UserManager mUserManager;
-
- private WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
-
- @Before
- public void setUp() {
- allowTestableLooperAsMainThread();
- mHelper = new NotificationTestHelper(mContext, mDependency);
- when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
-
- mWindowRootViewVisibilityInteractor = new WindowRootViewVisibilityInteractor(
- mTestScope.getBackgroundScope(),
- new WindowRootViewVisibilityRepository(mBarService, mExecutor),
- new FakeKeyguardRepository(),
- mHeadsUpManager,
- PowerInteractorFactory.create().getPowerInteractor(),
- mKosmos.getActiveNotificationsInteractor(),
- () -> mKosmos.getSceneInteractor()
- );
-
- mGutsManager = new NotificationGutsManager(
- mContext,
- mHandler,
- mHandler,
- mJavaAdapter,
- mAccessibilityManager,
- mHighPriorityProvider,
- mINotificationManager,
- mUserManager,
- mPeopleSpaceWidgetManager,
- mLauncherApps,
- mShortcutManager,
- mChannelEditorDialogController,
- mContextTracker,
- mAssistantFeedbackController,
- Optional.of(mBubblesManager),
- new UiEventLoggerFake(),
- mOnUserInteractionCallback,
- mShadeController,
- mWindowRootViewVisibilityInteractor,
- mNotificationLockscreenUserManager,
- mStatusBarStateController,
- mBarService,
- mDeviceProvisionedController,
- mMetricsLogger,
- mHeadsUpManager,
- mActivityStarter);
- mGutsManager.setUpWithPresenter(mPresenter, mNotificationListContainer,
- mOnSettingsClickListener);
- mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
- mGutsManager.start();
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Test methods:
-
- @Test
- public void testOpenAndCloseGuts() {
- NotificationGuts guts = spy(new NotificationGuts(mContext));
- when(guts.post(any())).thenAnswer(invocation -> {
- mHandler.post(((Runnable) invocation.getArguments()[0]));
- return null;
- });
-
- // Test doesn't support animation since the guts view is not attached.
- doNothing().when(guts).openControls(
- anyInt(),
- anyInt(),
- anyBoolean(),
- any(Runnable.class));
-
- ExpandableNotificationRow realRow = createTestNotificationRow();
- NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow);
-
- ExpandableNotificationRow row = spy(realRow);
- when(row.getWindowToken()).thenReturn(new Binder());
- when(row.getGuts()).thenReturn(guts);
-
- assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
- assertEquals(View.INVISIBLE, guts.getVisibility());
- mExecutor.runAllReady();
- verify(guts).openControls(
- anyInt(),
- anyInt(),
- anyBoolean(),
- any(Runnable.class));
- verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), true);
-
- assertEquals(View.VISIBLE, guts.getVisibility());
- mGutsManager.closeAndSaveGuts(false, false, true, 0, 0, false);
-
- verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
- verify(row, times(1)).setGutsView(any());
- mExecutor.runAllReady();
- verify(mHeadsUpManager).setGutsShown(realRow.getEntry(), false);
- }
-
- @Test
- public void testLockscreenShadeVisible_visible_gutsNotClosed() {
- // First, start out lockscreen or shade as not visible
- mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
- mTestScope.getTestScheduler().runCurrent();
-
- NotificationGuts guts = mock(NotificationGuts.class);
- mGutsManager.setExposedGuts(guts);
-
- // WHEN the lockscreen or shade becomes visible
- mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
- mTestScope.getTestScheduler().runCurrent();
-
- // THEN the guts are not closed
- verify(guts, never()).removeCallbacks(any());
- verify(guts, never()).closeControls(
- anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
- }
-
- @Test
- public void testLockscreenShadeVisible_notVisible_gutsClosed() {
- // First, start out lockscreen or shade as visible
- mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
- mTestScope.getTestScheduler().runCurrent();
-
- NotificationGuts guts = mock(NotificationGuts.class);
- mGutsManager.setExposedGuts(guts);
-
- // WHEN the lockscreen or shade is no longer visible
- mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
- mTestScope.getTestScheduler().runCurrent();
-
- // THEN the guts are closed
- verify(guts).removeCallbacks(any());
- verify(guts).closeControls(
- /* leavebehinds= */ eq(true),
- /* controls= */ eq(true),
- /* x= */ anyInt(),
- /* y= */ anyInt(),
- /* force= */ eq(true));
- }
-
- @Test
- public void testLockscreenShadeVisible_notVisible_listContainerReset() {
- // First, start out lockscreen or shade as visible
- mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true);
- mTestScope.getTestScheduler().runCurrent();
-
- // WHEN the lockscreen or shade is no longer visible
- mWindowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false);
- mTestScope.getTestScheduler().runCurrent();
-
- // THEN the list container is reset
- verify(mNotificationListContainer).resetExposedMenuView(anyBoolean(), anyBoolean());
- }
-
- @Test
- public void testChangeDensityOrFontScale() {
- NotificationGuts guts = spy(new NotificationGuts(mContext));
- when(guts.post(any())).thenAnswer(invocation -> {
- mHandler.post(((Runnable) invocation.getArguments()[0]));
- return null;
- });
-
- // Test doesn't support animation since the guts view is not attached.
- doNothing().when(guts).openControls(
- anyInt(),
- anyInt(),
- anyBoolean(),
- any(Runnable.class));
-
- ExpandableNotificationRow realRow = createTestNotificationRow();
- NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow);
-
- ExpandableNotificationRow row = spy(realRow);
-
- when(row.getWindowToken()).thenReturn(new Binder());
- when(row.getGuts()).thenReturn(guts);
- doNothing().when(row).ensureGutsInflated();
-
- NotificationEntry realEntry = realRow.getEntry();
- NotificationEntry entry = spy(realEntry);
-
- when(entry.getRow()).thenReturn(row);
- when(entry.getGuts()).thenReturn(guts);
-
- assertTrue(mGutsManager.openGutsInternal(row, 0, 0, menuItem));
- mExecutor.runAllReady();
- verify(guts).openControls(
- anyInt(),
- anyInt(),
- anyBoolean(),
- any(Runnable.class));
-
- // called once by mGutsManager.bindGuts() in mGutsManager.openGuts()
- verify(row).setGutsView(any());
-
- row.onDensityOrFontScaleChanged();
- mGutsManager.onDensityOrFontScaleChanged(entry);
-
- mExecutor.runAllReady();
-
- mGutsManager.closeAndSaveGuts(false, false, false, 0, 0, false);
-
- verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean());
-
- // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged()
- verify(row, times(2)).setGutsView(any());
- }
-
- @Test
- public void testAppOpsSettingsIntent_camera() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_CAMERA);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
- }
-
- @Test
- public void testAppOpsSettingsIntent_mic() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_RECORD_AUDIO);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
- }
-
- @Test
- public void testAppOpsSettingsIntent_camera_mic() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_CAMERA);
- ops.add(OP_RECORD_AUDIO);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.getValue().getAction());
- }
-
- @Test
- public void testAppOpsSettingsIntent_overlay() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_SYSTEM_ALERT_WINDOW);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION, captor.getValue().getAction());
- }
-
- @Test
- public void testAppOpsSettingsIntent_camera_mic_overlay() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_CAMERA);
- ops.add(OP_RECORD_AUDIO);
- ops.add(OP_SYSTEM_ALERT_WINDOW);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
- }
-
- @Test
- public void testAppOpsSettingsIntent_camera_overlay() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_CAMERA);
- ops.add(OP_SYSTEM_ALERT_WINDOW);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
- }
-
- @Test
- public void testAppOpsSettingsIntent_mic_overlay() {
- ArraySet<Integer> ops = new ArraySet<>();
- ops.add(OP_RECORD_AUDIO);
- ops.add(OP_SYSTEM_ALERT_WINDOW);
- mGutsManager.startAppOpsSettingsActivity("", 0, ops, null);
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mNotificationActivityStarter, times(1))
- .startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.getValue().getAction());
- }
-
- @Test
- public void testInitializeNotificationInfoView_highPriority() throws Exception {
- NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = spy(mHelper.createRow());
- final NotificationEntry entry = row.getEntry();
- modifyRanking(entry)
- .setUserSentiment(USER_SENTIMENT_NEGATIVE)
- .setImportance(IMPORTANCE_HIGH)
- .build();
-
- when(row.getIsNonblockable()).thenReturn(false);
- when(mHighPriorityProvider.isHighPriority(entry)).thenReturn(true);
- StatusBarNotification statusBarNotification = entry.getSbn();
- mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
- verify(notificationInfoView).bindNotification(
- any(PackageManager.class),
- any(INotificationManager.class),
- eq(mOnUserInteractionCallback),
- eq(mChannelEditorDialogController),
- eq(statusBarNotification.getPackageName()),
- any(NotificationChannel.class),
- eq(entry),
- any(NotificationInfo.OnSettingsClickListener.class),
- any(NotificationInfo.OnAppSettingsClickListener.class),
- any(UiEventLogger.class),
- eq(false),
- eq(false),
- eq(true), /* wasShownHighPriority */
- eq(mAssistantFeedbackController),
- any(MetricsLogger.class));
- }
-
- @Test
- public void testInitializeNotificationInfoView_PassesAlongProvisionedState() throws Exception {
- NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = spy(mHelper.createRow());
- modifyRanking(row.getEntry())
- .setUserSentiment(USER_SENTIMENT_NEGATIVE)
- .build();
- when(row.getIsNonblockable()).thenReturn(false);
- StatusBarNotification statusBarNotification = row.getEntry().getSbn();
- NotificationEntry entry = row.getEntry();
-
- when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-
- mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
- verify(notificationInfoView).bindNotification(
- any(PackageManager.class),
- any(INotificationManager.class),
- eq(mOnUserInteractionCallback),
- eq(mChannelEditorDialogController),
- eq(statusBarNotification.getPackageName()),
- any(NotificationChannel.class),
- eq(entry),
- any(NotificationInfo.OnSettingsClickListener.class),
- any(NotificationInfo.OnAppSettingsClickListener.class),
- any(UiEventLogger.class),
- eq(true),
- eq(false),
- eq(false), /* wasShownHighPriority */
- eq(mAssistantFeedbackController),
- any(MetricsLogger.class));
- }
-
- @Test
- public void testInitializeNotificationInfoView_withInitialAction() throws Exception {
- NotificationInfo notificationInfoView = mock(NotificationInfo.class);
- ExpandableNotificationRow row = spy(mHelper.createRow());
- modifyRanking(row.getEntry())
- .setUserSentiment(USER_SENTIMENT_NEGATIVE)
- .build();
- when(row.getIsNonblockable()).thenReturn(false);
- StatusBarNotification statusBarNotification = row.getEntry().getSbn();
- NotificationEntry entry = row.getEntry();
-
- mGutsManager.initializeNotificationInfo(row, notificationInfoView);
-
- verify(notificationInfoView).bindNotification(
- any(PackageManager.class),
- any(INotificationManager.class),
- eq(mOnUserInteractionCallback),
- eq(mChannelEditorDialogController),
- eq(statusBarNotification.getPackageName()),
- any(NotificationChannel.class),
- eq(entry),
- any(NotificationInfo.OnSettingsClickListener.class),
- any(NotificationInfo.OnAppSettingsClickListener.class),
- any(UiEventLogger.class),
- eq(false),
- eq(false),
- eq(false), /* wasShownHighPriority */
- eq(mAssistantFeedbackController),
- any(MetricsLogger.class));
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////////////
- // Utility methods:
-
- private ExpandableNotificationRow createTestNotificationRow() {
- Notification.Builder nb = new Notification.Builder(mContext,
- mTestNotificationChannel.getId())
- .setContentTitle("foo")
- .setColorized(true).setColor(Color.RED)
- .setFlag(Notification.FLAG_CAN_COLORIZE, true)
- .setSmallIcon(android.R.drawable.sym_def_app_icon);
-
- try {
- ExpandableNotificationRow row = mHelper.createRow(nb.build());
- modifyRanking(row.getEntry())
- .setChannel(mTestNotificationChannel)
- .build();
- return row;
- } catch (Exception e) {
- fail();
- return null;
- }
- }
-
- private NotificationMenuRowPlugin.MenuItem createTestMenuItem(ExpandableNotificationRow row) {
- NotificationMenuRowPlugin menuRow =
- new NotificationMenuRow(mContext, mPeopleNotificationIdentifier);
- menuRow.createMenu(row, row.getEntry().getSbn());
-
- NotificationMenuRowPlugin.MenuItem menuItem = menuRow.getLongpressMenuItem(mContext);
- assertNotNull(menuItem);
- return menuItem;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
new file mode 100644
index 000000000000..60c5404a2c46
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.kt
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.notification.row
+
+import android.R
+import android.app.AppOpsManager
+import android.app.INotificationManager
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.content.Intent
+import android.content.pm.LauncherApps
+import android.content.pm.PackageManager
+import android.content.pm.ShortcutManager
+import android.graphics.Color
+import android.os.Binder
+import android.os.UserManager
+import android.os.fakeExecutorHandler
+import android.provider.Settings
+import android.service.notification.NotificationListenerService
+import android.testing.TestableLooper.RunWithLooper
+import android.util.ArraySet
+import android.view.View
+import android.view.accessibility.AccessibilityManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+import com.android.internal.logging.testing.UiEventLoggerFake
+import com.android.internal.statusbar.IStatusBarService
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.concurrency.fakeExecutor
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.people.widget.PeopleSpaceWidgetManager
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.domain.interactor.PowerInteractorFactory.create
+import com.android.systemui.scene.data.repository.WindowRootViewVisibilityRepository
+import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.settings.UserContextProvider
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.statusbar.NotificationEntryHelper
+import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.AssistantFeedbackController
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider
+import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.testKosmos
+import com.android.systemui.util.kotlin.JavaAdapter
+import com.android.systemui.wmshell.BubblesManager
+import java.util.Optional
+import kotlin.test.assertNotNull
+import kotlin.test.fail
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/** Tests for [NotificationGutsManager]. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class NotificationGutsManagerTest : SysuiTestCase() {
+ private val testNotificationChannel =
+ NotificationChannel(
+ TEST_CHANNEL_ID,
+ TEST_CHANNEL_ID,
+ NotificationManager.IMPORTANCE_DEFAULT,
+ )
+
+ private val kosmos = testKosmos()
+
+ private val testScope = kosmos.testScope
+ private val javaAdapter = JavaAdapter(testScope.backgroundScope)
+ private val executor = kosmos.fakeExecutor
+ private val handler = kosmos.fakeExecutorHandler
+ private lateinit var helper: NotificationTestHelper
+ private lateinit var gutsManager: NotificationGutsManager
+
+ @get:Rule val rule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var metricsLogger: MetricsLogger
+ @Mock private lateinit var onUserInteractionCallback: OnUserInteractionCallback
+ @Mock private lateinit var presenter: NotificationPresenter
+ @Mock private lateinit var notificationActivityStarter: NotificationActivityStarter
+ @Mock private lateinit var notificationListContainer: NotificationListContainer
+ @Mock
+ private lateinit var onSettingsClickListener: NotificationGutsManager.OnSettingsClickListener
+ @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+ @Mock private lateinit var accessibilityManager: AccessibilityManager
+ @Mock private lateinit var highPriorityProvider: HighPriorityProvider
+ @Mock private lateinit var iNotificationManager: INotificationManager
+ @Mock private lateinit var barService: IStatusBarService
+ @Mock private lateinit var launcherApps: LauncherApps
+ @Mock private lateinit var shortcutManager: ShortcutManager
+ @Mock private lateinit var channelEditorDialogController: ChannelEditorDialogController
+ @Mock private lateinit var peopleNotificationIdentifier: PeopleNotificationIdentifier
+ @Mock private lateinit var contextTracker: UserContextProvider
+ @Mock private lateinit var bubblesManager: BubblesManager
+ @Mock private lateinit var shadeController: ShadeController
+ @Mock private lateinit var peopleSpaceWidgetManager: PeopleSpaceWidgetManager
+ @Mock private lateinit var assistantFeedbackController: AssistantFeedbackController
+ @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
+ @Mock private lateinit var statusBarStateController: StatusBarStateController
+ @Mock private lateinit var headsUpManager: HeadsUpManager
+ @Mock private lateinit var activityStarter: ActivityStarter
+ @Mock private lateinit var userManager: UserManager
+
+ private lateinit var windowRootViewVisibilityInteractor: WindowRootViewVisibilityInteractor
+
+ @Before
+ fun setUp() {
+ allowTestableLooperAsMainThread()
+ helper = NotificationTestHelper(mContext, mDependency)
+ whenever(accessibilityManager.isTouchExplorationEnabled).thenReturn(false)
+
+ windowRootViewVisibilityInteractor =
+ WindowRootViewVisibilityInteractor(
+ testScope.backgroundScope,
+ WindowRootViewVisibilityRepository(barService, executor),
+ FakeKeyguardRepository(),
+ headsUpManager,
+ create().powerInteractor,
+ kosmos.activeNotificationsInteractor,
+ ) {
+ kosmos.sceneInteractor
+ }
+
+ gutsManager =
+ NotificationGutsManager(
+ mContext,
+ handler,
+ handler,
+ javaAdapter,
+ accessibilityManager,
+ highPriorityProvider,
+ iNotificationManager,
+ userManager,
+ peopleSpaceWidgetManager,
+ launcherApps,
+ shortcutManager,
+ channelEditorDialogController,
+ contextTracker,
+ assistantFeedbackController,
+ Optional.of(bubblesManager),
+ UiEventLoggerFake(),
+ onUserInteractionCallback,
+ shadeController,
+ windowRootViewVisibilityInteractor,
+ notificationLockscreenUserManager,
+ statusBarStateController,
+ barService,
+ deviceProvisionedController,
+ metricsLogger,
+ headsUpManager,
+ activityStarter,
+ )
+ gutsManager.setUpWithPresenter(
+ presenter,
+ notificationListContainer,
+ onSettingsClickListener,
+ )
+ gutsManager.setNotificationActivityStarter(notificationActivityStarter)
+ gutsManager.start()
+ }
+
+ @Test
+ fun testOpenAndCloseGuts() {
+ val guts = spy(NotificationGuts(mContext))
+ whenever(guts.post(any())).thenAnswer { invocation: InvocationOnMock ->
+ handler.post(((invocation.arguments[0] as Runnable)))
+ null
+ }
+
+ // Test doesn't support animation since the guts view is not attached.
+ doNothing().whenever(guts).openControls(anyInt(), anyInt(), anyBoolean(), any())
+
+ val realRow = createTestNotificationRow()
+ val menuItem = createTestMenuItem(realRow)
+
+ val row = spy(realRow)
+ whenever(row.windowToken).thenReturn(Binder())
+ whenever(row.guts).thenReturn(guts)
+
+ assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
+ assertEquals(View.INVISIBLE.toLong(), guts.visibility.toLong())
+ executor.runAllReady()
+ verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
+ verify(headsUpManager).setGutsShown(realRow.entry, true)
+
+ assertEquals(View.VISIBLE.toLong(), guts.visibility.toLong())
+ gutsManager.closeAndSaveGuts(false, false, true, 0, 0, false)
+
+ verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean())
+ verify(row, times(1)).setGutsView(any<MenuItem>())
+ executor.runAllReady()
+ verify(headsUpManager).setGutsShown(realRow.entry, false)
+ }
+
+ @Test
+ fun testLockscreenShadeVisible_visible_gutsNotClosed() =
+ testScope.runTest {
+ // First, start out lockscreen or shade as not visible
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false)
+ runCurrent()
+
+ val guts: NotificationGuts = mock()
+ gutsManager.exposedGuts = guts
+
+ // WHEN the lockscreen or shade becomes visible
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ runCurrent()
+
+ // THEN the guts are not closed
+ verify(guts, never()).removeCallbacks(any())
+ verify(guts, never())
+ .closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean())
+ }
+
+ @Test
+ fun testLockscreenShadeVisible_notVisible_gutsClosed() =
+ testScope.runTest {
+ // First, start out lockscreen or shade as visible
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ runCurrent()
+
+ val guts: NotificationGuts = mock()
+ gutsManager.exposedGuts = guts
+
+ // WHEN the lockscreen or shade is no longer visible
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false)
+ runCurrent()
+
+ // THEN the guts are closed
+ verify(guts).removeCallbacks(null)
+ verify(guts)
+ .closeControls(
+ /* leavebehinds = */ eq(true),
+ /* controls = */ eq(true),
+ /* x = */ anyInt(),
+ /* y = */ anyInt(),
+ /* force = */ eq(true),
+ )
+ }
+
+ @Test
+ fun testLockscreenShadeVisible_notVisible_listContainerReset() =
+ testScope.runTest {
+ // First, start out lockscreen or shade as visible
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(true)
+ runCurrent()
+ clearInvocations(notificationListContainer)
+
+ // WHEN the lockscreen or shade is no longer visible
+ windowRootViewVisibilityInteractor.setIsLockscreenOrShadeVisible(false)
+ runCurrent()
+
+ // THEN the list container is reset
+ verify(notificationListContainer).resetExposedMenuView(anyBoolean(), anyBoolean())
+ }
+
+ @Test
+ fun testChangeDensityOrFontScale() {
+ val guts = spy(NotificationGuts(mContext))
+ whenever(guts.post(any())).thenAnswer { invocation: InvocationOnMock ->
+ handler.post(((invocation.arguments[0] as Runnable)))
+ null
+ }
+
+ // Test doesn't support animation since the guts view is not attached.
+ doNothing().whenever(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
+
+ val realRow = createTestNotificationRow()
+ val menuItem = createTestMenuItem(realRow)
+
+ val row = spy(realRow)
+
+ whenever(row.windowToken).thenReturn(Binder())
+ whenever(row.guts).thenReturn(guts)
+ doNothing().whenever(row).ensureGutsInflated()
+
+ val realEntry = realRow.entry
+ val entry = spy(realEntry)
+
+ whenever(entry.row).thenReturn(row)
+ whenever(entry.guts).thenReturn(guts)
+
+ assertTrue(gutsManager.openGutsInternal(row, 0, 0, menuItem))
+ executor.runAllReady()
+ verify(guts).openControls(anyInt(), anyInt(), anyBoolean(), any<Runnable>())
+
+ // called once by mGutsManager.bindGuts() in mGutsManager.openGuts()
+ verify(row).setGutsView(any<MenuItem>())
+
+ row.onDensityOrFontScaleChanged()
+ gutsManager.onDensityOrFontScaleChanged(entry)
+
+ executor.runAllReady()
+
+ gutsManager.closeAndSaveGuts(false, false, false, 0, 0, false)
+
+ verify(guts).closeControls(anyBoolean(), anyBoolean(), anyInt(), anyInt(), anyBoolean())
+
+ // called again by mGutsManager.bindGuts(), in mGutsManager.onDensityOrFontScaleChanged()
+ verify(row, times(2)).setGutsView(any<MenuItem>())
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_camera() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_CAMERA)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.lastValue.action)
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_mic() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_RECORD_AUDIO)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.lastValue.action)
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_camera_mic() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_CAMERA)
+ ops.add(AppOpsManager.OP_RECORD_AUDIO)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Intent.ACTION_MANAGE_APP_PERMISSIONS, captor.lastValue.action)
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_overlay() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION, captor.lastValue.action)
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_camera_mic_overlay() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_CAMERA)
+ ops.add(AppOpsManager.OP_RECORD_AUDIO)
+ ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.lastValue.action)
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_camera_overlay() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_CAMERA)
+ ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.lastValue.action)
+ }
+
+ @Test
+ fun testAppOpsSettingsIntent_mic_overlay() {
+ val row = createTestNotificationRow()
+ val ops = ArraySet<Int>()
+ ops.add(AppOpsManager.OP_RECORD_AUDIO)
+ ops.add(AppOpsManager.OP_SYSTEM_ALERT_WINDOW)
+ gutsManager.startAppOpsSettingsActivity("", 0, ops, row)
+ val captor = argumentCaptor<Intent>()
+ verify(notificationActivityStarter, times(1))
+ .startNotificationGutsIntent(captor.capture(), anyInt(), eq(row))
+ assertEquals(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, captor.lastValue.action)
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun testInitializeNotificationInfoView_highPriority() {
+ val notificationInfoView: NotificationInfo = mock()
+ val row = spy(helper.createRow())
+ val entry = row.entry
+ NotificationEntryHelper.modifyRanking(entry)
+ .setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
+ .setImportance(NotificationManager.IMPORTANCE_HIGH)
+ .build()
+
+ whenever(row.isNonblockable).thenReturn(false)
+ whenever(highPriorityProvider.isHighPriority(entry)).thenReturn(true)
+ val statusBarNotification = entry.sbn
+ gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ verify(notificationInfoView)
+ .bindNotification(
+ any<PackageManager>(),
+ any<INotificationManager>(),
+ eq(onUserInteractionCallback),
+ eq(channelEditorDialogController),
+ eq(statusBarNotification.packageName),
+ any<NotificationChannel>(),
+ eq(entry),
+ any<NotificationInfo.OnSettingsClickListener>(),
+ any<NotificationInfo.OnAppSettingsClickListener>(),
+ any<UiEventLogger>(),
+ /* isDeviceProvisioned = */ eq(false),
+ /* isNonblockable = */ eq(false),
+ /* wasShownHighPriority = */ eq(true),
+ eq(assistantFeedbackController),
+ eq(metricsLogger),
+ )
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun testInitializeNotificationInfoView_PassesAlongProvisionedState() {
+ val notificationInfoView: NotificationInfo = mock()
+ val row = spy(helper.createRow())
+ NotificationEntryHelper.modifyRanking(row.entry)
+ .setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
+ .build()
+ whenever(row.isNonblockable).thenReturn(false)
+ val statusBarNotification = row.entry.sbn
+ val entry = row.entry
+
+ whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(true)
+
+ gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ verify(notificationInfoView)
+ .bindNotification(
+ any<PackageManager>(),
+ any<INotificationManager>(),
+ eq(onUserInteractionCallback),
+ eq(channelEditorDialogController),
+ eq(statusBarNotification.packageName),
+ any<NotificationChannel>(),
+ eq(entry),
+ any<NotificationInfo.OnSettingsClickListener>(),
+ any<NotificationInfo.OnAppSettingsClickListener>(),
+ any<UiEventLogger>(),
+ /* isDeviceProvisioned = */ eq(true),
+ /* isNonblockable = */ eq(false),
+ /* wasShownHighPriority = */ eq(false),
+ eq(assistantFeedbackController),
+ eq(metricsLogger),
+ )
+ }
+
+ @Test
+ @Throws(Exception::class)
+ fun testInitializeNotificationInfoView_withInitialAction() {
+ val notificationInfoView: NotificationInfo = mock()
+ val row = spy(helper.createRow())
+ NotificationEntryHelper.modifyRanking(row.entry)
+ .setUserSentiment(NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE)
+ .build()
+ whenever(row.isNonblockable).thenReturn(false)
+ val statusBarNotification = row.entry.sbn
+ val entry = row.entry
+
+ gutsManager.initializeNotificationInfo(row, notificationInfoView)
+
+ verify(notificationInfoView)
+ .bindNotification(
+ any<PackageManager>(),
+ any<INotificationManager>(),
+ eq(onUserInteractionCallback),
+ eq(channelEditorDialogController),
+ eq(statusBarNotification.packageName),
+ any<NotificationChannel>(),
+ eq(entry),
+ any<NotificationInfo.OnSettingsClickListener>(),
+ any<NotificationInfo.OnAppSettingsClickListener>(),
+ any<UiEventLogger>(),
+ /* isDeviceProvisioned = */ eq(false),
+ /* isNonblockable = */ eq(false),
+ /* wasShownHighPriority = */ eq(false),
+ eq(assistantFeedbackController),
+ eq(metricsLogger),
+ )
+ }
+
+ private fun createTestNotificationRow(): ExpandableNotificationRow {
+ val nb =
+ Notification.Builder(mContext, testNotificationChannel.id)
+ .setContentTitle("foo")
+ .setColorized(true)
+ .setColor(Color.RED)
+ .setFlag(Notification.FLAG_CAN_COLORIZE, true)
+ .setSmallIcon(R.drawable.sym_def_app_icon)
+
+ try {
+ val row = helper.createRow(nb.build())
+ NotificationEntryHelper.modifyRanking(row.entry)
+ .setChannel(testNotificationChannel)
+ .build()
+ return row
+ } catch (e: Exception) {
+ fail()
+ }
+ }
+
+ private fun createTestMenuItem(
+ row: ExpandableNotificationRow
+ ): NotificationMenuRowPlugin.MenuItem {
+ val menuRow: NotificationMenuRowPlugin =
+ NotificationMenuRow(mContext, peopleNotificationIdentifier)
+ menuRow.createMenu(row, row.entry.sbn)
+
+ val menuItem = menuRow.getLongpressMenuItem(mContext)
+ assertNotNull(menuItem)
+ return menuItem
+ }
+
+ companion object {
+ private const val TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"
+ }
+}