Show snoozed conversations in conversation header

- And allow them to be unsnoozed with a tap.
- Also use the conversation's shortcut icon and name if available.
- And ignore the setting to turn off the strips since it now requires
explicit user action to make the strip visible

Note 1: unsnoozing a notification causes it to make sound again - we
probably want to change that for manually unsnoozed things
Note 2: the entries in the header don't yet persist across a reboot

Test: atest, manual
Bug: 149486431
Change-Id: Id661c25a49bc982e39deab977eb912f51eaf6757
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index c912b67..69e933e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui;
 
+import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
+
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.TestCase.fail;
@@ -528,7 +530,8 @@
                         .setSbn(notification)
                         .build(),
                 null,
-                false);
+                false,
+                REASON_APP_CANCEL);
     }
 
     private void entryAdded(StatusBarNotification notification, int importance) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 3009593..9fe9e6d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -685,7 +685,7 @@
         assertTrue(mBubbleController.hasBubbles());
 
         // Removes the notification
-        mEntryListener.onEntryRemoved(mRow.getEntry(), null, false);
+        mEntryListener.onEntryRemoved(mRow.getEntry(), null, false, REASON_APP_CANCEL);
         assertFalse(mBubbleController.hasBubbles());
     }
 
@@ -827,7 +827,7 @@
         mBubbleController.handleDismissalInterception(groupSummary.getEntry());
 
         // WHEN the summary is cancelled by the app
-        mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, true);
+        mEntryListener.onEntryRemoved(groupSummary.getEntry(), null, false, REASON_APP_CANCEL);
 
         // THEN the summary and its children are removed from bubble data
         assertFalse(mBubbleData.hasBubbleWithKey(groupedBubble.getEntry().getKey()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
index 16f105d..fe8b89f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
@@ -20,6 +20,7 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager.Importance;
+import android.content.pm.ShortcutInfo;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.SnoozeCriterion;
 
@@ -53,6 +54,7 @@
     private boolean mCanBubble = false;
     private boolean mIsVisuallyInterruptive = false;
     private boolean mIsConversation = false;
+    private ShortcutInfo mShortcutInfo = null;
 
     public RankingBuilder() {
     }
@@ -79,6 +81,7 @@
         mCanBubble = ranking.canBubble();
         mIsVisuallyInterruptive = ranking.visuallyInterruptive();
         mIsConversation = ranking.isConversation();
+        mShortcutInfo = ranking.getShortcutInfo();
     }
 
     public Ranking build() {
@@ -104,7 +107,8 @@
                 mSmartReplies,
                 mCanBubble,
                 mIsVisuallyInterruptive,
-                mIsConversation);
+                mIsConversation,
+                mShortcutInfo);
         return ranking;
     }
 
@@ -189,6 +193,11 @@
         return this;
     }
 
+    public RankingBuilder setShortcutInfo(ShortcutInfo shortcutInfo) {
+        mShortcutInfo = shortcutInfo;
+        return this;
+    }
+
     public RankingBuilder setImportance(@Importance int importance) {
         mImportance = importance;
         return this;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 98f12ce..312bb7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -143,7 +143,7 @@
                     IMPORTANCE_DEFAULT,
                     null, null,
                     null, null, null, true, sentiment, false, -1, false, null, null, false, false,
-                    false);
+                    false, null);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
     }
@@ -162,7 +162,7 @@
                     null, null,
                     null, null, null, true,
                     Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
-                    false, smartActions, null, false, false, false);
+                    false, smartActions, null, false, false, false, null);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
     }
@@ -254,7 +254,7 @@
 
         verify(mPresenter).updateNotificationViews();
         verify(mEntryListener).onEntryRemoved(
-                eq(mEntry), any(), eq(false) /* removedByUser */);
+                eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
         verify(mRow).setRemoved();
 
         assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
@@ -266,7 +266,7 @@
         mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
 
         verify(mEntryListener, never()).onEntryRemoved(
-                eq(mEntry), any(), eq(false) /* removedByUser */);
+                eq(mEntry), any(), eq(false) /* removedByUser */, eq(UNDEFINED_DISMISS_REASON));
     }
 
     @Test
@@ -275,7 +275,7 @@
         mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
 
         verify(mEntryListener, never()).onEntryRemoved(
-                eq(mEntry), any(), eq(false /* removedByUser */));
+                eq(mEntry), any(), eq(false /* removedByUser */), eq(UNDEFINED_DISMISS_REASON));
     }
 
     @Test
@@ -356,7 +356,8 @@
         verify(extender).setShouldManageLifetime(mEntry, true);
         // THEN the notification is retained
         assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-        verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(), eq(false));
+        verify(mEntryListener, never()).onEntryRemoved(
+                eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
     }
 
     @Test
@@ -374,7 +375,8 @@
 
         // THEN the notification is removed
         assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
-        verify(mEntryListener).onEntryRemoved(eq(mEntry), any(), eq(false));
+        verify(mEntryListener).onEntryRemoved(
+                eq(mEntry), any(), eq(false), eq(UNDEFINED_DISMISS_REASON));
     }
 
     @Test
@@ -447,7 +449,7 @@
         // THEN the interceptor intercepts & the entry is not removed & no listeners are called
         assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
         verify(mEntryListener, never()).onEntryRemoved(eq(mEntry),
-                any(NotificationVisibility.class), anyBoolean());
+                any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
     }
 
     @Test
@@ -466,7 +468,7 @@
         // THEN the interceptor intercepts & the entry is not removed & no listeners are called
         assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
         verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry),
-                any(NotificationVisibility.class), anyBoolean());
+                any(NotificationVisibility.class), anyBoolean(), eq(UNDEFINED_DISMISS_REASON));
     }
 
     private NotificationEntry createNotification() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index 7343e5e..19dd027 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification;
 
