1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.people;
18 
19 import static android.app.Notification.CATEGORY_MISSED_CALL;
20 import static android.app.people.ConversationStatus.ACTIVITY_ANNIVERSARY;
21 import static android.app.people.ConversationStatus.ACTIVITY_BIRTHDAY;
22 import static android.app.people.ConversationStatus.ACTIVITY_GAME;
23 import static android.app.people.ConversationStatus.ACTIVITY_NEW_STORY;
24 import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE;
25 import static android.app.people.PeopleSpaceTile.BLOCK_CONVERSATIONS;
26 import static android.app.people.PeopleSpaceTile.SHOW_CONTACTS;
27 import static android.app.people.PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS;
28 import static android.app.people.PeopleSpaceTile.SHOW_STARRED_CONTACTS;
29 
30 import static com.android.systemui.people.PeopleSpaceUtils.STARRED_CONTACT;
31 import static com.android.systemui.people.PeopleSpaceUtils.VALID_CONTACT;
32 
33 import static com.google.common.truth.Truth.assertThat;
34 
35 import static org.junit.Assert.assertEquals;
36 import static org.mockito.ArgumentMatchers.any;
37 import static org.mockito.ArgumentMatchers.anyString;
38 import static org.mockito.Mockito.doReturn;
39 import static org.mockito.Mockito.doThrow;
40 import static org.mockito.Mockito.mock;
41 import static org.mockito.Mockito.spy;
42 import static org.mockito.Mockito.when;
43 
44 import android.app.people.ConversationStatus;
45 import android.app.people.PeopleSpaceTile;
46 import android.content.Context;
47 import android.content.Intent;
48 import android.content.pm.PackageManager;
49 import android.content.res.Configuration;
50 import android.content.res.Resources;
51 import android.graphics.drawable.BitmapDrawable;
52 import android.graphics.drawable.Icon;
53 import android.net.Uri;
54 import android.os.UserHandle;
55 import android.util.DisplayMetrics;
56 import android.view.View;
57 import android.widget.RemoteViews;
58 import android.widget.TextView;
59 
60 import androidx.test.ext.junit.runners.AndroidJUnit4;
61 import androidx.test.filters.SmallTest;
62 
63 import com.android.systemui.SysuiTestCase;
64 import com.android.systemui.people.widget.PeopleTileKey;
65 import com.android.systemui.res.R;
66 
67 import org.junit.Before;
68 import org.junit.Test;
69 import org.junit.runner.RunWith;
70 import org.mockito.Mock;
71 import org.mockito.MockitoAnnotations;
72 
73 import java.time.Duration;
74 import java.util.Arrays;
75 
76 @RunWith(AndroidJUnit4.class)
77 @SmallTest
78 public class PeopleTileViewHelperTest extends SysuiTestCase {
79 
80     private static final String SHORTCUT_ID_1 = "101";
81     private static final String NOTIFICATION_KEY = "notification_key";
82     private static final String NOTIFICATION_CONTENT = "notification_content";
83     private static final Uri URI = Uri.parse("fake_uri");
84     private static final Icon ICON = Icon.createWithResource("package", R.drawable.ic_android);
85     private static final String GAME_DESCRIPTION = "Playing a game!";
86     private static final CharSequence MISSED_CALL = "Custom missed call message";
87     private static final String NAME = "username";
88     private static final UserHandle USER = new UserHandle(0);
89     private static final String SENDER = "sender";
90 
91     private static final CharSequence EMOJI_BR_FLAG = "\ud83c\udde7\ud83c\uddf7";
92     private static final CharSequence EMOJI_BEAR = "\ud83d\udc3b";
93     private static final CharSequence EMOJI_THUMBS_UP_BROWN_SKIN = "\uD83D\uDC4D\uD83C\uDFFD";
94     private static final CharSequence EMOJI_JOY = "\uD83D\uDE02";
95     private static final CharSequence EMOJI_FAMILY =
96             "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67";
97 
98     private static final PeopleSpaceTile PERSON_TILE_WITHOUT_NOTIFICATION =
99             new PeopleSpaceTile
100                     .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
101                     .setLastInteractionTimestamp(0L)
102                     .setUserHandle(USER)
103                     .build();
104     private static final PeopleSpaceTile PERSON_TILE =
105             new PeopleSpaceTile
106                     .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
107                     .setLastInteractionTimestamp(123L)
108                     .setNotificationKey(NOTIFICATION_KEY)
109                     .setNotificationContent(NOTIFICATION_CONTENT)
110                     .setNotificationDataUri(URI)
111                     .setUserHandle(USER)
112                     .build();
113     private static final PeopleSpaceTile PERSON_TILE_WITH_SENDER =
114             new PeopleSpaceTile
115                     .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
116                     .setLastInteractionTimestamp(123L)
117                     .setNotificationKey(NOTIFICATION_KEY)
118                     .setNotificationContent(NOTIFICATION_CONTENT)
119                     .setNotificationSender(SENDER)
120                     .setUserHandle(USER)
121                     .build();
122     private static final ConversationStatus GAME_STATUS =
123             new ConversationStatus
124                     .Builder(PERSON_TILE.getId(), ACTIVITY_GAME)
125                     .setDescription(GAME_DESCRIPTION)
126                     .build();
127     private static final ConversationStatus NEW_STORY_WITH_AVAILABILITY =
128             new ConversationStatus
129                     .Builder(PERSON_TILE.getId(), ACTIVITY_NEW_STORY)
130                     .setAvailability(AVAILABILITY_AVAILABLE)
131                     .build();
132 
133     @Mock
134     private Icon mIcon;
135 
136     @Mock
137     private Context mMockContext;
138     @Mock
139     private PackageManager mPackageManager;
140 
141     private int mWidth;
142     private int mHeight;
143     private PeopleTileViewHelper mPeopleTileViewHelper;
144 
145     @Before
setUp()146     public void setUp() throws Exception {
147         MockitoAnnotations.initMocks(this);
148 
149         when(mMockContext.getString(R.string.birthday_status)).thenReturn(
150                 mContext.getString(R.string.birthday_status));
151         when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
152         when(mMockContext.getString(R.string.over_two_weeks_timestamp)).thenReturn(
153                 mContext.getString(R.string.over_two_weeks_timestamp));
154         Configuration configuration = mock(Configuration.class);
155         DisplayMetrics displayMetrics = mock(DisplayMetrics.class);
156         Resources resources = mock(Resources.class);
157         when(mMockContext.getResources()).thenReturn(resources);
158         when(resources.getConfiguration()).thenReturn(configuration);
159         when(resources.getDisplayMetrics()).thenReturn(displayMetrics);
160         TextView textView = mock(TextView.class);
161         when(textView.getLineHeight()).thenReturn(16);
162         when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null);
163 
164         mWidth = getSizeInDp(R.dimen.default_width);
165         mHeight = getSizeInDp(R.dimen.default_height);
166         mPeopleTileViewHelper = getPeopleTileViewHelper(PERSON_TILE);
167     }
168 
169     @Test
testCreateRemoteViewsWithLastInteractionTimeUnderOneDayHidden()170     public void testCreateRemoteViewsWithLastInteractionTimeUnderOneDayHidden() {
171         RemoteViews views = getPeopleTileViewHelper(PERSON_TILE_WITHOUT_NOTIFICATION).getViews();
172         View result = views.apply(mContext, null);
173 
174         // Not showing last interaction.
175         assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility());
176 
177         mWidth = getSizeInDp(R.dimen.required_width_for_large);
178         mHeight = getSizeInDp(R.dimen.required_height_for_large);
179         RemoteViews largeView = getPeopleTileViewHelper(
180                 PERSON_TILE_WITHOUT_NOTIFICATION).getViews();
181         View largeResult = largeView.apply(mContext, null);
182 
183         // Not showing last interaction.
184         assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility());
185     }
186 
187     @Test
testLastInteractionTime()188     public void testLastInteractionTime() {
189         long now = System.currentTimeMillis();
190         long fiveDaysAgo = now - Duration.ofDays(5).toMillis();
191         String lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
192                 fiveDaysAgo);
193         assertThat(lastInteractionString).isEqualTo("5 days ago");
194 
195         long lessThanOneDayAgo = now - Duration.ofHours(20).toMillis();
196         lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
197                 lessThanOneDayAgo);
198         assertThat(lastInteractionString).isNull();
199 
200         long overOneWeekAgo = now - Duration.ofDays(8).toMillis();
201         lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
202                 overOneWeekAgo);
203         assertThat(lastInteractionString).isEqualTo("Over 1 week ago");
204 
205         long overTwoWeeksAgo = now - Duration.ofDays(15).toMillis();
206         lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
207                 overTwoWeeksAgo);
208         assertThat(lastInteractionString).isEqualTo("Over 2 weeks ago");
209     }
210 
211     @Test
testCreateRemoteViewsWithLastInteractionTime()212     public void testCreateRemoteViewsWithLastInteractionTime() {
213         PeopleSpaceTile tileWithLastInteraction =
214                 PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setLastInteractionTimestamp(
215                         123445L).build();
216         RemoteViews views = getPeopleTileViewHelper(tileWithLastInteraction).getViews();
217         View result = views.apply(mContext, null);
218 
219         TextView name = (TextView) result.findViewById(R.id.name);
220         assertEquals(name.getText(), NAME);
221         // Has last interaction.
222         assertEquals(View.VISIBLE, result.findViewById(R.id.last_interaction).getVisibility());
223         TextView lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
224         assertEquals(lastInteraction.getText(), "Over 2 weeks ago");
225         // No availability.
226         assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
227         // Shows person icon.
228         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
229         // No status.
230         assertThat((View) result.findViewById(R.id.text_content)).isNull();
231 
232         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
233         RemoteViews smallView = getPeopleTileViewHelper(tileWithLastInteraction).getViews();
234         View smallResult = smallView.apply(mContext, null);
235 
236         // Show name over predefined icon.
237         assertEquals(View.VISIBLE, smallResult.findViewById(R.id.name).getVisibility());
238         assertEquals(View.GONE, smallResult.findViewById(R.id.predefined_icon).getVisibility());
239         // Shows person icon.
240         assertEquals(View.VISIBLE, smallResult.findViewById(R.id.person_icon).getVisibility());
241         // No messages count.
242         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
243 
244         mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
245         RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
246                 tileWithLastInteraction).getViews();
247         View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);
248 
249         // Show name over predefined icon.
250         assertEquals(View.VISIBLE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
251         assertEquals(View.GONE,
252                 smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
253         // Shows person icon.
254         assertEquals(View.VISIBLE,
255                 smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
256         // No messages count.
257         assertEquals(View.GONE,
258                 smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());
259 
260         mWidth = getSizeInDp(R.dimen.required_width_for_large);
261         mHeight = getSizeInDp(R.dimen.required_height_for_large);
262         RemoteViews largeView = getPeopleTileViewHelper(
263                 tileWithLastInteraction).getViews();
264         View largeResult = largeView.apply(mContext, null);
265 
266         name = (TextView) largeResult.findViewById(R.id.name);
267         assertEquals(name.getText(), NAME);
268         // Has last interaction.
269         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.last_interaction).getVisibility());
270         lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
271         assertEquals(lastInteraction.getText(), "Over 2 weeks ago");
272         // No availability.
273         assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
274         // Shows person icon.
275         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
276         // No status.
277         assertThat((View) result.findViewById(R.id.text_content)).isNull();
278     }
279 
280     @Test
testCreateRemoteViewsWithGameTypeOnlyIsIgnored()281     public void testCreateRemoteViewsWithGameTypeOnlyIsIgnored() {
282         PeopleSpaceTile tileWithAvailabilityAndNewStory =
283                 PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(
284                         Arrays.asList(NEW_STORY_WITH_AVAILABILITY,
285                                 new ConversationStatus.Builder(
286                                         PERSON_TILE_WITHOUT_NOTIFICATION.getId(),
287                                         ACTIVITY_GAME).build())).build();
288         RemoteViews views = getPeopleTileViewHelper(tileWithAvailabilityAndNewStory).getViews();
289         View result = views.apply(mContext, null);
290 
291         TextView name = (TextView) result.findViewById(R.id.name);
292         assertEquals(name.getText(), NAME);
293         // Has last interaction over status.
294         assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility());
295         // Has availability.
296         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
297         assertEquals(result.findViewById(R.id.availability).getContentDescription(),
298                 mContext.getString(R.string.person_available));
299         // Has person icon.
300         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
301         // No status.
302         assertThat((View) result.findViewById(R.id.text_content)).isNull();
303 
304         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
305         RemoteViews smallView = getPeopleTileViewHelper(tileWithAvailabilityAndNewStory).getViews();
306         View smallResult = smallView.apply(mContext, null);
307 
308         // Show name rather than game type.
309         assertEquals(View.VISIBLE, smallResult.findViewById(R.id.name).getVisibility());
310         assertEquals(View.GONE, smallResult.findViewById(R.id.predefined_icon).getVisibility());
311         // Has person icon.
312         assertEquals(View.VISIBLE,
313                 smallResult.findViewById(R.id.person_icon).getVisibility());
314         // No messages count.
315         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
316 
317         mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
318         RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
319                 tileWithAvailabilityAndNewStory).getViews();
320         View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);
321 
322         // Show name over predefined icon.
323         assertEquals(View.VISIBLE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
324         assertEquals(View.GONE,
325                 smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
326         // Shows person icon.
327         assertEquals(View.VISIBLE,
328                 smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
329         // No messages count.
330         assertEquals(View.GONE,
331                 smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());
332 
333         mWidth = getSizeInDp(R.dimen.required_width_for_large);
334         mHeight = getSizeInDp(R.dimen.required_height_for_large);
335         RemoteViews largeView = getPeopleTileViewHelper(tileWithAvailabilityAndNewStory).getViews();
336         View largeResult = largeView.apply(mContext, null);
337 
338         name = (TextView) largeResult.findViewById(R.id.name);
339         assertEquals(name.getText(), NAME);
340         // Has last interaction.
341         assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility());
342         // Has availability.
343         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
344         assertEquals(largeResult.findViewById(R.id.availability).getContentDescription(),
345                 mContext.getString(R.string.person_available));
346         // Shows person icon.
347         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.person_icon).getVisibility());
348         // No status.
349         assertThat((View) largeResult.findViewById(R.id.text_content)).isNull();
350     }
351 
352     @Test
testCreateRemoteViewsWithBirthdayTypeOnlyIsNotIgnored()353     public void testCreateRemoteViewsWithBirthdayTypeOnlyIsNotIgnored() {
354         PeopleSpaceTile tileWithStatusTemplate =
355                 PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(
356                         Arrays.asList(
357                                 NEW_STORY_WITH_AVAILABILITY, new ConversationStatus.Builder(
358                                         PERSON_TILE_WITHOUT_NOTIFICATION.getId(),
359                                         ACTIVITY_BIRTHDAY).build())).build();
360         RemoteViews views = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
361         View result = views.apply(mContext, null);
362 
363         TextView name = (TextView) result.findViewById(R.id.name);
364         assertEquals(name.getText(), NAME);
365         assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
366         assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
367         // Has availability.
368         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
369         // Has person icon.
370         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
371         // Has status text from backup text.
372         TextView statusContent = (TextView) result.findViewById(R.id.text_content);
373         assertEquals(View.VISIBLE, statusContent.getVisibility());
374         assertEquals(statusContent.getText(), mContext.getString(R.string.birthday_status));
375         assertThat(statusContent.getMaxLines()).isEqualTo(2);
376         assertThat(statusContent.getContentDescription().toString()).isEqualTo(
377                 mContext.getString(R.string.new_status_content_description, NAME,
378                         mContext.getString(R.string.birthday_status_content_description, NAME)));
379 
380         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
381         RemoteViews smallView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
382         View smallResult = smallView.apply(mContext, null);
383 
384         // Show icon instead of name.
385         assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
386         assertEquals(View.VISIBLE,
387                 smallResult.findViewById(R.id.predefined_icon).getVisibility());
388         assertThat(smallResult.findViewById(
389                 R.id.predefined_icon).getContentDescription().toString()).isEqualTo(
390                 mContext.getString(R.string.new_status_content_description, NAME,
391                         mContext.getString(R.string.birthday_status_content_description, NAME)));
392         // Has person icon.
393         assertEquals(View.VISIBLE,
394                 smallResult.findViewById(R.id.person_icon).getVisibility());
395         // No messages count.
396         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
397 
398         mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
399         RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
400                 tileWithStatusTemplate).getViews();
401         View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);
402 
403         // Show name over predefined icon.
404         assertEquals(View.GONE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
405         assertEquals(View.VISIBLE,
406                 smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
407         // Shows person icon.
408         assertEquals(View.VISIBLE,
409                 smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
410         // No messages count.
411         assertEquals(View.GONE,
412                 smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());
413 
414         mWidth = getSizeInDp(R.dimen.required_width_for_large);
415         mHeight = getSizeInDp(R.dimen.required_height_for_large);
416         RemoteViews largeView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
417         View largeResult = largeView.apply(mContext, null);
418 
419         name = (TextView) largeResult.findViewById(R.id.name);
420         assertEquals(name.getText(), NAME);
421         assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
422         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
423         // Has availability.
424         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
425         // Has person icon.
426         View personIcon = largeResult.findViewById(R.id.person_icon);
427         assertEquals(View.VISIBLE, personIcon.getVisibility());
428         // Has notification content.
429         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
430         assertEquals(View.VISIBLE, statusContent.getVisibility());
431         assertEquals(statusContent.getText(), mContext.getString(R.string.birthday_status));
432         assertThat(statusContent.getMaxLines()).isEqualTo(2);
433         assertThat(statusContent.getContentDescription().toString()).isEqualTo(
434                 mContext.getString(R.string.new_status_content_description, NAME,
435                         mContext.getString(R.string.birthday_status_content_description, NAME)));
436     }
437 
438     @Test
testCreateRemoteViewsWithStatusTemplate()439     public void testCreateRemoteViewsWithStatusTemplate() {
440         PeopleSpaceTile tileWithStatusTemplate =
441                 PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(
442                         Arrays.asList(GAME_STATUS,
443                                 NEW_STORY_WITH_AVAILABILITY)).build();
444         RemoteViews views = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
445         View result = views.apply(mContext, null);
446 
447         TextView name = (TextView) result.findViewById(R.id.name);
448         assertEquals(name.getText(), NAME);
449         assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
450         assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
451         assertEquals(View.GONE, result.findViewById(R.id.scrim_layout).getVisibility());
452         assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
453         // Has availability.
454         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
455         // Has person icon.
456         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
457         // Has status.
458         TextView statusContent = (TextView) result.findViewById(R.id.text_content);
459         assertEquals(statusContent.getText(), GAME_DESCRIPTION);
460         assertThat(statusContent.getMaxLines()).isEqualTo(2);
461         assertThat(statusContent.getContentDescription().toString()).isEqualTo(
462                 mContext.getString(R.string.new_status_content_description, NAME,
463                         GAME_DESCRIPTION));
464 
465         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
466         RemoteViews smallView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
467         View smallResult = smallView.apply(mContext, null);
468 
469         // Show icon instead of name.
470         assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
471         assertEquals(View.VISIBLE,
472                 smallResult.findViewById(R.id.predefined_icon).getVisibility());
473         assertThat(smallResult.findViewById(
474                 R.id.predefined_icon).getContentDescription().toString()).isEqualTo(
475                 mContext.getString(R.string.new_status_content_description, NAME,
476                         GAME_DESCRIPTION));
477         // Has person icon.
478         assertEquals(View.VISIBLE,
479                 smallResult.findViewById(R.id.person_icon).getVisibility());
480         // No messages count.
481         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
482 
483         mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
484         RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
485                 tileWithStatusTemplate).getViews();
486         View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);
487 
488         // Show name over predefined icon.
489         assertEquals(View.GONE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
490         assertEquals(View.VISIBLE,
491                 smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
492         // Shows person icon.
493         assertEquals(View.VISIBLE,
494                 smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
495         // No messages count.
496         assertEquals(View.GONE,
497                 smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());
498 
499         mWidth = getSizeInDp(R.dimen.required_width_for_large);
500         mHeight = getSizeInDp(R.dimen.required_height_for_large);
501         RemoteViews largeView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
502         View largeResult = largeView.apply(mContext, null);
503 
504         name = (TextView) largeResult.findViewById(R.id.name);
505         assertEquals(name.getText(), NAME);
506         assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
507         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
508         assertEquals(View.GONE, largeResult.findViewById(R.id.scrim_layout).getVisibility());
509         assertEquals(View.GONE, largeResult.findViewById(R.id.image).getVisibility());
510         // Has availability.
511         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
512         // Has person icon.
513         View personIcon = largeResult.findViewById(R.id.person_icon);
514         assertEquals(View.VISIBLE, personIcon.getVisibility());
515         // Has notification content.
516         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
517         assertEquals(View.VISIBLE, statusContent.getVisibility());
518         assertEquals(statusContent.getText(), GAME_DESCRIPTION);
519         assertThat(statusContent.getMaxLines()).isEqualTo(2);
520         assertThat(statusContent.getContentDescription().toString()).isEqualTo(
521                 mContext.getString(R.string.new_status_content_description, NAME,
522                         GAME_DESCRIPTION));
523     }
524 
525     @Test
testCreateRemoteViewsWithStatusTemplateWithImageOnMediumAndLarge()526     public void testCreateRemoteViewsWithStatusTemplateWithImageOnMediumAndLarge() {
527         PeopleSpaceTile tileWithIconInStatusTemplate =
528                 PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(
529                         Arrays.asList(new ConversationStatus.Builder(PERSON_TILE.getId(),
530                                 ACTIVITY_ANNIVERSARY).setDescription("Anniversary").setAvailability(
531                                 AVAILABILITY_AVAILABLE).setIcon(mIcon).build())).build();
532         RemoteViews views = getPeopleTileViewHelper(
533                 tileWithIconInStatusTemplate).getViews();
534         View result = views.apply(mContext, null);
535 
536         assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
537         assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
538         assertEquals(View.VISIBLE, result.findViewById(R.id.scrim_layout).getVisibility());
539         assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
540         // Has availability.
541         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
542         // Has person icon.
543         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
544         // Has status.
545         TextView statusContent = (TextView) result.findViewById(R.id.name);
546         assertEquals(statusContent.getText(), "Anniversary");
547         // Since the image is showing which removes name, we need to manually include the name.
548         assertThat(statusContent.getContentDescription().toString()).isEqualTo(
549                 mContext.getString(R.string.new_status_content_description, NAME, "Anniversary"));
550         assertThat(statusContent.getMaxLines()).isEqualTo(1);
551 
552         mWidth = getSizeInDp(R.dimen.required_width_for_large);
553         mHeight = getSizeInDp(R.dimen.required_height_for_large);
554         RemoteViews largeView = getPeopleTileViewHelper(tileWithIconInStatusTemplate).getViews();
555         View largeResult = largeView.apply(mContext, null);
556 
557         assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
558         assertEquals(View.GONE, largeResult.findViewById(R.id.name).getVisibility());
559         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
560         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.scrim_layout).getVisibility());
561         assertEquals(View.GONE, largeResult.findViewById(R.id.image).getVisibility());
562         // Has availability.
563         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
564         // Has person icon.
565         View personIcon = largeResult.findViewById(R.id.person_icon);
566         assertEquals(View.VISIBLE, personIcon.getVisibility());
567         // Has status content.
568         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
569         assertEquals(View.VISIBLE, statusContent.getVisibility());
570         assertEquals(statusContent.getText(), "Anniversary");
571         // Since the image is showing which removes name, we need to manually include the name.
572         assertThat(statusContent.getContentDescription().toString()).isEqualTo(
573                 mContext.getString(R.string.new_status_content_description, NAME, "Anniversary"));
574         assertThat(statusContent.getMaxLines()).isEqualTo(2);
575     }
576 
577     @Test
testCreateRemoteViewsWithPackageSuspended()578     public void testCreateRemoteViewsWithPackageSuspended() {
579         PeopleSpaceTile tile = PERSON_TILE.toBuilder()
580                 .setIsPackageSuspended(true)
581                 .build();
582         RemoteViews views = getPeopleTileViewHelper(tile).getViews();
583         View result = views.apply(mContext, null);
584 
585         assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
586     }
587 
588     @Test
testCreateRemoteViewsWithNotificationContent()589     public void testCreateRemoteViewsWithNotificationContent() throws Exception {
590         PeopleTileViewHelper helper = spy(getPeopleTileViewHelper(PERSON_TILE));
591         doReturn(new BitmapDrawable()).when(helper).resolveImage(any(), any());
592         RemoteViews views = helper.getViews();
593         View result = views.apply(mContext, null);
594 
595         assertEquals(View.VISIBLE, result.findViewById(R.id.image).getVisibility());
596     }
597 
598     @Test
testCreateRemoteViewsWithInvalidNotificationContent()599     public void testCreateRemoteViewsWithInvalidNotificationContent() throws Exception {
600         PeopleTileViewHelper helper = spy(getPeopleTileViewHelper(PERSON_TILE));
601         doThrow(SecurityException.class).when(helper).resolveImage(any(), any());
602         RemoteViews views = helper.getViews();
603         View result = views.apply(mContext, null);
604 
605         assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
606         assertEquals(View.VISIBLE, result.findViewById(R.id.text_content).getVisibility());
607     }
608 
609     @Test
testCreateRemoteViewsWithUserQuieted()610     public void testCreateRemoteViewsWithUserQuieted() {
611         PeopleSpaceTile tile = PERSON_TILE.toBuilder()
612                 .setIsUserQuieted(true)
613                 .build();
614         RemoteViews views = getPeopleTileViewHelper(tile).getViews();
615         View result = views.apply(mContext, null);
616 
617         assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_work_profile_quiet_layout);
618     }
619 
620     @Test
testCreateRemoteViewsWithDndBlocking()621     public void testCreateRemoteViewsWithDndBlocking() {
622         PeopleSpaceTile tileWithDndBlocking = PERSON_TILE.toBuilder()
623                 .setNotificationPolicyState(BLOCK_CONVERSATIONS)
624                 .build();
625         RemoteViews views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
626         View result = views.apply(mContext, null);
627 
628         assertResourcesEqual(
629                 result.getSourceLayoutResId(),
630                 R.layout.people_tile_with_suppression_detail_content_horizontal);
631 
632         tileWithDndBlocking = PERSON_TILE.toBuilder()
633                 .setNotificationPolicyState(BLOCK_CONVERSATIONS)
634                 .setCanBypassDnd(true)
635                 .build();
636         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
637         result = views.apply(mContext, null);
638 
639         assertResourcesNotEqual(
640                 result.getSourceLayoutResId(),
641                 R.layout.people_tile_with_suppression_detail_content_horizontal);
642 
643         tileWithDndBlocking = PERSON_TILE.toBuilder()
644                 .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS)
645                 .build();
646         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
647         result = views.apply(mContext, null);
648 
649         assertResourcesEqual(
650                 result.getSourceLayoutResId(),
651                 R.layout.people_tile_with_suppression_detail_content_horizontal);
652 
653         tileWithDndBlocking = PERSON_TILE.toBuilder()
654                 .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS)
655                 .setIsImportantConversation(true)
656                 .build();
657         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
658         result = views.apply(mContext, null);
659 
660         assertResourcesNotEqual(
661                 result.getSourceLayoutResId(),
662                 R.layout.people_tile_with_suppression_detail_content_horizontal);
663 
664         tileWithDndBlocking = PERSON_TILE.toBuilder()
665                 .setNotificationPolicyState(SHOW_STARRED_CONTACTS)
666                 .setContactAffinity(VALID_CONTACT)
667                 .build();
668         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
669         result = views.apply(mContext, null);
670 
671         assertResourcesEqual(
672                 result.getSourceLayoutResId(),
673                 R.layout.people_tile_with_suppression_detail_content_horizontal);
674 
675         tileWithDndBlocking = PERSON_TILE.toBuilder()
676                 .setNotificationPolicyState(SHOW_STARRED_CONTACTS)
677                 .setContactAffinity(STARRED_CONTACT)
678                 .build();
679         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
680         result = views.apply(mContext, null);
681 
682         assertResourcesNotEqual(
683                 result.getSourceLayoutResId(),
684                 R.layout.people_tile_with_suppression_detail_content_horizontal);
685 
686         tileWithDndBlocking = PERSON_TILE.toBuilder()
687                 .setNotificationPolicyState(SHOW_CONTACTS)
688                 .setContactAffinity(STARRED_CONTACT)
689                 .build();
690         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
691         result = views.apply(mContext, null);
692 
693         assertResourcesNotEqual(
694                 result.getSourceLayoutResId(),
695                 R.layout.people_tile_with_suppression_detail_content_horizontal);
696 
697         tileWithDndBlocking = PERSON_TILE.toBuilder()
698                 .setNotificationPolicyState(SHOW_CONTACTS)
699                 .setContactAffinity(VALID_CONTACT)
700                 .build();
701         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
702         result = views.apply(mContext, null);
703 
704         assertResourcesNotEqual(
705                 result.getSourceLayoutResId(),
706                 R.layout.people_tile_with_suppression_detail_content_horizontal);
707 
708         tileWithDndBlocking = PERSON_TILE.toBuilder()
709                 .setNotificationPolicyState(SHOW_CONTACTS)
710                 .build();
711         views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
712         result = views.apply(mContext, null);
713 
714         assertResourcesEqual(
715                 result.getSourceLayoutResId(),
716                 R.layout.people_tile_with_suppression_detail_content_horizontal);
717         assertThat(result.<TextView>findViewById(R.id.text_content).getText().toString())
718                 .isEqualTo(mContext.getString(R.string.paused_by_dnd));
719     }
720 
721     @Test
testCreateRemoteViewsWithMissedCallNotification()722     public void testCreateRemoteViewsWithMissedCallNotification() {
723         PeopleSpaceTile tileWithMissedCallNotification = PERSON_TILE.toBuilder()
724                 .setNotificationDataUri(null)
725                 .setNotificationCategory(CATEGORY_MISSED_CALL)
726                 .setNotificationContent(MISSED_CALL)
727                 .build();
728         RemoteViews views = getPeopleTileViewHelper(tileWithMissedCallNotification).getViews();
729         View result = views.apply(mContext, null);
730 
731         TextView name = (TextView) result.findViewById(R.id.name);
732         assertEquals(name.getText(), NAME);
733         assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
734         assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
735         // Has availability.
736         assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
737         // Has person icon.
738         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
739         // Has missed call notification content.
740         TextView statusContent = (TextView) result.findViewById(R.id.text_content);
741         assertEquals(View.VISIBLE, statusContent.getVisibility());
742         assertEquals(statusContent.getText(), MISSED_CALL);
743         assertEquals(statusContent.getContentDescription(), mContext.getString(
744                 R.string.new_notification_text_content_description, NAME, MISSED_CALL));
745         assertThat(statusContent.getMaxLines()).isEqualTo(2);
746 
747         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
748         RemoteViews smallView = getPeopleTileViewHelper(
749                 tileWithMissedCallNotification).getViews();
750         View smallResult = smallView.apply(mContext, null);
751 
752         // Show icon instead of name.
753         assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
754         assertEquals(View.VISIBLE,
755                 smallResult.findViewById(R.id.predefined_icon).getVisibility());
756         assertEquals(smallResult.findViewById(R.id.predefined_icon).getContentDescription(),
757                 mContext.getString(
758                         R.string.new_notification_text_content_description, NAME, MISSED_CALL));
759         // Has person icon.
760         assertEquals(View.VISIBLE, smallResult.findViewById(R.id.person_icon).getVisibility());
761         // No messages count.
762         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
763 
764         mWidth = getSizeInDp(R.dimen.required_width_for_large);
765         mHeight = getSizeInDp(R.dimen.required_height_for_large);
766         RemoteViews largeView = getPeopleTileViewHelper(tileWithMissedCallNotification).getViews();
767         View largeResult = largeView.apply(mContext, null);
768 
769         name = (TextView) largeResult.findViewById(R.id.name);
770         assertEquals(name.getText(), NAME);
771         assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
772         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
773         // Has availability.
774         assertEquals(View.GONE, largeResult.findViewById(R.id.availability).getVisibility());
775         // Has person icon.
776         View personIcon = largeResult.findViewById(R.id.person_icon);
777         assertEquals(View.VISIBLE, personIcon.getVisibility());
778         // Has notification content.
779         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
780         assertEquals(View.VISIBLE, statusContent.getVisibility());
781         assertEquals(statusContent.getText(), MISSED_CALL);
782         assertEquals(statusContent.getContentDescription(), mContext.getString(
783                 R.string.new_notification_text_content_description, NAME, MISSED_CALL));
784         assertThat(statusContent.getMaxLines()).isEqualTo(2);
785     }
786 
787     @Test
testCreateRemoteViewsWithNotificationTemplate()788     public void testCreateRemoteViewsWithNotificationTemplate() {
789         PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
790                 .setNotificationDataUri(null)
791                 .setStatuses(Arrays.asList(GAME_STATUS,
792                         NEW_STORY_WITH_AVAILABILITY)).build();
793         RemoteViews views = getPeopleTileViewHelper(
794                 tileWithStatusAndNotification).getViews();
795         View result = views.apply(mContext, null);
796 
797         TextView name = (TextView) result.findViewById(R.id.name);
798         assertEquals(name.getText(), NAME);
799         assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
800         assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
801         assertEquals(View.GONE, result.findViewById(R.id.scrim_layout).getVisibility());
802         // Has availability.
803         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
804         // Has person icon.
805         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
806         // Has notification content.
807         TextView statusContent = (TextView) result.findViewById(R.id.text_content);
808         assertEquals(View.VISIBLE, statusContent.getVisibility());
809         assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
810         assertEquals(statusContent.getContentDescription(), mContext.getString(
811                 R.string.new_notification_text_content_description, NAME, NOTIFICATION_CONTENT));
812         assertThat(statusContent.getMaxLines()).isEqualTo(2);
813 
814         // Has a single message, no count shown.
815         assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());
816 
817         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
818         RemoteViews smallView = getPeopleTileViewHelper(
819                 tileWithStatusAndNotification).getViews();
820         View smallResult = smallView.apply(mContext, null);
821 
822         // Show icon instead of name.
823         assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
824         assertEquals(View.VISIBLE,
825                 smallResult.findViewById(R.id.predefined_icon).getVisibility());
826         assertEquals(smallResult.findViewById(R.id.predefined_icon).getContentDescription(),
827                 mContext.getString(R.string.new_notification_text_content_description, NAME,
828                         NOTIFICATION_CONTENT));
829         // Has person icon.
830         assertEquals(View.VISIBLE,
831                 smallResult.findViewById(R.id.person_icon).getVisibility());
832 
833         // Has a single message, no count shown.
834         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
835 
836         mWidth = getSizeInDp(R.dimen.required_width_for_large);
837         mHeight = getSizeInDp(R.dimen.required_height_for_large);
838         RemoteViews largeView = getPeopleTileViewHelper(
839                 tileWithStatusAndNotification).getViews();
840         View largeResult = largeView.apply(mContext, null);
841 
842         name = (TextView) largeResult.findViewById(R.id.name);
843         assertEquals(name.getText(), NAME);
844         assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
845         assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
846         assertEquals(largeResult.findViewById(R.id.scrim_layout), null);
847         // Has availability.
848         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
849         // Has person icon.
850         View personIcon = largeResult.findViewById(R.id.person_icon);
851         assertEquals(View.VISIBLE, personIcon.getVisibility());
852         // Has notification content.
853         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
854         assertEquals(View.VISIBLE, statusContent.getVisibility());
855         assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
856         assertEquals(statusContent.getContentDescription(), mContext.getString(
857                 R.string.new_notification_text_content_description, NAME, NOTIFICATION_CONTENT));
858         assertThat(statusContent.getMaxLines()).isEqualTo(2);
859         // Has a single message, no count shown.
860         assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility());
861 
862     }
863 
864     @Test
testCreateRemoteViewsWithNotificationWithSenderTemplate()865     public void testCreateRemoteViewsWithNotificationWithSenderTemplate() {
866         PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE_WITH_SENDER.toBuilder()
867                 .setNotificationDataUri(null)
868                 .setStatuses(Arrays.asList(GAME_STATUS,
869                         NEW_STORY_WITH_AVAILABILITY)).build();
870         RemoteViews views = getPeopleTileViewHelper(
871                 tileWithStatusAndNotification).getViews();
872         View result = views.apply(mContext, null);
873 
874         TextView name = (TextView) result.findViewById(R.id.name);
875         assertEquals(name.getText(), NAME);
876         TextView subtext = (TextView) result.findViewById(R.id.subtext);
877         assertEquals(View.VISIBLE, result.findViewById(R.id.subtext).getVisibility());
878         assertEquals(subtext.getText(), SENDER);
879         assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
880         // Has availability.
881         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
882         // Has person icon.
883         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
884         // Has notification content.
885         TextView statusContent = (TextView) result.findViewById(R.id.text_content);
886         assertEquals(View.VISIBLE, statusContent.getVisibility());
887         assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
888         assertEquals(statusContent.getContentDescription(), mContext.getString(
889                 R.string.new_notification_text_content_description, SENDER, NOTIFICATION_CONTENT));
890 
891         // Subtract one from lines because sender is included.
892         assertThat(statusContent.getMaxLines()).isEqualTo(1);
893 
894         // Has a single message, no count shown.
895         assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());
896 
897         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
898         RemoteViews smallView = getPeopleTileViewHelper(
899                 tileWithStatusAndNotification).getViews();
900         View smallResult = smallView.apply(mContext, null);
901 
902         // Show icon instead of name.
903         assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
904         assertEquals(View.VISIBLE,
905                 smallResult.findViewById(R.id.predefined_icon).getVisibility());
906         assertEquals(smallResult.findViewById(R.id.predefined_icon).getContentDescription(),
907                 mContext.getString(
908                         R.string.new_notification_text_content_description, SENDER,
909                         NOTIFICATION_CONTENT));
910         // Has person icon.
911         assertEquals(View.VISIBLE,
912                 smallResult.findViewById(R.id.person_icon).getVisibility());
913 
914         // Has a single message, no count shown.
915         assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());
916 
917         mWidth = getSizeInDp(R.dimen.required_width_for_large);
918         mHeight = getSizeInDp(R.dimen.required_height_for_large);
919         RemoteViews largeView = getPeopleTileViewHelper(
920                 tileWithStatusAndNotification).getViews();
921         View largeResult = largeView.apply(mContext, null);
922 
923         name = (TextView) largeResult.findViewById(R.id.name);
924         assertEquals(name.getText(), NAME);
925         subtext = (TextView) largeResult.findViewById(R.id.subtext);
926         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.subtext).getVisibility());
927         assertEquals(subtext.getText(), SENDER);
928         assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
929         // Has availability.
930         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
931         // Has person icon.
932         View personIcon = largeResult.findViewById(R.id.person_icon);
933         assertEquals(View.VISIBLE, personIcon.getVisibility());
934         // Has notification content.
935         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
936         assertEquals(View.VISIBLE, statusContent.getVisibility());
937         assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
938         assertEquals(statusContent.getContentDescription(), mContext.getString(
939                 R.string.new_notification_text_content_description, SENDER, NOTIFICATION_CONTENT));
940 
941         // Subtract one from lines because sender is included.
942         assertThat(statusContent.getMaxLines()).isEqualTo(1);
943 
944         // Has a single message, no count shown.
945         assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility());
946 
947     }
948 
949     @Test
testCreateRemoteViewsWithNotificationTemplateTwoMessages()950     public void testCreateRemoteViewsWithNotificationTemplateTwoMessages() {
951         PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
952                 .setNotificationDataUri(null)
953                 .setStatuses(Arrays.asList(GAME_STATUS,
954                         NEW_STORY_WITH_AVAILABILITY))
955                 .setMessagesCount(2).build();
956         RemoteViews views = getPeopleTileViewHelper(
957                 tileWithStatusAndNotification).getViews();
958         View result = views.apply(mContext, null);
959 
960         TextView name = (TextView) result.findViewById(R.id.name);
961         assertEquals(name.getText(), NAME);
962         assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
963         assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
964         // Has availability.
965         assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
966         // Has person icon.
967         assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
968         // Has notification content.
969         TextView statusContent = (TextView) result.findViewById(R.id.text_content);
970         assertEquals(View.VISIBLE, statusContent.getVisibility());
971         assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
972         assertThat(statusContent.getMaxLines()).isEqualTo(2);
973 
974         // Has two messages, show count.
975         assertEquals(View.VISIBLE, result.findViewById(R.id.messages_count).getVisibility());
976 
977         mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
978         RemoteViews smallView = getPeopleTileViewHelper(
979                 tileWithStatusAndNotification).getViews();
980         View smallResult = smallView.apply(mContext, null);
981 
982         // Show icon instead of name.
983         assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
984         assertEquals(View.GONE,
985                 smallResult.findViewById(R.id.predefined_icon).getVisibility());
986         // Has person icon.
987         assertEquals(View.VISIBLE,
988                 smallResult.findViewById(R.id.person_icon).getVisibility());
989 
990         // Has two messages, show count.
991         assertEquals(View.VISIBLE, smallResult.findViewById(R.id.messages_count).getVisibility());
992 
993         mWidth = getSizeInDp(R.dimen.required_width_for_large);
994         mHeight = getSizeInDp(R.dimen.required_height_for_large);
995         RemoteViews largeView = getPeopleTileViewHelper(
996                 tileWithStatusAndNotification).getViews();
997         View largeResult = largeView.apply(mContext, null);
998 
999         name = (TextView) largeResult.findViewById(R.id.name);
1000         assertEquals(name.getText(), NAME);
1001         assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
1002         assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
1003         // Has availability.
1004         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
1005         // Has person icon.
1006         View personIcon = largeResult.findViewById(R.id.person_icon);
1007         assertEquals(View.VISIBLE, personIcon.getVisibility());
1008         // Has notification content.
1009         statusContent = (TextView) largeResult.findViewById(R.id.text_content);
1010         assertEquals(View.VISIBLE, statusContent.getVisibility());
1011         assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
1012         assertThat(statusContent.getMaxLines()).isEqualTo(2);
1013 
1014         // Has two messages, show count.
1015         assertEquals(View.VISIBLE, largeResult.findViewById(R.id.messages_count).getVisibility());
1016     }
1017 
1018 
1019     @Test
testGetDoublePunctuationNoPunctuation()1020     public void testGetDoublePunctuationNoPunctuation() {
1021         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test");
1022 
1023         assertThat(backgroundText).isNull();
1024     }
1025 
1026     @Test
testGetDoublePunctuationSingleExclamation()1027     public void testGetDoublePunctuationSingleExclamation() {
1028         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test!");
1029 
1030         assertThat(backgroundText).isNull();
1031     }
1032 
1033     @Test
testGetDoublePunctuationSingleQuestion()1034     public void testGetDoublePunctuationSingleQuestion() {
1035         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("?test");
1036 
1037         assertThat(backgroundText).isNull();
1038     }
1039 
1040     @Test
testGetDoublePunctuationSeparatedMarks()1041     public void testGetDoublePunctuationSeparatedMarks() {
1042         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test! right!");
1043 
1044         assertThat(backgroundText).isNull();
1045     }
1046 
1047     @Test
testGetDoublePunctuationDoubleExclamation()1048     public void testGetDoublePunctuationDoubleExclamation() {
1049         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("!!test");
1050 
1051         assertThat(backgroundText).isEqualTo("!");
1052     }
1053 
1054     @Test
testGetDoublePunctuationDoubleQuestion()1055     public void testGetDoublePunctuationDoubleQuestion() {
1056         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test??");
1057 
1058         assertThat(backgroundText).isEqualTo("?");
1059     }
1060 
1061     @Test
testGetDoublePunctuationMixed()1062     public void testGetDoublePunctuationMixed() {
1063         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test?!");
1064 
1065         assertThat(backgroundText).isEqualTo("!?");
1066     }
1067 
1068     @Test
testGetDoublePunctuationMixedInTheMiddle()1069     public void testGetDoublePunctuationMixedInTheMiddle() {
1070         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
1071                 "test!? in the middle");
1072 
1073         assertThat(backgroundText).isEqualTo("!?");
1074     }
1075 
1076     @Test
testGetDoublePunctuationMixedDifferentOrder()1077     public void testGetDoublePunctuationMixedDifferentOrder() {
1078         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
1079                 "test!? in the middle");
1080 
1081         assertThat(backgroundText).isEqualTo("!?");
1082     }
1083 
1084     @Test
testGetDoublePunctuationMultiple()1085     public void testGetDoublePunctuationMultiple() {
1086         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
1087                 "test!?!!? in the middle");
1088 
1089         assertThat(backgroundText).isEqualTo("!?");
1090     }
1091 
1092     @Test
testGetDoublePunctuationQuestionFirst()1093     public void testGetDoublePunctuationQuestionFirst() {
1094         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
1095                 "test?? in the middle!!");
1096 
1097         assertThat(backgroundText).isEqualTo("?");
1098     }
1099 
1100     @Test
testGetDoublePunctuationExclamationFirst()1101     public void testGetDoublePunctuationExclamationFirst() {
1102         CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
1103                 "test!! in the middle??");
1104 
1105         assertThat(backgroundText).isEqualTo("!");
1106     }
1107 
1108     @Test
testGetDoubleEmojisNoEmojis()1109     public void testGetDoubleEmojisNoEmojis() {
1110         CharSequence backgroundText = mPeopleTileViewHelper
1111                 .getDoubleEmoji("This string has no emojis.");
1112         assertThat(backgroundText).isNull();
1113     }
1114 
1115     @Test
testGetDoubleEmojisSingleEmoji()1116     public void testGetDoubleEmojisSingleEmoji() {
1117         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1118                 "This string has one emoji " + EMOJI_JOY + " in the middle.");
1119         assertThat(backgroundText).isNull();
1120     }
1121 
1122     @Test
testGetDoubleEmojisSingleEmojiThenTwoEmojis()1123     public void testGetDoubleEmojisSingleEmojiThenTwoEmojis() {
1124         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1125                 "This string has one emoji " + EMOJI_JOY + " in the middle, then two "
1126                         + EMOJI_BEAR + EMOJI_BEAR);
1127         assertEquals(backgroundText, EMOJI_BEAR);
1128     }
1129 
1130     @Test
testGetDoubleEmojisTwoEmojisWithModifier()1131     public void testGetDoubleEmojisTwoEmojisWithModifier() {
1132         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1133                 "Yes! " + EMOJI_THUMBS_UP_BROWN_SKIN + EMOJI_THUMBS_UP_BROWN_SKIN + " Sure.");
1134         assertEquals(backgroundText, EMOJI_THUMBS_UP_BROWN_SKIN);
1135     }
1136 
1137     @Test
testGetDoubleEmojisTwoFlagEmojis()1138     public void testGetDoubleEmojisTwoFlagEmojis() {
1139         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1140                 "Let's travel to " + EMOJI_BR_FLAG + EMOJI_BR_FLAG + " next year.");
1141         assertEquals(backgroundText, EMOJI_BR_FLAG);
1142     }
1143 
1144     @Test
testGetDoubleEmojiTwoBears()1145     public void testGetDoubleEmojiTwoBears() {
1146         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1147                 EMOJI_BEAR.toString() + EMOJI_BEAR.toString() + "bears!");
1148         assertEquals(backgroundText, EMOJI_BEAR);
1149     }
1150 
1151     @Test
testGetDoubleEmojiTwoEmojisTwice()1152     public void testGetDoubleEmojiTwoEmojisTwice() {
1153         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1154                 "Two sets of two emojis: " + EMOJI_FAMILY + EMOJI_FAMILY + EMOJI_BEAR + EMOJI_BEAR);
1155         assertEquals(backgroundText, EMOJI_FAMILY);
1156     }
1157 
1158     @Test
testGetDoubleEmojiTwoEmojisSeparated()1159     public void testGetDoubleEmojiTwoEmojisSeparated() {
1160         CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
1161                 "Two emojis " + EMOJI_BEAR + " separated " + EMOJI_BEAR + ".");
1162         assertThat(backgroundText).isNull();
1163     }
1164 
getSizeInDp(int dimenResourceId)1165     private int getSizeInDp(int dimenResourceId) {
1166         return (int) (mContext.getResources().getDimension(dimenResourceId)
1167                 / mContext.getResources().getDisplayMetrics().density);
1168     }
1169 
getPeopleTileViewHelper( PeopleSpaceTile tile)1170     private PeopleTileViewHelper getPeopleTileViewHelper(
1171             PeopleSpaceTile tile) {
1172         return new PeopleTileViewHelper(mContext, tile, 0, mWidth, mHeight,
1173                 new PeopleTileKey(tile.getId(), 0, tile.getPackageName()));
1174     }
1175 
assertResourcesEqual(int expected, int actual)1176     private void assertResourcesEqual(int expected, int actual) {
1177         assertThat(getResourceName(actual)).isEqualTo(getResourceName(expected));
1178     }
1179 
assertResourcesNotEqual(int expected, int actual)1180     private void assertResourcesNotEqual(int expected, int actual) {
1181         assertThat(getResourceName(actual)).isNotEqualTo(getResourceName(expected));
1182     }
1183 
getResourceName(int resId)1184     private String getResourceName(int resId) {
1185         Resources resources = mContext.getResources();
1186         try {
1187             return resources.getResourceEntryName(resId);
1188         } catch (Resources.NotFoundException e) {
1189             return String.valueOf(resId);
1190         }
1191     }
1192 }
1193