/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.people;

import static android.app.Notification.CATEGORY_MISSED_CALL;
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_NEW_STORY;
import static android.app.people.ConversationStatus.AVAILABILITY_AVAILABLE;
import static android.app.people.PeopleSpaceTile.BLOCK_CONVERSATIONS;
import static android.app.people.PeopleSpaceTile.SHOW_CONTACTS;
import static android.app.people.PeopleSpaceTile.SHOW_IMPORTANT_CONVERSATIONS;
import static android.app.people.PeopleSpaceTile.SHOW_STARRED_CONTACTS;

import static com.android.systemui.people.PeopleSpaceUtils.STARRED_CONTACT;
import static com.android.systemui.people.PeopleSpaceUtils.VALID_CONTACT;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;

import android.app.people.ConversationStatus;
import android.app.people.PeopleSpaceTile;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.UserHandle;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.TextView;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.widget.PeopleTileKey;
import com.android.systemui.res.R;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.time.Duration;
import java.util.Arrays;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class PeopleTileViewHelperTest extends SysuiTestCase {

    private static final String SHORTCUT_ID_1 = "101";
    private static final String NOTIFICATION_KEY = "notification_key";
    private static final String NOTIFICATION_CONTENT = "notification_content";
    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 CharSequence MISSED_CALL = "Custom missed call message";
    private static final String NAME = "username";
    private static final UserHandle USER = new UserHandle(0);
    private static final String SENDER = "sender";

    private static final CharSequence EMOJI_BR_FLAG = "\ud83c\udde7\ud83c\uddf7";
    private static final CharSequence EMOJI_BEAR = "\ud83d\udc3b";
    private static final CharSequence EMOJI_THUMBS_UP_BROWN_SKIN = "\uD83D\uDC4D\uD83C\uDFFD";
    private static final CharSequence EMOJI_JOY = "\uD83D\uDE02";
    private static final CharSequence EMOJI_FAMILY =
            "\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d\udc67";

    private static final PeopleSpaceTile PERSON_TILE_WITHOUT_NOTIFICATION =
            new PeopleSpaceTile
                    .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
                    .setLastInteractionTimestamp(0L)
                    .setUserHandle(USER)
                    .build();
    private static final PeopleSpaceTile PERSON_TILE =
            new PeopleSpaceTile
                    .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
                    .setLastInteractionTimestamp(123L)
                    .setNotificationKey(NOTIFICATION_KEY)
                    .setNotificationContent(NOTIFICATION_CONTENT)
                    .setNotificationDataUri(URI)
                    .setUserHandle(USER)
                    .build();
    private static final PeopleSpaceTile PERSON_TILE_WITH_SENDER =
            new PeopleSpaceTile
                    .Builder(SHORTCUT_ID_1, NAME, ICON, new Intent())
                    .setLastInteractionTimestamp(123L)
                    .setNotificationKey(NOTIFICATION_KEY)
                    .setNotificationContent(NOTIFICATION_CONTENT)
                    .setNotificationSender(SENDER)
                    .setUserHandle(USER)
                    .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();

    @Mock
    private Icon mIcon;

    @Mock
    private Context mMockContext;
    @Mock
    private PackageManager mPackageManager;

    private int mWidth;
    private int mHeight;
    private PeopleTileViewHelper mPeopleTileViewHelper;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        when(mMockContext.getString(R.string.birthday_status)).thenReturn(
                mContext.getString(R.string.birthday_status));
        when(mMockContext.getPackageManager()).thenReturn(mPackageManager);
        when(mMockContext.getString(R.string.over_two_weeks_timestamp)).thenReturn(
                mContext.getString(R.string.over_two_weeks_timestamp));
        Configuration configuration = mock(Configuration.class);
        DisplayMetrics displayMetrics = mock(DisplayMetrics.class);
        Resources resources = mock(Resources.class);
        when(mMockContext.getResources()).thenReturn(resources);
        when(resources.getConfiguration()).thenReturn(configuration);
        when(resources.getDisplayMetrics()).thenReturn(displayMetrics);
        TextView textView = mock(TextView.class);
        when(textView.getLineHeight()).thenReturn(16);
        when(mPackageManager.getApplicationIcon(anyString())).thenReturn(null);

        mWidth = getSizeInDp(R.dimen.default_width);
        mHeight = getSizeInDp(R.dimen.default_height);
        mPeopleTileViewHelper = getPeopleTileViewHelper(PERSON_TILE);
    }

    @Test
    public void testCreateRemoteViewsWithLastInteractionTimeUnderOneDayHidden() {
        RemoteViews views = getPeopleTileViewHelper(PERSON_TILE_WITHOUT_NOTIFICATION).getViews();
        View result = views.apply(mContext, null);

        // Not showing last interaction.
        assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(
                PERSON_TILE_WITHOUT_NOTIFICATION).getViews();
        View largeResult = largeView.apply(mContext, null);

        // Not showing last interaction.
        assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility());
    }

    @Test
    public void testLastInteractionTime() {
        long now = System.currentTimeMillis();
        long fiveDaysAgo = now - Duration.ofDays(5).toMillis();
        String lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
                fiveDaysAgo);
        assertThat(lastInteractionString).isEqualTo("5 days ago");

        long lessThanOneDayAgo = now - Duration.ofHours(20).toMillis();
        lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
                lessThanOneDayAgo);
        assertThat(lastInteractionString).isNull();

        long overOneWeekAgo = now - Duration.ofDays(8).toMillis();
        lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
                overOneWeekAgo);
        assertThat(lastInteractionString).isEqualTo("Over 1 week ago");

        long overTwoWeeksAgo = now - Duration.ofDays(15).toMillis();
        lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
                overTwoWeeksAgo);
        assertThat(lastInteractionString).isEqualTo("Over 2 weeks ago");
    }

    @Test
    public void testCreateRemoteViewsWithLastInteractionTime() {
        PeopleSpaceTile tileWithLastInteraction =
                PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setLastInteractionTimestamp(
                        123445L).build();
        RemoteViews views = getPeopleTileViewHelper(tileWithLastInteraction).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        // Has last interaction.
        assertEquals(View.VISIBLE, result.findViewById(R.id.last_interaction).getVisibility());
        TextView lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
        assertEquals(lastInteraction.getText(), "Over 2 weeks ago");
        // No availability.
        assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // No status.
        assertThat((View) result.findViewById(R.id.text_content)).isNull();

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(tileWithLastInteraction).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show name over predefined icon.
        assertEquals(View.VISIBLE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.GONE, smallResult.findViewById(R.id.predefined_icon).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE, smallResult.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
        RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
                tileWithLastInteraction).getViews();
        View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);

        // Show name over predefined icon.
        assertEquals(View.VISIBLE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
        assertEquals(View.GONE,
                smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE,
                smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE,
                smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(
                tileWithLastInteraction).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        // Has last interaction.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.last_interaction).getVisibility());
        lastInteraction = (TextView) result.findViewById(R.id.last_interaction);
        assertEquals(lastInteraction.getText(), "Over 2 weeks ago");
        // No availability.
        assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // No status.
        assertThat((View) result.findViewById(R.id.text_content)).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 = getPeopleTileViewHelper(tileWithAvailabilityAndNewStory).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        // Has last interaction over status.
        assertEquals(View.GONE, result.findViewById(R.id.last_interaction).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        assertEquals(result.findViewById(R.id.availability).getContentDescription(),
                mContext.getString(R.string.person_available));
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // No status.
        assertThat((View) result.findViewById(R.id.text_content)).isNull();

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(tileWithAvailabilityAndNewStory).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show name rather than game type.
        assertEquals(View.VISIBLE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.GONE, smallResult.findViewById(R.id.predefined_icon).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
        RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
                tileWithAvailabilityAndNewStory).getViews();
        View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);

        // Show name over predefined icon.
        assertEquals(View.VISIBLE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
        assertEquals(View.GONE,
                smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE,
                smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE,
                smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(tileWithAvailabilityAndNewStory).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        // Has last interaction.
        assertEquals(View.GONE, largeResult.findViewById(R.id.last_interaction).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        assertEquals(largeResult.findViewById(R.id.availability).getContentDescription(),
                mContext.getString(R.string.person_available));
        // Shows person icon.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.person_icon).getVisibility());
        // No status.
        assertThat((View) largeResult.findViewById(R.id.text_content)).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 = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has status text from backup text.
        TextView statusContent = (TextView) result.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), mContext.getString(R.string.birthday_status));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
        assertThat(statusContent.getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME,
                        mContext.getString(R.string.birthday_status_content_description, NAME)));

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show icon instead of name.
        assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.predefined_icon).getVisibility());
        assertThat(smallResult.findViewById(
                R.id.predefined_icon).getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME,
                        mContext.getString(R.string.birthday_status_content_description, NAME)));
        // Has person icon.
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
        RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
                tileWithStatusTemplate).getViews();
        View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);

        // Show name over predefined icon.
        assertEquals(View.GONE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE,
                smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE,
                smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has notification content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), mContext.getString(R.string.birthday_status));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
        assertThat(statusContent.getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME,
                        mContext.getString(R.string.birthday_status_content_description, NAME)));
    }

    @Test
    public void testCreateRemoteViewsWithStatusTemplate() {
        PeopleSpaceTile tileWithStatusTemplate =
                PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(
                        Arrays.asList(GAME_STATUS,
                                NEW_STORY_WITH_AVAILABILITY)).build();
        RemoteViews views = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(View.GONE, result.findViewById(R.id.scrim_layout).getVisibility());
        assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has status.
        TextView statusContent = (TextView) result.findViewById(R.id.text_content);
        assertEquals(statusContent.getText(), GAME_DESCRIPTION);
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
        assertThat(statusContent.getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME,
                        GAME_DESCRIPTION));

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show icon instead of name.
        assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.predefined_icon).getVisibility());
        assertThat(smallResult.findViewById(
                R.id.predefined_icon).getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME,
                        GAME_DESCRIPTION));
        // Has person icon.
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mHeight = getSizeInDp(R.dimen.required_height_for_medium) - 1;
        RemoteViews smallViewHorizontal = getPeopleTileViewHelper(
                tileWithStatusTemplate).getViews();
        View smallResultHorizontal = smallViewHorizontal.apply(mContext, null);

        // Show name over predefined icon.
        assertEquals(View.GONE, smallResultHorizontal.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResultHorizontal.findViewById(R.id.predefined_icon).getVisibility());
        // Shows person icon.
        assertEquals(View.VISIBLE,
                smallResultHorizontal.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE,
                smallResultHorizontal.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(tileWithStatusTemplate).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(View.GONE, largeResult.findViewById(R.id.scrim_layout).getVisibility());
        assertEquals(View.GONE, largeResult.findViewById(R.id.image).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has notification content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), GAME_DESCRIPTION);
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
        assertThat(statusContent.getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME,
                        GAME_DESCRIPTION));
    }

    @Test
    public void testCreateRemoteViewsWithStatusTemplateWithImageOnMediumAndLarge() {
        PeopleSpaceTile tileWithIconInStatusTemplate =
                PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setStatuses(
                        Arrays.asList(new ConversationStatus.Builder(PERSON_TILE.getId(),
                                ACTIVITY_ANNIVERSARY).setDescription("Anniversary").setAvailability(
                                AVAILABILITY_AVAILABLE).setIcon(mIcon).build())).build();
        RemoteViews views = getPeopleTileViewHelper(
                tileWithIconInStatusTemplate).getViews();
        View result = views.apply(mContext, null);

        assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(View.VISIBLE, result.findViewById(R.id.scrim_layout).getVisibility());
        assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has status.
        TextView statusContent = (TextView) result.findViewById(R.id.name);
        assertEquals(statusContent.getText(), "Anniversary");
        // Since the image is showing which removes name, we need to manually include the name.
        assertThat(statusContent.getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME, "Anniversary"));
        assertThat(statusContent.getMaxLines()).isEqualTo(1);

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(tileWithIconInStatusTemplate).getViews();
        View largeResult = largeView.apply(mContext, null);

        assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.GONE, largeResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.scrim_layout).getVisibility());
        assertEquals(View.GONE, largeResult.findViewById(R.id.image).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has status content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), "Anniversary");
        // Since the image is showing which removes name, we need to manually include the name.
        assertThat(statusContent.getContentDescription().toString()).isEqualTo(
                mContext.getString(R.string.new_status_content_description, NAME, "Anniversary"));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
    }

    @Test
    public void testCreateRemoteViewsWithPackageSuspended() {
        PeopleSpaceTile tile = PERSON_TILE.toBuilder()
                .setIsPackageSuspended(true)
                .build();
        RemoteViews views = getPeopleTileViewHelper(tile).getViews();
        View result = views.apply(mContext, null);

        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_suppressed_layout);
    }

    @Test
    public void testCreateRemoteViewsWithNotificationContent() throws Exception {
        PeopleTileViewHelper helper = spy(getPeopleTileViewHelper(PERSON_TILE));
        doReturn(new BitmapDrawable()).when(helper).resolveImage(any(), any());
        RemoteViews views = helper.getViews();
        View result = views.apply(mContext, null);

        assertEquals(View.VISIBLE, result.findViewById(R.id.image).getVisibility());
    }

    @Test
    public void testCreateRemoteViewsWithInvalidNotificationContent() throws Exception {
        PeopleTileViewHelper helper = spy(getPeopleTileViewHelper(PERSON_TILE));
        doThrow(SecurityException.class).when(helper).resolveImage(any(), any());
        RemoteViews views = helper.getViews();
        View result = views.apply(mContext, null);

        assertEquals(View.GONE, result.findViewById(R.id.image).getVisibility());
        assertEquals(View.VISIBLE, result.findViewById(R.id.text_content).getVisibility());
    }

    @Test
    public void testCreateRemoteViewsWithUserQuieted() {
        PeopleSpaceTile tile = PERSON_TILE.toBuilder()
                .setIsUserQuieted(true)
                .build();
        RemoteViews views = getPeopleTileViewHelper(tile).getViews();
        View result = views.apply(mContext, null);

        assertEquals(result.getSourceLayoutResId(), R.layout.people_tile_work_profile_quiet_layout);
    }

    @Test
    public void testCreateRemoteViewsWithDndBlocking() {
        PeopleSpaceTile tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(BLOCK_CONVERSATIONS)
                .build();
        RemoteViews views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        View result = views.apply(mContext, null);

        assertResourcesEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(BLOCK_CONVERSATIONS)
                .setCanBypassDnd(true)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesNotEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_IMPORTANT_CONVERSATIONS)
                .setIsImportantConversation(true)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesNotEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_STARRED_CONTACTS)
                .setContactAffinity(VALID_CONTACT)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_STARRED_CONTACTS)
                .setContactAffinity(STARRED_CONTACT)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesNotEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_CONTACTS)
                .setContactAffinity(STARRED_CONTACT)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesNotEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_CONTACTS)
                .setContactAffinity(VALID_CONTACT)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesNotEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);

        tileWithDndBlocking = PERSON_TILE.toBuilder()
                .setNotificationPolicyState(SHOW_CONTACTS)
                .build();
        views = getPeopleTileViewHelper(tileWithDndBlocking).getViews();
        result = views.apply(mContext, null);

        assertResourcesEqual(
                result.getSourceLayoutResId(),
                R.layout.people_tile_with_suppression_detail_content_horizontal);
        assertThat(result.<TextView>findViewById(R.id.text_content).getText().toString())
                .isEqualTo(mContext.getString(R.string.paused_by_dnd));
    }

    @Test
    public void testCreateRemoteViewsWithMissedCallNotification() {
        PeopleSpaceTile tileWithMissedCallNotification = PERSON_TILE.toBuilder()
                .setNotificationDataUri(null)
                .setNotificationCategory(CATEGORY_MISSED_CALL)
                .setNotificationContent(MISSED_CALL)
                .build();
        RemoteViews views = getPeopleTileViewHelper(tileWithMissedCallNotification).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, result.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.GONE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has missed call notification content.
        TextView statusContent = (TextView) result.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), MISSED_CALL);
        assertEquals(statusContent.getContentDescription(), mContext.getString(
                R.string.new_notification_text_content_description, NAME, MISSED_CALL));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(
                tileWithMissedCallNotification).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show icon instead of name.
        assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(smallResult.findViewById(R.id.predefined_icon).getContentDescription(),
                mContext.getString(
                        R.string.new_notification_text_content_description, NAME, MISSED_CALL));
        // Has person icon.
        assertEquals(View.VISIBLE, smallResult.findViewById(R.id.person_icon).getVisibility());
        // No messages count.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(tileWithMissedCallNotification).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.GONE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has notification content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), MISSED_CALL);
        assertEquals(statusContent.getContentDescription(), mContext.getString(
                R.string.new_notification_text_content_description, NAME, MISSED_CALL));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
    }

    @Test
    public void testCreateRemoteViewsWithNotificationTemplate() {
        PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
                .setNotificationDataUri(null)
                .setStatuses(Arrays.asList(GAME_STATUS,
                        NEW_STORY_WITH_AVAILABILITY)).build();
        RemoteViews views = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(View.GONE, result.findViewById(R.id.scrim_layout).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has notification content.
        TextView statusContent = (TextView) result.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
        assertEquals(statusContent.getContentDescription(), mContext.getString(
                R.string.new_notification_text_content_description, NAME, NOTIFICATION_CONTENT));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);

        // Has a single message, no count shown.
        assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show icon instead of name.
        assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(smallResult.findViewById(R.id.predefined_icon).getContentDescription(),
                mContext.getString(R.string.new_notification_text_content_description, NAME,
                        NOTIFICATION_CONTENT));
        // Has person icon.
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.person_icon).getVisibility());

        // Has a single message, no count shown.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(largeResult.findViewById(R.id.scrim_layout), null);
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has notification content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
        assertEquals(statusContent.getContentDescription(), mContext.getString(
                R.string.new_notification_text_content_description, NAME, NOTIFICATION_CONTENT));
        assertThat(statusContent.getMaxLines()).isEqualTo(2);
        // Has a single message, no count shown.
        assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility());

    }

    @Test
    public void testCreateRemoteViewsWithNotificationWithSenderTemplate() {
        PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE_WITH_SENDER.toBuilder()
                .setNotificationDataUri(null)
                .setStatuses(Arrays.asList(GAME_STATUS,
                        NEW_STORY_WITH_AVAILABILITY)).build();
        RemoteViews views = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        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);
        assertEquals(View.VISIBLE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(subtext.getText(), SENDER);
        assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has notification content.
        TextView statusContent = (TextView) result.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
        assertEquals(statusContent.getContentDescription(), mContext.getString(
                R.string.new_notification_text_content_description, SENDER, NOTIFICATION_CONTENT));

        // Subtract one from lines because sender is included.
        assertThat(statusContent.getMaxLines()).isEqualTo(1);

        // Has a single message, no count shown.
        assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show icon instead of name.
        assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.predefined_icon).getVisibility());
        assertEquals(smallResult.findViewById(R.id.predefined_icon).getContentDescription(),
                mContext.getString(
                        R.string.new_notification_text_content_description, SENDER,
                        NOTIFICATION_CONTENT));
        // Has person icon.
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.person_icon).getVisibility());

        // Has a single message, no count shown.
        assertEquals(View.GONE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        subtext = (TextView) largeResult.findViewById(R.id.subtext);
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(subtext.getText(), SENDER);
        assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has notification content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
        assertEquals(statusContent.getContentDescription(), mContext.getString(
                R.string.new_notification_text_content_description, SENDER, NOTIFICATION_CONTENT));

        // Subtract one from lines because sender is included.
        assertThat(statusContent.getMaxLines()).isEqualTo(1);

        // Has a single message, no count shown.
        assertEquals(View.GONE, largeResult.findViewById(R.id.messages_count).getVisibility());

    }

    @Test
    public void testCreateRemoteViewsWithNotificationTemplateTwoMessages() {
        PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
                .setNotificationDataUri(null)
                .setStatuses(Arrays.asList(GAME_STATUS,
                        NEW_STORY_WITH_AVAILABILITY))
                .setMessagesCount(2).build();
        RemoteViews views = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View result = views.apply(mContext, null);

        TextView name = (TextView) result.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, result.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.GONE, result.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, result.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE, result.findViewById(R.id.person_icon).getVisibility());
        // Has notification content.
        TextView statusContent = (TextView) result.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
        assertThat(statusContent.getMaxLines()).isEqualTo(2);

        // Has two messages, show count.
        assertEquals(View.VISIBLE, result.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_medium) - 1;
        RemoteViews smallView = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View smallResult = smallView.apply(mContext, null);

        // Show icon instead of name.
        assertEquals(View.GONE, smallResult.findViewById(R.id.name).getVisibility());
        assertEquals(View.GONE,
                smallResult.findViewById(R.id.predefined_icon).getVisibility());
        // Has person icon.
        assertEquals(View.VISIBLE,
                smallResult.findViewById(R.id.person_icon).getVisibility());

        // Has two messages, show count.
        assertEquals(View.VISIBLE, smallResult.findViewById(R.id.messages_count).getVisibility());

        mWidth = getSizeInDp(R.dimen.required_width_for_large);
        mHeight = getSizeInDp(R.dimen.required_height_for_large);
        RemoteViews largeView = getPeopleTileViewHelper(
                tileWithStatusAndNotification).getViews();
        View largeResult = largeView.apply(mContext, null);

        name = (TextView) largeResult.findViewById(R.id.name);
        assertEquals(name.getText(), NAME);
        assertEquals(View.GONE, largeResult.findViewById(R.id.subtext).getVisibility());
        assertEquals(View.GONE, largeResult.findViewById(R.id.predefined_icon).getVisibility());
        // Has availability.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.availability).getVisibility());
        // Has person icon.
        View personIcon = largeResult.findViewById(R.id.person_icon);
        assertEquals(View.VISIBLE, personIcon.getVisibility());
        // Has notification content.
        statusContent = (TextView) largeResult.findViewById(R.id.text_content);
        assertEquals(View.VISIBLE, statusContent.getVisibility());
        assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
        assertThat(statusContent.getMaxLines()).isEqualTo(2);

        // Has two messages, show count.
        assertEquals(View.VISIBLE, largeResult.findViewById(R.id.messages_count).getVisibility());
    }


    @Test
    public void testGetDoublePunctuationNoPunctuation() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test");

        assertThat(backgroundText).isNull();
    }

    @Test
    public void testGetDoublePunctuationSingleExclamation() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test!");

        assertThat(backgroundText).isNull();
    }

    @Test
    public void testGetDoublePunctuationSingleQuestion() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("?test");

        assertThat(backgroundText).isNull();
    }

    @Test
    public void testGetDoublePunctuationSeparatedMarks() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test! right!");

        assertThat(backgroundText).isNull();
    }

    @Test
    public void testGetDoublePunctuationDoubleExclamation() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("!!test");

        assertThat(backgroundText).isEqualTo("!");
    }

    @Test
    public void testGetDoublePunctuationDoubleQuestion() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test??");

        assertThat(backgroundText).isEqualTo("?");
    }

    @Test
    public void testGetDoublePunctuationMixed() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation("test?!");

        assertThat(backgroundText).isEqualTo("!?");
    }

    @Test
    public void testGetDoublePunctuationMixedInTheMiddle() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
                "test!? in the middle");

        assertThat(backgroundText).isEqualTo("!?");
    }

    @Test
    public void testGetDoublePunctuationMixedDifferentOrder() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
                "test!? in the middle");

        assertThat(backgroundText).isEqualTo("!?");
    }

    @Test
    public void testGetDoublePunctuationMultiple() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
                "test!?!!? in the middle");

        assertThat(backgroundText).isEqualTo("!?");
    }

    @Test
    public void testGetDoublePunctuationQuestionFirst() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
                "test?? in the middle!!");

        assertThat(backgroundText).isEqualTo("?");
    }

    @Test
    public void testGetDoublePunctuationExclamationFirst() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoublePunctuation(
                "test!! in the middle??");

        assertThat(backgroundText).isEqualTo("!");
    }

    @Test
    public void testGetDoubleEmojisNoEmojis() {
        CharSequence backgroundText = mPeopleTileViewHelper
                .getDoubleEmoji("This string has no emojis.");
        assertThat(backgroundText).isNull();
    }

    @Test
    public void testGetDoubleEmojisSingleEmoji() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                "This string has one emoji " + EMOJI_JOY + " in the middle.");
        assertThat(backgroundText).isNull();
    }

    @Test
    public void testGetDoubleEmojisSingleEmojiThenTwoEmojis() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                "This string has one emoji " + EMOJI_JOY + " in the middle, then two "
                        + EMOJI_BEAR + EMOJI_BEAR);
        assertEquals(backgroundText, EMOJI_BEAR);
    }

    @Test
    public void testGetDoubleEmojisTwoEmojisWithModifier() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                "Yes! " + EMOJI_THUMBS_UP_BROWN_SKIN + EMOJI_THUMBS_UP_BROWN_SKIN + " Sure.");
        assertEquals(backgroundText, EMOJI_THUMBS_UP_BROWN_SKIN);
    }

    @Test
    public void testGetDoubleEmojisTwoFlagEmojis() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                "Let's travel to " + EMOJI_BR_FLAG + EMOJI_BR_FLAG + " next year.");
        assertEquals(backgroundText, EMOJI_BR_FLAG);
    }

    @Test
    public void testGetDoubleEmojiTwoBears() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                EMOJI_BEAR.toString() + EMOJI_BEAR.toString() + "bears!");
        assertEquals(backgroundText, EMOJI_BEAR);
    }

    @Test
    public void testGetDoubleEmojiTwoEmojisTwice() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                "Two sets of two emojis: " + EMOJI_FAMILY + EMOJI_FAMILY + EMOJI_BEAR + EMOJI_BEAR);
        assertEquals(backgroundText, EMOJI_FAMILY);
    }

    @Test
    public void testGetDoubleEmojiTwoEmojisSeparated() {
        CharSequence backgroundText = mPeopleTileViewHelper.getDoubleEmoji(
                "Two emojis " + EMOJI_BEAR + " separated " + EMOJI_BEAR + ".");
        assertThat(backgroundText).isNull();
    }

    private int getSizeInDp(int dimenResourceId) {
        return (int) (mContext.getResources().getDimension(dimenResourceId)
                / mContext.getResources().getDisplayMetrics().density);
    }

    private PeopleTileViewHelper getPeopleTileViewHelper(
            PeopleSpaceTile tile) {
        return new PeopleTileViewHelper(mContext, tile, 0, mWidth, mHeight,
                new PeopleTileKey(tile.getId(), 0, tile.getPackageName()));
    }

    private void assertResourcesEqual(int expected, int actual) {
        assertThat(getResourceName(actual)).isEqualTo(getResourceName(expected));
    }

    private void assertResourcesNotEqual(int expected, int actual) {
        assertThat(getResourceName(actual)).isNotEqualTo(getResourceName(expected));
    }

    private String getResourceName(int resId) {
        Resources resources = mContext.getResources();
        try {
            return resources.getResourceEntryName(resId);
        } catch (Resources.NotFoundException e) {
            return String.valueOf(resId);
        }
    }
}
