From 469c69b53ee3688b18a92fac116a4ff9b56aee12 Mon Sep 17 00:00:00 2001 From: Anna Zappone Date: Fri, 12 Feb 2021 12:37:31 +0000 Subject: Add new templates & show Statuses in People Tiles Backup strings provided in the case of missing status text when icons are provided. Implements three layouts to handle our different states. Change-Id: I1cb81c42e4cdd75b000f52c402a7396897c0f027 Test: PeopleSpaceUtilsTest Bug: 178792356 --- .../SystemUI/res/drawable/circle_green_10dp.xml | 22 ++ .../drawable/people_space_content_background.xml | 2 +- .../drawable/people_space_new_story_outline.xml | 20 ++ .../drawable/people_space_round_tile_view_card.xml | 19 -- .../res/layout/people_space_large_avatar_tile.xml | 70 +++--- .../people_space_notification_content_tile.xml | 154 ++++++++++++ .../res/layout/people_space_small_avatar_tile.xml | 271 +++++++++------------ .../SystemUI/res/layout/punctuation_layout.xml | 100 ++++++++ packages/SystemUI/res/values/dimens.xml | 4 +- packages/SystemUI/res/values/strings.xml | 22 +- .../SystemUI/res/xml/people_space_widget_info.xml | 6 +- .../android/systemui/people/PeopleSpaceUtils.java | 218 ++++++++++++++--- .../systemui/people/PeopleSpaceUtilsTest.java | 178 +++++++++++++- 13 files changed, 834 insertions(+), 252 deletions(-) create mode 100644 packages/SystemUI/res/drawable/circle_green_10dp.xml create mode 100644 packages/SystemUI/res/drawable/people_space_new_story_outline.xml delete mode 100644 packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml create mode 100644 packages/SystemUI/res/layout/people_space_notification_content_tile.xml create mode 100644 packages/SystemUI/res/layout/punctuation_layout.xml diff --git a/packages/SystemUI/res/drawable/circle_green_10dp.xml b/packages/SystemUI/res/drawable/circle_green_10dp.xml new file mode 100644 index 000000000000..571ec621da9f --- /dev/null +++ b/packages/SystemUI/res/drawable/circle_green_10dp.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/people_space_content_background.xml b/packages/SystemUI/res/drawable/people_space_content_background.xml index 5310840939b8..32314d29277e 100644 --- a/packages/SystemUI/res/drawable/people_space_content_background.xml +++ b/packages/SystemUI/res/drawable/people_space_content_background.xml @@ -16,5 +16,5 @@ --> - + diff --git a/packages/SystemUI/res/drawable/people_space_new_story_outline.xml b/packages/SystemUI/res/drawable/people_space_new_story_outline.xml new file mode 100644 index 000000000000..a1737f92fa22 --- /dev/null +++ b/packages/SystemUI/res/drawable/people_space_new_story_outline.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml b/packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml deleted file mode 100644 index 59af7750dada..000000000000 --- a/packages/SystemUI/res/drawable/people_space_round_tile_view_card.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml index e9f3424547fa..b1c13287d203 100644 --- a/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml +++ b/packages/SystemUI/res/layout/people_space_large_avatar_tile.xml @@ -19,70 +19,78 @@ android:layout_height="match_parent" android:orientation="vertical"> - + - - + android:id="@+id/person_icon_inside_ring" + android:layout_marginEnd="4dp" + android:layout_marginStart="4dp" + android:layout_marginBottom="4dp" + android:layout_marginTop="4dp" + android:layout_width="52dp" + android:layout_height="52dp"/> + + - - + + + android:layout_height="wrap_content"/> + android:ellipsize="end"/> diff --git a/packages/SystemUI/res/layout/people_space_notification_content_tile.xml b/packages/SystemUI/res/layout/people_space_notification_content_tile.xml new file mode 100644 index 000000000000..739738ae9e35 --- /dev/null +++ b/packages/SystemUI/res/layout/people_space_notification_content_tile.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml index 03589d34efd2..bb4a20e4108e 100644 --- a/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml +++ b/packages/SystemUI/res/layout/people_space_small_avatar_tile.xml @@ -14,183 +14,144 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - - + + + + + + android:layout_height="wrap_content"> + + + + + + + + + android:maxLines="2" + android:ellipsize="end"/> + + + android:visibility="gone" + android:ellipsize="end"/> + - - - - - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content"/> \ No newline at end of file diff --git a/packages/SystemUI/res/layout/punctuation_layout.xml b/packages/SystemUI/res/layout/punctuation_layout.xml new file mode 100644 index 000000000000..25c7648530d6 --- /dev/null +++ b/packages/SystemUI/res/layout/punctuation_layout.xml @@ -0,0 +1,100 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 0d92aea6ed6f..b07df9caa95b 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1348,8 +1348,8 @@ 16dp 12.5dp - 24dp - 100dp + 28dp + 20dp 6dp 48dp diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d997ca2fa4a4..de47b2dcdba9 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2810,8 +2810,26 @@ Less than %1$s ago Over %1$s ago - - Today is their birthday! + + Birthday + + Birthday soon + + Anniversary + + Sharing location + + New story + + Watching + + Listening + + Playing + + Your friend + + Their status diff --git a/packages/SystemUI/res/xml/people_space_widget_info.xml b/packages/SystemUI/res/xml/people_space_widget_info.xml index d0c63a8b180c..fbdac5e1789b 100644 --- a/packages/SystemUI/res/xml/people_space_widget_info.xml +++ b/packages/SystemUI/res/xml/people_space_widget_info.xml @@ -16,11 +16,11 @@ diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java index 7eb1fc175c5a..f6fdbf2affa2 100644 --- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java +++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceUtils.java @@ -17,12 +17,21 @@ package com.android.systemui.people; import static android.app.Notification.EXTRA_MESSAGES; +import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY; +import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY; +import static android.app.people.ConversationStatus.ACTIVITY_GAME; +import static android.app.people.ConversationStatus.ACTIVITY_LOCATION; +import static android.app.people.ConversationStatus.ACTIVITY_MEDIA; +import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY; +import static android.app.people.ConversationStatus.ACTIVITY_UPCOMING_BIRTHDAY; +import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE; import android.annotation.Nullable; import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; import android.app.people.ConversationChannel; +import android.app.people.ConversationStatus; import android.app.people.IPeopleManager; import android.app.people.PeopleSpaceTile; import android.appwidget.AppWidgetManager; @@ -37,6 +46,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.icu.text.MeasureFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; @@ -71,6 +81,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import java.text.SimpleDateFormat; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -441,20 +452,141 @@ public class PeopleSpaceUtils { /** Creates a {@link RemoteViews} for {@code tile}. */ public static RemoteViews createRemoteViews(Context context, PeopleSpaceTile tile, int appWidgetId) { - RemoteViews views; + RemoteViews viewsForTile = getViewForTile(context, tile); + RemoteViews views = setCommonRemoteViewsFields(context, viewsForTile, tile); + return setLaunchIntents(context, views, tile, appWidgetId); + } + + /** + * The prioritization for the {@code tile} content is missed calls, followed by notification + * content, then birthdays, then the most recent status, and finally last interaction. + */ + private static RemoteViews getViewForTile(Context context, PeopleSpaceTile tile) { if (tile.getNotificationKey() != null) { - views = createNotificationRemoteViews(context, tile); - } else if (tile.getBirthdayText() != null) { - views = createStatusRemoteViews(context, tile); + if (DEBUG) Log.d(TAG, "Create notification view"); + return createNotificationRemoteViews(context, tile); + } + + // TODO: Add sorting when we expose timestamp of statuses. + List statusesForEntireView = + tile.getStatuses() == null ? Arrays.asList() : tile.getStatuses().stream().filter( + c -> isStatusValidForEntireStatusView(c)).collect(Collectors.toList()); + ConversationStatus birthdayStatus = getBirthdayStatus(tile, statusesForEntireView); + if (birthdayStatus != null) { + if (DEBUG) Log.d(TAG, "Create birthday view"); + return createStatusRemoteViews(context, birthdayStatus); + } + + if (!statusesForEntireView.isEmpty()) { + if (DEBUG) { + Log.d(TAG, + "Create status view for: " + statusesForEntireView.get(0).getActivity()); + } + return createStatusRemoteViews(context, statusesForEntireView.get(0)); + } + + return createLastInteractionRemoteViews(context, tile); + } + + @Nullable + private static ConversationStatus getBirthdayStatus(PeopleSpaceTile tile, + List statuses) { + Optional birthdayStatus = statuses.stream().filter( + c -> c.getActivity() == ACTIVITY_BIRTHDAY).findFirst(); + if (birthdayStatus.isPresent()) { + return birthdayStatus.get(); + } + if (!TextUtils.isEmpty(tile.getBirthdayText())) { + return new ConversationStatus.Builder(tile.getId(), ACTIVITY_BIRTHDAY).build(); + } + + return null; + } + + /** + * Returns whether a {@code status} should have its own entire templated view. + * + *

