From a0af6cf7955a2932a6747a5b846dcebf24c93a20 Mon Sep 17 00:00:00 2001 From: Anna Zappone Date: Tue, 12 Jan 2021 18:53:33 +0000 Subject: [PATCH] Add nonpriority conversations into sorted Recents Retrieve nonpriority conversations, and delay sorting until we've merged with Recent conversations. This ensures Priority is sorted at the top, and then all conversations afterwards are sorted. Test: PeopleSpaceUtilsTest Change-Id: I9ff7f16a530b81a36a591989bb24171ac72a78b1 --- .../systemui/people/PeopleSpaceUtils.java | 52 +++++--- .../systemui/people/PeopleSpaceUtilsTest.java | 125 +++++++++++++++++- .../widget/PeopleSpaceWidgetManagerTest.java | 14 +- 3 files changed, 164 insertions(+), 27 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index 12d5bac216e28..67d53fcd7285e 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -23,12 +23,12 @@ import android.app.Notification; import android.app.PendingIntent; import android.app.people.ConversationChannel; import android.app.people.IPeopleManager; -import android.appwidget.AppWidgetHost; import android.appwidget.AppWidgetManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.LauncherApps; +import android.content.pm.ShortcutInfo; import android.database.Cursor; import android.database.SQLException; import android.graphics.Bitmap; @@ -72,6 +72,7 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -129,25 +130,36 @@ public class PeopleSpaceUtils { throws Exception { boolean showOnlyPriority = Settings.Global.getInt(context.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0) == 1; - List conversations = notificationManager.getConversations( - true).getList(); - List tiles = getSortedTiles(peopleManager, - conversations.stream().filter(c -> c.getShortcutInfo() != null).map( - c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(), - launcherApps).build())); + List conversations = + notificationManager.getConversations( + false).getList(); + + // Add priority conversations to tiles list. + Stream priorityConversations = conversations.stream() + .filter(c -> c.getNotificationChannel() != null + && c.getNotificationChannel().isImportantConversation()) + .map(c -> c.getShortcutInfo()); + List tiles = getSortedTiles(peopleManager, launcherApps, + priorityConversations); + + // Sort and then add recent and non priority conversations to tiles list. if (!showOnlyPriority) { if (DEBUG) Log.d(TAG, "Add recent conversations"); - List recentConversations = + Stream nonPriorityConversations = conversations.stream() + .filter(c -> c.getNotificationChannel() == null + || !c.getNotificationChannel().isImportantConversation()) + .map(c -> c.getShortcutInfo()); + + List recentConversationsList = peopleManager.getRecentConversations().getList(); + Stream recentConversations = recentConversationsList + .stream() + .map(c -> c.getShortcutInfo()); + + Stream mergedStream = Stream.concat(nonPriorityConversations, + recentConversations); List recentTiles = - getSortedTiles(peopleManager, - recentConversations - .stream() - .filter( - c -> c.getShortcutInfo() != null) - .map( - c -> new PeopleSpaceTile.Builder(c.getShortcutInfo(), - launcherApps).build())); + getSortedTiles(peopleManager, launcherApps, mergedStream); tiles.addAll(recentTiles); } return tiles; @@ -417,8 +429,11 @@ public class PeopleSpaceUtils { /** Returns a list sorted by ascending last interaction time from {@code stream}. */ private static List getSortedTiles(IPeopleManager peopleManager, - Stream stream) { + LauncherApps launcherApps, + Stream stream) { return stream + .filter(Objects::nonNull) + .map(c -> new PeopleSpaceTile.Builder(c, launcherApps).build()) .filter(c -> shouldKeepConversation(c)) .map(c -> c.toBuilder().setLastInteractionTimestamp( getLastInteraction(peopleManager, c)).build()) @@ -653,5 +668,4 @@ public class PeopleSpaceUtils { } return lookupKeysWithBirthdaysToday; } -} - +} \ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java index e6cc107458067..64b96765106ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -21,6 +21,8 @@ import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; @@ -30,13 +32,19 @@ 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.app.NotificationManager; import android.app.Person; +import android.app.people.ConversationChannel; +import android.app.people.IPeopleManager; import android.appwidget.AppWidgetManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; +import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.database.Cursor; import android.graphics.drawable.Icon; @@ -45,6 +53,7 @@ import android.os.Bundle; import android.os.RemoteException; import android.provider.ContactsContract; import android.provider.Settings; +import android.service.notification.ConversationChannelWrapper; import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; @@ -62,7 +71,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Arrays; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @SmallTest @RunWith(AndroidTestingRunner.class) @@ -103,6 +115,12 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { @Mock private NotificationListener mListenerService; @Mock + private INotificationManager mNotificationManager; + @Mock + private IPeopleManager mPeopleManager; + @Mock + private LauncherApps mLauncherApps; + @Mock private IAppWidgetService mIAppWidgetService; @Mock private AppWidgetManager mAppWidgetManager; @@ -136,6 +154,85 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { mContext.getString(R.string.birthday_status)); } + @Test + public void testGetTilesReturnsSortedListWithMultipleRecentConversations() throws Exception { + // Ensure the less-recent Important conversation is before more recent conversations. + ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper( + SHORTCUT_ID, false, 3); + ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper( + SHORTCUT_ID + 1, + true, 1); + when(mNotificationManager.getConversations(anyBoolean())).thenReturn( + new ParceledListSlice(Arrays.asList( + newerNonImportantConversation, olderImportantConversation))); + + // Ensure the non-Important conversation is sorted between these recent conversations. + ConversationChannel recentConversationBeforeNonImportantConversation = + getConversationChannel( + SHORTCUT_ID + 2, 4); + ConversationChannel recentConversationAfterNonImportantConversation = + getConversationChannel(SHORTCUT_ID + 3, + 2); + when(mPeopleManager.getRecentConversations()).thenReturn( + new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation, + recentConversationBeforeNonImportantConversation))); + + List orderedShortcutIds = PeopleSpaceUtils.getTiles( + mContext, mNotificationManager, mPeopleManager, + mLauncherApps).stream().map(tile -> tile.getId()).collect(Collectors.toList()); + + assertThat(orderedShortcutIds).containsExactly( + // Even though the oldest conversation, should be first since "important" + olderImportantConversation.getShortcutInfo().getId(), + // Non-priority conversations should be sorted within recent conversations. + recentConversationBeforeNonImportantConversation.getShortcutInfo().getId(), + newerNonImportantConversation.getShortcutInfo().getId(), + recentConversationAfterNonImportantConversation.getShortcutInfo().getId()) + .inOrder(); + } + + @Test + public void testGetTilesReturnsSortedListWithMultipleImportantAndRecentConversations() + throws Exception { + // Ensure the less-recent Important conversation is before more recent conversations. + ConversationChannelWrapper newerNonImportantConversation = getConversationChannelWrapper( + SHORTCUT_ID, false, 3); + ConversationChannelWrapper newerImportantConversation = getConversationChannelWrapper( + SHORTCUT_ID + 1, true, 3); + ConversationChannelWrapper olderImportantConversation = getConversationChannelWrapper( + SHORTCUT_ID + 2, + true, 1); + when(mNotificationManager.getConversations(anyBoolean())).thenReturn( + new ParceledListSlice(Arrays.asList( + newerNonImportantConversation, newerImportantConversation, + olderImportantConversation))); + + // Ensure the non-Important conversation is sorted between these recent conversations. + ConversationChannel recentConversationBeforeNonImportantConversation = + getConversationChannel( + SHORTCUT_ID + 3, 4); + ConversationChannel recentConversationAfterNonImportantConversation = + getConversationChannel(SHORTCUT_ID + 4, + 2); + when(mPeopleManager.getRecentConversations()).thenReturn( + new ParceledListSlice(Arrays.asList(recentConversationAfterNonImportantConversation, + recentConversationBeforeNonImportantConversation))); + + List orderedShortcutIds = PeopleSpaceUtils.getTiles( + mContext, mNotificationManager, mPeopleManager, + mLauncherApps).stream().map(tile -> tile.getId()).collect(Collectors.toList()); + + assertThat(orderedShortcutIds).containsExactly( + // Important conversations should be sorted at the beginning. + newerImportantConversation.getShortcutInfo().getId(), + olderImportantConversation.getShortcutInfo().getId(), + // Non-priority conversations should be sorted within recent conversations. + recentConversationBeforeNonImportantConversation.getShortcutInfo().getId(), + newerNonImportantConversation.getShortcutInfo().getId(), + recentConversationAfterNonImportantConversation.getShortcutInfo().getId()) + .inOrder(); + } + @Test public void testGetLastMessagingStyleMessageNoMessage() { Notification notification = new Notification.Builder(mContext, "test") @@ -385,4 +482,30 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { verify(mAppWidgetManager, times(1)).updateAppWidget(eq(WIDGET_ID_WITH_SHORTCUT), any()); } -} + + private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId, + boolean importantConversation, long lastInteractionTimestamp) throws Exception { + ConversationChannelWrapper convo = new ConversationChannelWrapper(); + NotificationChannel notificationChannel = new NotificationChannel(shortcutId, + "channel" + shortcutId, + NotificationManager.IMPORTANCE_DEFAULT); + notificationChannel.setImportantConversation(importantConversation); + convo.setNotificationChannel(notificationChannel); + convo.setShortcutInfo(new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel( + "name").build()); + when(mPeopleManager.getLastInteraction(anyString(), anyInt(), + eq(shortcutId))).thenReturn(lastInteractionTimestamp); + return convo; + } + + private ConversationChannel getConversationChannel(String shortcutId, + long lastInteractionTimestamp) throws Exception { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext, shortcutId).setLongLabel( + "name").build(); + ConversationChannel convo = new ConversationChannel(shortcutInfo, 0, null, null, + lastInteractionTimestamp, false); + when(mPeopleManager.getLastInteraction(anyString(), anyInt(), + eq(shortcutId))).thenReturn(lastInteractionTimestamp); + return convo; + } +} \ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java index 63ea7dd6f4a41..e7363f3ce4f79 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/widget/PeopleSpaceWidgetManagerTest.java @@ -207,7 +207,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); @@ -229,7 +229,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); @@ -326,7 +326,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testDoNotUpdateNotificationPostedIfNoExistingTile() throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); @@ -346,7 +346,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testDoNotUpdateNotificationRemovedIfNoExistingTile() throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); @@ -368,7 +368,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testUpdateNotificationPostedIfExistingTile() throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); @@ -389,7 +389,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray); @@ -416,7 +416,7 @@ public class PeopleSpaceWidgetManagerTest extends SysuiTestCase { public void testUpdateNotificationRemovedIfExistingTile() throws RemoteException { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); - when(mINotificationManager.getConversations(true)).thenReturn( + when(mINotificationManager.getConversations(false)).thenReturn( new ParceledListSlice(getConversationWithShortcutId())); int[] widgetIdsArray = {WIDGET_ID_WITH_SHORTCUT, WIDGET_ID_WITHOUT_SHORTCUT}; when(mIAppWidgetService.getAppWidgetIds(any())).thenReturn(widgetIdsArray);