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);