A status may still be shown on the view (for example, as a new story ring) even if it's + * not valid to compose an entire view. + */ + private static boolean isStatusValidForEntireStatusView(ConversationStatus status) { + switch (status.getActivity()) { + // Birthday & Anniversary don't require text provided or icon provided. + case ACTIVITY_BIRTHDAY: + case ACTIVITY_ANNIVERSARY: + return true; + default: + // For future birthday, location, new story, video, music, game, and other, the + // app must provide either text or an icon. + return !TextUtils.isEmpty(status.getDescription()) + || status.getIcon() != null; + } + } + + private static RemoteViews createStatusRemoteViews(Context context, ConversationStatus status) { + RemoteViews views = new RemoteViews( + context.getPackageName(), R.layout.people_space_small_avatar_tile); + CharSequence statusText = status.getDescription(); + if (TextUtils.isEmpty(statusText)) { + statusText = getStatusTextByType(context, status.getActivity()); + } + views.setTextViewText(R.id.status, statusText); + Icon statusIcon = status.getIcon(); + if (statusIcon != null) { + views.setImageViewIcon(R.id.image, statusIcon); + views.setBoolean(R.id.content_background, "setClipToOutline", true); } else { - views = createLastInteractionRemoteViews(context, tile); + views.setViewVisibility(R.id.content_background, View.GONE); + } + // TODO: Set status pre-defined icons + return views; + } + + private static String getStatusTextByType(Context context, int activity) { + switch (activity) { + case ACTIVITY_BIRTHDAY: + return context.getString(R.string.birthday_status); + case ACTIVITY_UPCOMING_BIRTHDAY: + return context.getString(R.string.upcoming_birthday_status); + case ACTIVITY_ANNIVERSARY: + return context.getString(R.string.anniversary_status); + case ACTIVITY_LOCATION: + return context.getString(R.string.location_status); + case ACTIVITY_NEW_STORY: + return context.getString(R.string.new_story_status); + case ACTIVITY_MEDIA: + return context.getString(R.string.video_status); + case ACTIVITY_GAME: + return context.getString(R.string.game_status); + default: + return EMPTY_STRING; } - return setCommonRemoteViewsFields(context, views, tile, appWidgetId); } private static RemoteViews setCommonRemoteViewsFields(Context context, RemoteViews views, - PeopleSpaceTile tile, int appWidgetId) { + PeopleSpaceTile tile) { try { + boolean isAvailable = + tile.getStatuses() != null && tile.getStatuses().stream().anyMatch( + c -> c.getAvailability() == AVAILABILITY_AVAILABLE); + if (isAvailable) { + views.setViewVisibility(R.id.availability, View.VISIBLE); + } else { + views.setViewVisibility(R.id.availability, View.GONE); + } + boolean hasNewStory = + tile.getStatuses() != null && tile.getStatuses().stream().anyMatch( + c -> c.getActivity() == ACTIVITY_NEW_STORY); + if (hasNewStory) { + views.setViewVisibility(R.id.person_icon_with_story, View.VISIBLE); + views.setViewVisibility(R.id.person_icon_only, View.GONE); + views.setImageViewIcon(R.id.person_icon_inside_ring, tile.getUserIcon()); + } else { + views.setViewVisibility(R.id.person_icon_with_story, View.GONE); + views.setViewVisibility(R.id.person_icon_only, View.VISIBLE); + views.setImageViewIcon(R.id.person_icon_only, tile.getUserIcon()); + } + views.setTextViewText(R.id.name, tile.getUserName().toString()); views.setImageViewIcon(R.id.person_icon, tile.getUserIcon()); views.setBoolean(R.id.content_background, "setClipToOutline", true); @@ -466,7 +598,16 @@ public class PeopleSpaceUtils { tile.getPackageName()) ) ); + return views; + } catch (Exception e) { + Log.e(TAG, "Failed to set common fields: " + e); + } + return views; + } + private static RemoteViews setLaunchIntents(Context context, RemoteViews views, + PeopleSpaceTile tile, int appWidgetId) { + try { Intent activityIntent = new Intent(context, LaunchConversationActivity.class); activityIntent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK @@ -484,48 +625,42 @@ public class PeopleSpaceUtils { PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE)); return views; } catch (Exception e) { - Log.e(TAG, "Failed to set common fields: " + e); + Log.e(TAG, "Failed to add launch intents: " + e); } - return null; + return views; } private static RemoteViews createNotificationRemoteViews(Context context, PeopleSpaceTile tile) { RemoteViews views = new RemoteViews( - context.getPackageName(), R.layout.people_space_small_avatar_tile); + context.getPackageName(), R.layout.people_space_notification_content_tile); Uri image = tile.getNotificationDataUri(); if (image != null) { - //TODO: Use NotificationInlineImageCache + // TODO: Use NotificationInlineImageCache views.setImageViewUri(R.id.image, image); - views.setViewVisibility(R.id.image, View.VISIBLE); + views.setViewVisibility(R.id.content_background, View.VISIBLE); + views.setBoolean(R.id.content_background, "setClipToOutline", true); views.setViewVisibility(R.id.content, View.GONE); } else { CharSequence content = tile.getNotificationContent(); views = setPunctuationRemoteViewsFields(views, content); views.setTextViewText(R.id.content, content); views.setViewVisibility(R.id.content, View.VISIBLE); - views.setViewVisibility(R.id.image, View.GONE); + views.setViewVisibility(R.id.content_background, View.GONE); } - views.setTextViewText(R.id.time, PeopleSpaceUtils.getLastInteractionString( + // TODO: Set subtext as Group Sender name once storing the name in PeopleSpaceTile. + views.setTextViewText(R.id.subtext, PeopleSpaceUtils.getLastInteractionString( context, tile.getLastInteractionTimestamp(), false)); return views; } - private static RemoteViews createStatusRemoteViews(Context context, - PeopleSpaceTile tile) { - RemoteViews views = new RemoteViews( - context.getPackageName(), R.layout.people_space_large_avatar_tile); - views.setTextViewText(R.id.status, tile.getBirthdayText()); - return views; - } - private static RemoteViews createLastInteractionRemoteViews(Context context, PeopleSpaceTile tile) { RemoteViews views = new RemoteViews( context.getPackageName(), R.layout.people_space_large_avatar_tile); String status = PeopleSpaceUtils.getLastInteractionString( context, tile.getLastInteractionTimestamp(), true); - views.setTextViewText(R.id.status, status); + views.setTextViewText(R.id.last_interaction, status); return views; } @@ -682,20 +817,35 @@ public class PeopleSpaceUtils { Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction); MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE); + MeasureFormat shortFormatter = MeasureFormat.getInstance(Locale.getDefault(), + MeasureFormat.FormatWidth.SHORT); if (durationSinceLastInteraction.toHours() < MIN_HOUR) { - return context.getString(includeLastChatted ? R.string.last_interaction_status_less_than - : R.string.less_than_timestamp, - formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR))); + if (includeLastChatted) { + return context.getString(R.string.last_interaction_status_less_than, + formatter.formatMeasures(new Measure(MIN_HOUR, MeasureUnit.HOUR))); + } + return context.getString(R.string.timestamp, shortFormatter.formatMeasures( + new Measure(durationSinceLastInteraction.toMinutes(), MeasureUnit.MINUTE))); } else if (durationSinceLastInteraction.toDays() < ONE_DAY) { - return context.getString( - includeLastChatted ? R.string.last_interaction_status : R.string.timestamp, - formatter.formatMeasures( - new Measure(durationSinceLastInteraction.toHours(), MeasureUnit.HOUR))); + if (includeLastChatted) { + return context.getString(R.string.last_interaction_status, + formatter.formatMeasures( + new Measure(durationSinceLastInteraction.toHours(), + MeasureUnit.HOUR))); + } + return context.getString(R.string.timestamp, shortFormatter.formatMeasures( + new Measure(durationSinceLastInteraction.toHours(), + MeasureUnit.HOUR))); } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) { - return context.getString( - includeLastChatted ? R.string.last_interaction_status : R.string.timestamp, - formatter.formatMeasures( - new Measure(durationSinceLastInteraction.toDays(), MeasureUnit.DAY))); + if (includeLastChatted) { + return context.getString(R.string.last_interaction_status, + formatter.formatMeasures( + new Measure(durationSinceLastInteraction.toDays(), + MeasureUnit.DAY))); + } + return context.getString(R.string.timestamp, shortFormatter.formatMeasures( + new Measure(durationSinceLastInteraction.toHours(), + MeasureUnit.DAY))); } else { return context.getString(durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK ? (includeLastChatted ? R.string.last_interaction_status : 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 4ee2759028a9..d79155cbb2fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleSpaceUtilsTest.java @@ -16,11 +16,18 @@ package com.android.systemui.people; +import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY; +import static android.app.people.ConversationStatus.ACTIVITY_GAME; +import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY; +import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE; + import static com.android.systemui.people.PeopleSpaceUtils.OPTIONS_PEOPLE_SPACE_TILE; import static com.android.systemui.people.PeopleSpaceUtils.PACKAGE_NAME; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -39,6 +46,7 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Person; import android.app.people.ConversationChannel; +import android.app.people.ConversationStatus; import android.app.people.IPeopleManager; import android.app.people.PeopleSpaceTile; import android.appwidget.AppWidgetManager; @@ -46,13 +54,13 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.LauncherApps; +import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; import android.database.Cursor; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Bundle; -import android.os.RemoteException; import android.os.UserHandle; import android.provider.ContactsContract; import android.provider.Settings; @@ -60,6 +68,9 @@ import android.service.notification.ConversationChannelWrapper; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; +import android.view.View; +import android.widget.RemoteViews; +import android.widget.TextView; import com.android.internal.appwidget.IAppWidgetService; import com.android.systemui.R; @@ -101,27 +112,45 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { private static final int TEST_COLUMN_INDEX = 1; private static final Uri URI = Uri.parse("fake_uri"); private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android); + private static final String GAME_DESCRIPTION = "Playing a game!"; + private static final String NAME = "username"; private static final Person PERSON = new Person.Builder() .setName("name") .setKey("abc") .setUri(URI.toString()) .setBot(false) .build(); + private static final PeopleSpaceTile PERSON_TILE_WITHOUT_NOTIFICATION = + new PeopleSpaceTile + .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent()) + .setLastInteractionTimestamp(0L) + .build(); private static final PeopleSpaceTile PERSON_TILE = new PeopleSpaceTile - .Builder(SHORTCUT_ID_1, "username", ICON, new Intent()) + .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent()) + .setLastInteractionTimestamp(123L) .setNotificationKey(NOTIFICATION_KEY) .setNotificationContent(NOTIFICATION_CONTENT) .setNotificationDataUri(URI) .build(); + private static final ConversationStatus GAME_STATUS = + new ConversationStatus + .Builder(PERSON_TILE.getId(), ACTIVITY_GAME) + .setDescription(GAME_DESCRIPTION) + .build(); + private static final ConversationStatus NEW_STORY_WITH_AVAILABILITY = + new ConversationStatus + .Builder(PERSON_TILE.getId(), ACTIVITY_NEW_STORY) + .setAvailability(AVAILABILITY_AVAILABLE) + .build(); private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).setLongLabel( - "name").setPerson(PERSON) + NAME).setPerson(PERSON) .build(); private final ShortcutInfo mShortcutInfoWithoutPerson = new ShortcutInfo.Builder(mContext, SHORTCUT_ID_1).setLongLabel( - "name") + NAME) .build(); private final Notification mNotification1 = new Notification.Builder(mContext, "test") .setContentTitle("TEST_TITLE") @@ -189,10 +218,12 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { @Mock private Context mMockContext; @Mock + private PackageManager mPackageManager; + @Mock private NotificationEntryManager mNotificationEntryManager; @Before - public void setUp() throws RemoteException { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.PEOPLE_SPACE_CONVERSATION_TYPE, 0); @@ -212,6 +243,12 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { isNull())).thenReturn(mMockCursor); when(mMockContext.getString(R.string.birthday_status)).thenReturn( mContext.getString(R.string.birthday_status)); + when(mMockContext.getString(R.string.basic_status)).thenReturn( + mContext.getString(R.string.basic_status)); + when(mMockContext.getPackageManager()).thenReturn(mPackageManager); + when(mMockContext.getString(R.string.over_timestamp)).thenReturn( + mContext.getString(R.string.over_timestamp)); + when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null); when(mNotificationEntryManager.getVisibleNotifications()) .thenReturn(List.of(mNotificationEntry1, mNotificationEntry2, mNotificationEntry3)); } @@ -621,6 +658,137 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase { any()); } + @Test + public void testCreateRemoteViewsWithLastInteractionTime() { + RemoteViews views = PeopleSpaceUtils.createRemoteViews(mMockContext, + PERSON_TILE_WITHOUT_NOTIFICATION, 0); + View result = views.apply(mContext, null); + + TextView name = (TextView) result.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + // Has last interaction. + TextView lastInteraction = (TextView) result.findViewById(R.id.last_interaction); + assertEquals(lastInteraction.getText(), mContext.getString(R.string.basic_status)); + // No availability. + View availability = result.findViewById(R.id.availability); + assertEquals(View.GONE, availability.getVisibility()); + // No new story. + View personIcon = result.findViewById(R.id.person_icon_only); + View personIconWithStory = result.findViewById(R.id.person_icon_with_story); + assertEquals(View.VISIBLE, personIcon.getVisibility()); + assertEquals(View.GONE, personIconWithStory.getVisibility()); + // No status. + assertThat((View) result.findViewById(R.id.status)).isNull(); + } + + @Test + public void testCreateRemoteViewsWithGameTypeOnlyIsIgnored() { + PeopleSpaceTile tileWithAvailabilityAndNewStory = + PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses( + Arrays.asList(NEW_STORY_WITH_AVAILABILITY, + new ConversationStatus.Builder( + PERSON_TILE_WITHOUT_NOTIFICATION.getId(), + ACTIVITY_GAME).build())).build(); + RemoteViews views = PeopleSpaceUtils.createRemoteViews(mMockContext, + tileWithAvailabilityAndNewStory, 0); + View result = views.apply(mContext, null); + + TextView name = (TextView) result.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + // Has last interaction over status. + TextView lastInteraction = (TextView) result.findViewById(R.id.last_interaction); + assertEquals(lastInteraction.getText(), mContext.getString(R.string.basic_status)); + // Has availability. + View availability = result.findViewById(R.id.availability); + assertEquals(View.VISIBLE, availability.getVisibility()); + // Has new story. + View personIcon = result.findViewById(R.id.person_icon_only); + View personIconWithStory = result.findViewById(R.id.person_icon_with_story); + assertEquals(View.GONE, personIcon.getVisibility()); + assertEquals(View.VISIBLE, personIconWithStory.getVisibility()); + // No status. + assertThat((View) result.findViewById(R.id.status)).isNull(); + } + + @Test + public void testCreateRemoteViewsWithBirthdayTypeOnlyIsNotIgnored() { + PeopleSpaceTile tileWithStatusTemplate = + PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses( + Arrays.asList( + NEW_STORY_WITH_AVAILABILITY, new ConversationStatus.Builder( + PERSON_TILE_WITHOUT_NOTIFICATION.getId(), + ACTIVITY_BIRTHDAY).build())).build(); + RemoteViews views = PeopleSpaceUtils.createRemoteViews(mContext, + tileWithStatusTemplate, 0); + View result = views.apply(mContext, null); + + TextView name = (TextView) result.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + // Has availability. + View availability = result.findViewById(R.id.availability); + assertEquals(View.VISIBLE, availability.getVisibility()); + // Has new story. + View personIcon = result.findViewById(R.id.person_icon_only); + View personIconWithStory = result.findViewById(R.id.person_icon_with_story); + assertEquals(View.GONE, personIcon.getVisibility()); + assertEquals(View.VISIBLE, personIconWithStory.getVisibility()); + // Has status text from backup text. + TextView statusContent = (TextView) result.findViewById(R.id.status); + assertEquals(statusContent.getText(), mContext.getString(R.string.birthday_status)); + } + + @Test + public void testCreateRemoteViewsWithStatusTemplate() { + PeopleSpaceTile tileWithStatusTemplate = + PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses( + Arrays.asList(GAME_STATUS, + NEW_STORY_WITH_AVAILABILITY)).build(); + RemoteViews views = PeopleSpaceUtils.createRemoteViews(mContext, + tileWithStatusTemplate, 0); + View result = views.apply(mContext, null); + + TextView name = (TextView) result.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + // Has availability. + View availability = result.findViewById(R.id.availability); + assertEquals(View.VISIBLE, availability.getVisibility()); + // Has new story. + View personIcon = result.findViewById(R.id.person_icon_only); + View personIconWithStory = result.findViewById(R.id.person_icon_with_story); + assertEquals(View.GONE, personIcon.getVisibility()); + assertEquals(View.VISIBLE, personIconWithStory.getVisibility()); + // Has status. + TextView statusContent = (TextView) result.findViewById(R.id.status); + assertEquals(statusContent.getText(), GAME_DESCRIPTION); + } + + @Test + public void testCreateRemoteViewsWithNotificationTemplate() { + PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder() + .setNotificationDataUri(null) + .setStatuses(Arrays.asList(GAME_STATUS, + NEW_STORY_WITH_AVAILABILITY)).build(); + RemoteViews views = PeopleSpaceUtils.createRemoteViews(mContext, + tileWithStatusAndNotification, 0); + View result = views.apply(mContext, null); + + TextView name = (TextView) result.findViewById(R.id.name); + assertEquals(name.getText(), NAME); + TextView subtext = (TextView) result.findViewById(R.id.subtext); + assertTrue(subtext.getText().toString().contains("weeks ago")); + // Has availability. + View availability = result.findViewById(R.id.availability); + assertEquals(View.VISIBLE, availability.getVisibility()); + // Has new story. + View personIcon = result.findViewById(R.id.person_icon_only); + View personIconWithStory = result.findViewById(R.id.person_icon_with_story); + assertEquals(View.GONE, personIcon.getVisibility()); + assertEquals(View.VISIBLE, personIconWithStory.getVisibility()); + // Has notification content. + TextView statusContent = (TextView) result.findViewById(R.id.content); + assertEquals(statusContent.getText(), NOTIFICATION_CONTENT); + } + private ConversationChannelWrapper getConversationChannelWrapper(String shortcutId, boolean importantConversation, long lastInteractionTimestamp) throws Exception { ConversationChannelWrapper convo = new ConversationChannelWrapper(); -- cgit v1.2.3-59-g8ed1b