+import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
+
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.verify;
 
@@ -87,7 +89,8 @@
         mEntryListener.onEntryRemoved(
                 entry,
                 NotificationVisibility.obtain(entry.getKey(), 0, 0, true),
-                false);
+                false,
+                UNDEFINED_DISMISS_REASON);
         verify(mListContainer).cleanUpViewStateForEntry(entry);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index d2bb011..92a9080 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -21,6 +21,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.pm.ShortcutInfo;
 import android.os.UserHandle;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
@@ -266,4 +267,9 @@
         mRankingBuilder.setSmartReplies(smartReplies);
         return this;
     }
+
+    public NotificationEntryBuilder setShortcutInfo(ShortcutInfo shortcutInfo) {
+        mRankingBuilder.setShortcutInfo(shortcutInfo);
+        return this;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
index b0ca943..b1288f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
@@ -101,15 +101,13 @@
 
     @Test
     fun testViewModelDataSourceTransformsModel() {
-        val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0)
-        val fakePerson = fakePersonModel("id", "name", fakeClickIntent)
+        val fakeClickRunnable = mock(Runnable::class.java)
+        val fakePerson = fakePersonModel("id", "name", fakeClickRunnable)
         val fakeModel = PeopleHubModel(listOf(fakePerson))
         val fakeModelDataSource = FakeDataSource(fakeModel)
-        val fakeSettingDataSource = FakeDataSource(true)
         val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
                 mockActivityStarter,
-                fakeModelDataSource,
-                fakeSettingDataSource
+                fakeModelDataSource
         )
         val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
         val mockClickView = mock(View::class.java)
@@ -126,35 +124,7 @@
 
         people[0].onClick()
 
-        verify(mockActivityStarter).startPendingIntentDismissingKeyguard(
-                same(fakeClickIntent),
-                any(),
-                same(mockClickView)
-        )
-    }
-
-    @Test
-    fun testViewModelDataSource_notVisibleIfSettingDisabled() {
-        val fakeClickIntent = PendingIntent.getActivity(context, 0, Intent("action"), 0)
-        val fakePerson = fakePersonModel("id", "name", fakeClickIntent)
-        val fakeModel = PeopleHubModel(listOf(fakePerson))
-        val fakeModelDataSource = FakeDataSource(fakeModel)
-        val fakeSettingDataSource = FakeDataSource(false)
-        val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
-                mockActivityStarter,
-                fakeModelDataSource,
-                fakeSettingDataSource
-        )
-        val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
-        val mockClickView = mock(View::class.java)
-
-        factoryDataSource.registerListener(fakeListener)
-
-        val viewModel = (fakeListener.lastSeen as Maybe.Just).value
-                .createWithAssociatedClickView(mockClickView)
-        assertThat(viewModel.isVisible).isFalse()
-        val people = viewModel.people.toList()
-        assertThat(people.size).isEqualTo(0)
+        verify(fakeClickRunnable).run()
     }
 }
 
@@ -178,10 +148,10 @@
 private fun fakePersonModel(
     id: String,
     name: CharSequence,
-    clickIntent: PendingIntent,
+    clickRunnable: Runnable,
     userId: Int = 0
 ): PersonModel =
-        PersonModel(id, name, mock(Drawable::class.java), clickIntent, userId)
+        PersonModel(id, name, mock(Drawable::class.java), clickRunnable, userId)
 
 private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
         PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 6c12c76..e1ab33a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -198,7 +198,7 @@
                 .build();
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 notification, UserHandle.CURRENT, null, 0);
-        mEntry = new NotificationEntryBuilder().setSbn(mSbn).build();
+        mEntry = new NotificationEntryBuilder().setSbn(mSbn).setShortcutInfo(mShortcutInfo).build();
 
         PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0,
                 new Intent(mContext, BubblesTestActivity.class), 0);
@@ -207,7 +207,10 @@
                         .createIntentBubble(bubbleIntent,
                                 Icon.createWithResource(mContext, R.drawable.android)).build())
                 .build();
-        mBubbleEntry = new NotificationEntryBuilder().setSbn(mBubbleSbn).build();
+        mBubbleEntry = new NotificationEntryBuilder()
+                .setSbn(mBubbleSbn)
+                .setShortcutInfo(mShortcutInfo)
+                .build();
 
         mConversationChannel = new NotificationChannel(
                 TEST_CHANNEL + " : " + CONVERSATION_ID, TEST_CHANNEL_NAME, IMPORTANCE_LOW);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 48a3b25..5d0349d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -283,7 +283,8 @@
                 null,
                 false,
                 false,
-                false);
+                false,
+                null);
         mRankingMap = new NotificationListenerService.RankingMap(new Ranking[] {ranking});
 
         TestableLooper.get(this).processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index 3d59d61..dbb4512 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 
 import static junit.framework.Assert.assertFalse;
@@ -205,7 +206,8 @@
         // WHEN all active notifications are removed
         when(mEntryManager.hasActiveNotifications()).thenReturn(false);
         assertFalse(mLightsOutNotifController.shouldShowDot());
-        mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false);
+        mEntryListener.onEntryRemoved(
+                mock(NotificationEntry.class), null, false, REASON_CANCEL_ALL);
 
         // THEN we shouldn't see the dot view
         assertIsShowingDot(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index e171a28..f6a099d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
 
 import static org.junit.Assert.assertFalse;
@@ -254,7 +255,8 @@
         mGroupManager.onEntryAdded(summaryEntry);
         mGroupManager.onEntryAdded(childEntry);
 
-        mNotificationEntryListener.onEntryRemoved(childEntry, null, false);
+        mNotificationEntryListener.onEntryRemoved(
+                childEntry, null, false, UNDEFINED_DISMISS_REASON);
 
         assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
     }