1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.ui.conversation;
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.res.Resources;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.graphics.Rect;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.graphics.drawable.Drawable;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.support.annotation.Nullable;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.Spanned;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.format.DateUtils;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.format.Formatter;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.style.URLSpan;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.util.Linkify;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.AttributeSet;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.DisplayMetrics;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.Gravity;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.LayoutInflater;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.MotionEvent;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.ViewGroup;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.WindowManager;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.FrameLayout;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ImageView.ScaleType;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.LinearLayout;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.TextView;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModel;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ConversationMessageData;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MessageData;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MessagePartData;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.SubscriptionListData.SubscriptionListEntry;
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.media.ImageRequestDescriptor;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.media.MessagePartImageRequestDescriptor;
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.media.UriImageRequestDescriptor;
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsUtils;
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.AsyncImageView;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.AsyncImageView.AsyncImageViewDelayLoader;
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.AudioAttachmentView;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.ContactIconView;
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.ConversationDrawables;
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.MultiAttachmentLayout;
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.MultiAttachmentLayout.OnAttachmentClickListener;
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.PersonItemView;
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.UIIntents;
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.VideoThumbnailView;
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.AccessibilityUtil;
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.AvatarUriUtil;
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ContentType;
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ImageUtils;
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.OsUtil;
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.PhoneUtils;
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UiUtils;
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.YouTubeUtil;
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.google.common.base.Predicate;
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Collections;
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Comparator;
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * The view for a single entry in a conversation.
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class ConversationMessageView extends FrameLayout implements View.OnClickListener,
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        View.OnLongClickListener, OnAttachmentClickListener {
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public interface ConversationMessageViewHost {
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean onAttachmentClick(ConversationMessageView view, MessagePartData attachment,
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Rect imageBounds, boolean longPress);
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        SubscriptionListEntry getSubscriptionEntryForSelfParticipant(String selfParticipantId,
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                boolean excludeDefault);
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private final ConversationMessageData mData;
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private LinearLayout mMessageAttachmentsView;
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private MultiAttachmentLayout mMultiAttachmentView;
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private AsyncImageView mMessageImageView;
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mMessageTextView;
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean mMessageTextHasLinks;
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean mMessageHasYouTubeLink;
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mStatusTextView;
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mTitleTextView;
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mMmsInfoTextView;
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private LinearLayout mMessageTitleLayout;
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mSenderNameTextView;
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ContactIconView mContactIconView;
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ConversationMessageBubbleView mMessageBubble;
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private View mSubjectView;
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mSubjectLabel;
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mSubjectText;
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private View mDeliveredBadge;
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ViewGroup mMessageMetadataView;
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ViewGroup mMessageTextAndInfoView;
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mSimNameView;
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean mOneOnOne;
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ConversationMessageViewHost mHost;
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public ConversationMessageView(final Context context, final AttributeSet attrs) {
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        super(context, attrs);
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // TODO: we should switch to using Binding and DataModel factory methods.
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mData = new ConversationMessageData();
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onFinishInflate() {
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContactIconView = (ContactIconView) findViewById(R.id.conversation_icon);
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContactIconView.setOnLongClickListener(new OnLongClickListener() {
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public boolean onLongClick(final View view) {
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ConversationMessageView.this.performLongClick();
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return true;
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageAttachmentsView = (LinearLayout) findViewById(R.id.message_attachments);
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMultiAttachmentView = (MultiAttachmentLayout) findViewById(R.id.multiple_attachments);
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMultiAttachmentView.setOnAttachmentClickListener(this);
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageImageView = (AsyncImageView) findViewById(R.id.message_image);
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageImageView.setOnClickListener(this);
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageImageView.setOnLongClickListener(this);
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextView = (TextView) findViewById(R.id.message_text);
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextView.setOnClickListener(this);
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        IgnoreLinkLongClickHelper.ignoreLinkLongClick(mMessageTextView, this);
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mStatusTextView = (TextView) findViewById(R.id.message_status);
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mTitleTextView = (TextView) findViewById(R.id.message_title);
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMmsInfoTextView = (TextView) findViewById(R.id.mms_info);
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTitleLayout = (LinearLayout) findViewById(R.id.message_title_layout);
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSenderNameTextView = (TextView) findViewById(R.id.message_sender_name);
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageBubble = (ConversationMessageBubbleView) findViewById(R.id.message_content);
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSubjectView = findViewById(R.id.subject_container);
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSubjectLabel = (TextView) mSubjectView.findViewById(R.id.subject_label);
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSubjectText = (TextView) mSubjectView.findViewById(R.id.subject_text);
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mDeliveredBadge = findViewById(R.id.smsDeliveredBadge);
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageMetadataView = (ViewGroup) findViewById(R.id.message_metadata);
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextAndInfoView = (ViewGroup) findViewById(R.id.message_text_and_info);
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSimNameView = (TextView) findViewById(R.id.sim_name);
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int horizontalSpace = MeasureSpec.getSize(widthMeasureSpec);
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int iconSize = getResources()
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .getDimensionPixelSize(R.dimen.conversation_message_contact_icon_size);
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int unspecifiedMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int iconMeasureSpec = MeasureSpec.makeMeasureSpec(iconSize, MeasureSpec.EXACTLY);
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContactIconView.measure(iconMeasureSpec, iconMeasureSpec);
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int arrowWidth =
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                getResources().getDimensionPixelSize(R.dimen.message_bubble_arrow_width);
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We need to subtract contact icon width twice from the horizontal space to get
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // the max leftover space because we want the message bubble to extend no further than the
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // starting position of the message bubble in the opposite direction.
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int maxLeftoverSpace = horizontalSpace - mContactIconView.getMeasuredWidth() * 2
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                - arrowWidth - getPaddingLeft() - getPaddingRight();
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageContentWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxLeftoverSpace,
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                MeasureSpec.AT_MOST);
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageBubble.measure(messageContentWidthMeasureSpec, unspecifiedMeasureSpec);
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int maxHeight = Math.max(mContactIconView.getMeasuredHeight(),
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageBubble.getMeasuredHeight());
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setMeasuredDimension(horizontalSpace, maxHeight + getPaddingBottom() + getPaddingTop());
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onLayout(final boolean changed, final int left, final int top, final int right,
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int bottom) {
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isRtl = AccessibilityUtil.isLayoutRtl(this);
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int iconWidth = mContactIconView.getMeasuredWidth();
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int iconHeight = mContactIconView.getMeasuredHeight();
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int iconTop = getPaddingTop();
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int contentWidth = (right -left) - iconWidth - getPaddingLeft() - getPaddingRight();
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int contentHeight = mMessageBubble.getMeasuredHeight();
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int contentTop = iconTop;
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int iconLeft;
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int contentLeft;
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mData.getIsIncoming()) {
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isRtl) {
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                iconLeft = (right - left) - getPaddingRight() - iconWidth;
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentLeft = iconLeft - contentWidth;
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                iconLeft = getPaddingLeft();
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentLeft = iconLeft + iconWidth;
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isRtl) {
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                iconLeft = getPaddingLeft();
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentLeft = iconLeft + iconWidth;
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                iconLeft = (right - left) - getPaddingRight() - iconWidth;
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentLeft = iconLeft - contentWidth;
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mContactIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageBubble.layout(contentLeft, contentTop, contentLeft + contentWidth,
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentTop + contentHeight);
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Fills in the data associated with this view.
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param cursor The cursor from a MessageList that this view is in, pointing to its entry.
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void bind(final Cursor cursor) {
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bind(cursor, true, null);
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Fills in the data associated with this view.
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     *
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param cursor The cursor from a MessageList that this view is in, pointing to its entry.
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param oneOnOne Whether this is a 1:1 conversation
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void bind(final Cursor cursor,
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final boolean oneOnOne, final String selectedMessageId) {
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mOneOnOne = oneOnOne;
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update our UI model
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mData.bind(cursor);
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setSelected(TextUtils.equals(mData.getMessageId(), selectedMessageId));
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update text and image content for the view.
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateViewContent();
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update colors and layout parameters for the view.
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateViewAppearance();
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateContentDescription();
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setHost(final ConversationMessageViewHost host) {
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mHost = host;
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Sets a delay loader instance to manage loading / resuming of image attachments.
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setImageViewDelayLoader(final AsyncImageViewDelayLoader delayLoader) {
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.notNull(mMessageImageView);
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageImageView.setDelayLoader(delayLoader);
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMultiAttachmentView.setImageViewDelayLoader(delayLoader);
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public ConversationMessageData getData() {
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mData;
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns whether we should show simplified visual style for the message view (i.e. hide the
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * avatar and bubble arrow, reduce padding).
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean shouldShowSimplifiedVisualStyle() {
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mData.getCanClusterWithPreviousMessage();
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns whether we need to show message bubble arrow. We don't show arrow if the message
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * contains media attachments or if shouldShowSimplifiedVisualStyle() is true.
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean shouldShowMessageBubbleArrow() {
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return !shouldShowSimplifiedVisualStyle()
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                && !(mData.hasAttachments() || mMessageHasYouTubeLink);
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Returns whether we need to show a message bubble for text content.
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean shouldShowMessageTextBubble() {
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mData.hasText()) {
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String subjectText = MmsUtils.cleanseMmsSubject(getResources(),
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mData.getMmsSubject());
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!TextUtils.isEmpty(subjectText)) {
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return false;
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateViewContent() {
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateMessageContent();
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int titleResId = -1;
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int statusResId = -1;
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String statusText = null;
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        switch(mData.getStatus()) {
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING:
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING:
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD:
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD:
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                titleResId = R.string.message_title_downloading;
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                statusResId = R.string.message_status_downloading;
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD:
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!OsUtil.isSecondaryUser()) {
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    titleResId = R.string.message_title_manual_download;
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (isSelected()) {
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        statusResId = R.string.message_status_download_action;
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        statusResId = R.string.message_status_download;
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE:
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!OsUtil.isSecondaryUser()) {
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    titleResId = R.string.message_title_download_failed;
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    statusResId = R.string.message_status_download_error;
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED:
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!OsUtil.isSecondaryUser()) {
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    titleResId = R.string.message_title_download_failed;
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (isSelected()) {
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        statusResId = R.string.message_status_download_action;
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        statusResId = R.string.message_status_download;
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND:
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_SENDING:
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                statusResId = R.string.message_status_sending;
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_RESENDING:
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY:
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                statusResId = R.string.message_status_send_retrying;
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER:
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                statusResId = R.string.message_status_send_failed_emergency_number;
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_FAILED:
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // don't show the error state unless we're the default sms app
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (PhoneUtils.getDefault().isDefaultSmsApp()) {
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (isSelected()) {
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        statusResId = R.string.message_status_resend;
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        statusResId = MmsUtils.mapRawStatusToErrorResourceId(
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                mData.getStatus(), mData.getRawTelephonyStatus());
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // FALL THROUGH HERE
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_OUTGOING_COMPLETE:
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            case MessageData.BUGLE_STATUS_INCOMING_COMPLETE:
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            default:
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!mData.getCanClusterWithNextMessage()) {
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    statusText = mData.getFormattedReceivedTimeStamp();
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean titleVisible = (titleResId >= 0);
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (titleVisible) {
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String titleText = getResources().getString(titleResId);
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mTitleTextView.setText(titleText);
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String mmsInfoText = getResources().getString(
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    R.string.mms_info,
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Formatter.formatFileSize(getContext(), mData.getSmsMessageSize()),
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DateUtils.formatDateTime(
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            getContext(),
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            mData.getMmsExpiry(),
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            DateUtils.FORMAT_SHOW_DATE |
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            DateUtils.FORMAT_SHOW_TIME |
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            DateUtils.FORMAT_NUMERIC_DATE |
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            DateUtils.FORMAT_NO_YEAR));
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMmsInfoTextView.setText(mmsInfoText);
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTitleLayout.setVisibility(View.VISIBLE);
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTitleLayout.setVisibility(View.GONE);
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String subjectText = MmsUtils.cleanseMmsSubject(getResources(),
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mData.getMmsSubject());
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean subjectVisible = !TextUtils.isEmpty(subjectText);
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean senderNameVisible = !mOneOnOne && !mData.getCanClusterWithNextMessage()
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                && mData.getIsIncoming();
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (senderNameVisible) {
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSenderNameTextView.setText(mData.getSenderDisplayName());
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSenderNameTextView.setVisibility(View.VISIBLE);
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSenderNameTextView.setVisibility(View.GONE);
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (statusResId >= 0) {
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            statusText = getResources().getString(statusResId);
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We set the text even if the view will be GONE for accessibility
427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mStatusTextView.setText(statusText);
428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean statusVisible = !TextUtils.isEmpty(statusText);
429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (statusVisible) {
430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mStatusTextView.setVisibility(View.VISIBLE);
431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mStatusTextView.setVisibility(View.GONE);
433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean deliveredBadgeVisible =
436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mData.getStatus() == MessageData.BUGLE_STATUS_OUTGOING_DELIVERED;
437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mDeliveredBadge.setVisibility(deliveredBadgeVisible ? View.VISIBLE : View.GONE);
438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update the sim indicator.
440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean showSimIconAsIncoming = mData.getIsIncoming() &&
441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                (!mData.hasAttachments() || shouldShowMessageTextBubble());
442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final SubscriptionListEntry subscriptionEntry =
443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mHost.getSubscriptionEntryForSelfParticipant(mData.getSelfParticipantId(),
444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        true /* excludeDefault */);
445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean simNameVisible = subscriptionEntry != null &&
446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                !TextUtils.isEmpty(subscriptionEntry.displayName) &&
447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                !mData.getCanClusterWithNextMessage();
448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (simNameVisible) {
449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String simNameText = mData.getIsIncoming() ? getResources().getString(
450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    R.string.incoming_sim_name_text, subscriptionEntry.displayName) :
451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        subscriptionEntry.displayName;
452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSimNameView.setText(simNameText);
453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSimNameView.setTextColor(showSimIconAsIncoming ? getResources().getColor(
454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    R.color.timestamp_text_incoming) : subscriptionEntry.displayColor);
455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSimNameView.setVisibility(VISIBLE);
456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSimNameView.setText(null);
458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSimNameView.setVisibility(GONE);
459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean metadataVisible = senderNameVisible || statusVisible
462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || deliveredBadgeVisible || simNameVisible;
463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageMetadataView.setVisibility(metadataVisible ? View.VISIBLE : View.GONE);
464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean messageTextAndOrInfoVisible = titleVisible || subjectVisible
466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                || mData.hasText() || metadataVisible;
467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextAndInfoView.setVisibility(
468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                messageTextAndOrInfoVisible ? View.VISIBLE : View.GONE);
469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (shouldShowSimplifiedVisualStyle()) {
471d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactIconView.setVisibility(View.GONE);
472d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactIconView.setImageResourceUri(null);
473d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
474d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactIconView.setVisibility(View.VISIBLE);
475d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Uri avatarUri = AvatarUriUtil.createAvatarUri(
476d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.getSenderProfilePhotoUri(),
477d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.getSenderFullName(),
478d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.getSenderNormalizedDestination(),
479d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.getSenderContactLookupKey());
480d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mContactIconView.setImageResourceUri(avatarUri, mData.getSenderContactId(),
481d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.getSenderContactLookupKey(), mData.getSenderNormalizedDestination());
482d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
483d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
484d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
485d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateMessageContent() {
486d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We must update the text before the attachments since we search the text to see if we
487d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // should make a preview youtube image in the attachments
488d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateMessageText();
489d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateMessageAttachments();
490d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateMessageSubject();
491d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageBubble.bind(mData);
492d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
493d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
494d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateMessageAttachments() {
495d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Bind video, audio, and VCard attachments. If there are multiple, they stack vertically.
496d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bindAttachmentsOfSameType(sVideoFilter,
497d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.layout.message_video_attachment, mVideoViewBinder, VideoThumbnailView.class);
498d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bindAttachmentsOfSameType(sAudioFilter,
499d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.layout.message_audio_attachment, mAudioViewBinder, AudioAttachmentView.class);
500d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        bindAttachmentsOfSameType(sVCardFilter,
501d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.layout.message_vcard_attachment, mVCardViewBinder, PersonItemView.class);
502d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
503d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Bind image attachments. If there are multiple, they are shown in a collage view.
504d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<MessagePartData> imageParts = mData.getAttachments(sImageFilter);
505d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (imageParts.size() > 1) {
506d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Collections.sort(imageParts, sImageComparator);
507d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMultiAttachmentView.bindAttachments(imageParts, null, imageParts.size());
508d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMultiAttachmentView.setVisibility(View.VISIBLE);
509d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
510d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMultiAttachmentView.setVisibility(View.GONE);
511d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
512d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
513d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // In the case that we have no image attachments and exactly one youtube link in a message
514d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // then we will show a preview.
515d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String youtubeThumbnailUrl = null;
516d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String originalYoutubeLink = null;
517d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mMessageTextHasLinks && imageParts.size() == 0) {
518d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            CharSequence messageTextWithSpans = mMessageTextView.getText();
519d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final URLSpan[] spans = ((Spanned) messageTextWithSpans).getSpans(0,
520d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    messageTextWithSpans.length(), URLSpan.class);
521d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (URLSpan span : spans) {
522d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                String url = span.getURL();
523d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                String youtubeLinkForUrl = YouTubeUtil.getYoutubePreviewImageLink(url);
524d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (!TextUtils.isEmpty(youtubeLinkForUrl)) {
525d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (TextUtils.isEmpty(youtubeThumbnailUrl)) {
526d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Save the youtube link if we don't already have one
527d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        youtubeThumbnailUrl = youtubeLinkForUrl;
528d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        originalYoutubeLink = url;
529d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
530d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // We already have a youtube link. This means we have two youtube links so
531d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // we shall show none.
532d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        youtubeThumbnailUrl = null;
533d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        originalYoutubeLink = null;
534d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        break;
535d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
536d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
537d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
538d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
539d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We need to keep track if we have a youtube link in the message so that we will not show
540d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // the arrow
541d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageHasYouTubeLink = !TextUtils.isEmpty(youtubeThumbnailUrl);
542d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
543d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We will show the message image view if there is one attachment or one youtube link
544d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (imageParts.size() == 1 || mMessageHasYouTubeLink) {
545d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Get the display metrics for a hint for how large to pull the image data into
546d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final WindowManager windowManager = (WindowManager) getContext().
547d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    getSystemService(Context.WINDOW_SERVICE);
548d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final DisplayMetrics displayMetrics = new DisplayMetrics();
549d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            windowManager.getDefaultDisplay().getMetrics(displayMetrics);
550d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
551d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int iconSize = getResources()
552d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    .getDimensionPixelSize(R.dimen.conversation_message_contact_icon_size);
553d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int desiredWidth = displayMetrics.widthPixels - iconSize - iconSize;
554d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
555d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (imageParts.size() == 1) {
556d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final MessagePartData imagePart = imageParts.get(0);
557d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // If the image is big, we want to scale it down to save memory since we're going to
558d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // scale it down to fit into the bubble width. We don't constrain the height.
559d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final ImageRequestDescriptor imageRequest =
560d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        new MessagePartImageRequestDescriptor(imagePart,
561d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                desiredWidth,
562d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                MessagePartData.UNSPECIFIED_SIZE,
563d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                false);
564d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                adjustImageViewBounds(imagePart);
565d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageImageView.setImageResourceId(imageRequest);
566d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageImageView.setTag(imagePart);
567d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
568d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Youtube Thumbnail image
569d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final ImageRequestDescriptor imageRequest =
570d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        new UriImageRequestDescriptor(Uri.parse(youtubeThumbnailUrl), desiredWidth,
571d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            MessagePartData.UNSPECIFIED_SIZE, true /* allowCompression */,
572d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            true /* isStatic */, false /* cropToCircle */,
573d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ImageUtils.DEFAULT_CIRCLE_BACKGROUND_COLOR /* circleBackgroundColor */,
574d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ImageUtils.DEFAULT_CIRCLE_STROKE_COLOR /* circleStrokeColor */);
575d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageImageView.setImageResourceId(imageRequest);
576d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageImageView.setTag(originalYoutubeLink);
577d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
578d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageImageView.setVisibility(View.VISIBLE);
579d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
580d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageImageView.setImageResourceId(null);
581d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageImageView.setVisibility(View.GONE);
582d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
583d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
584d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Show the message attachments container if any of its children are visible
585d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean attachmentsVisible = false;
586d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0, size = mMessageAttachmentsView.getChildCount(); i < size; i++) {
587d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View attachmentView = mMessageAttachmentsView.getChildAt(i);
588d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (attachmentView.getVisibility() == View.VISIBLE) {
589d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                attachmentsVisible = true;
590d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
591d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
592d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
593d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageAttachmentsView.setVisibility(attachmentsVisible ? View.VISIBLE : View.GONE);
594d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
595d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
596d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void bindAttachmentsOfSameType(final Predicate<MessagePartData> attachmentTypeFilter,
597d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int attachmentViewLayoutRes, final AttachmentViewBinder viewBinder,
598d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Class<?> attachmentViewClass) {
599d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final LayoutInflater layoutInflater = LayoutInflater.from(getContext());
600d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
601d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Iterate through all attachments of a particular type (video, audio, etc).
602d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Find the first attachment index that matches the given type if possible.
603d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int attachmentViewIndex = -1;
604d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        View existingAttachmentView;
605d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        do {
606d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            existingAttachmentView = mMessageAttachmentsView.getChildAt(++attachmentViewIndex);
607d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } while (existingAttachmentView != null &&
608d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                !(attachmentViewClass.isInstance(existingAttachmentView)));
609d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
610d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final MessagePartData attachment : mData.getAttachments(attachmentTypeFilter)) {
611d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            View attachmentView = mMessageAttachmentsView.getChildAt(attachmentViewIndex);
612d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!attachmentViewClass.isInstance(attachmentView)) {
613d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                attachmentView = layoutInflater.inflate(attachmentViewLayoutRes,
614d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        mMessageAttachmentsView, false /* attachToRoot */);
615d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                attachmentView.setOnClickListener(this);
616d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                attachmentView.setOnLongClickListener(this);
617d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageAttachmentsView.addView(attachmentView, attachmentViewIndex);
618d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
619d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            viewBinder.bindView(attachmentView, attachment);
620d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            attachmentView.setTag(attachment);
621d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            attachmentView.setVisibility(View.VISIBLE);
622d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            attachmentViewIndex++;
623d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
624d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // If there are unused views left over, unbind or remove them.
625d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        while (attachmentViewIndex < mMessageAttachmentsView.getChildCount()) {
626d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View attachmentView = mMessageAttachmentsView.getChildAt(attachmentViewIndex);
627d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (attachmentViewClass.isInstance(attachmentView)) {
628d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageAttachmentsView.removeViewAt(attachmentViewIndex);
629d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
630d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // No more views of this type; we're done.
631d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                break;
632d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
633d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
634d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
635d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
636d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateMessageSubject() {
637d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String subjectText = MmsUtils.cleanseMmsSubject(getResources(),
638d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mData.getMmsSubject());
639d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean subjectVisible = !TextUtils.isEmpty(subjectText);
640d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
641d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (subjectVisible) {
642d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSubjectText.setText(subjectText);
643d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSubjectView.setVisibility(View.VISIBLE);
644d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
645d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mSubjectView.setVisibility(View.GONE);
646d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
647d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
648d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
649d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateMessageText() {
650d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String text = mData.getText();
651d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!TextUtils.isEmpty(text)) {
652d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextView.setText(text);
653d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Linkify phone numbers, web urls, emails, and map addresses to allow users to
654d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // click on them and take the default intent.
655d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextHasLinks = Linkify.addLinks(mMessageTextView, Linkify.ALL);
656d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextView.setVisibility(View.VISIBLE);
657d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
658d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextView.setVisibility(View.GONE);
659d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextHasLinks = false;
660d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
661d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
662d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
663d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateViewAppearance() {
664d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Resources res = getResources();
665d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ConversationDrawables drawableProvider = ConversationDrawables.get();
666d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean incoming = mData.getIsIncoming();
667d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean outgoing = !incoming;
668d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean showArrow =  shouldShowMessageBubbleArrow();
669d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
670d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageTopPaddingClustered =
671d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                res.getDimensionPixelSize(R.dimen.message_padding_same_author);
672d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageTopPaddingDefault =
673d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                res.getDimensionPixelSize(R.dimen.message_padding_default);
674d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int arrowWidth = res.getDimensionPixelOffset(R.dimen.message_bubble_arrow_width);
675d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageTextMinHeightDefault = res.getDimensionPixelSize(
676d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.conversation_message_contact_icon_size);
677d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageTextLeftRightPadding = res.getDimensionPixelOffset(
678d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.message_text_left_right_padding);
679d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int textTopPaddingDefault = res.getDimensionPixelOffset(
680d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.message_text_top_padding);
681d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int textBottomPaddingDefault = res.getDimensionPixelOffset(
682d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.message_text_bottom_padding);
683d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
684d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // These values depend on whether the message has text, attachments, or both.
685d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We intentionally don't set defaults, so the compiler will tell us if we forget
686d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // to set one of them, or if we set one more than once.
687d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int contentLeftPadding, contentRightPadding;
688d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Drawable textBackground;
689d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int textMinHeight;
690d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int textTopMargin;
691d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int textTopPadding, textBottomPadding;
692d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int textLeftPadding, textRightPadding;
693d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
694d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mData.hasAttachments()) {
695d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (shouldShowMessageTextBubble()) {
696d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Text and attachment(s)
697d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentLeftPadding = incoming ? arrowWidth : 0;
698d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentRightPadding = outgoing ? arrowWidth : 0;
699d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textBackground = drawableProvider.getBubbleDrawable(
700d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        isSelected(),
701d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        incoming,
702d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        false /* needArrow */,
703d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        mData.hasIncomingErrorStatus());
704d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textMinHeight = messageTextMinHeightDefault;
705d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textTopMargin = messageTopPaddingClustered;
706d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textTopPadding = textTopPaddingDefault;
707d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textBottomPadding = textBottomPaddingDefault;
708d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textLeftPadding = messageTextLeftRightPadding;
709d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textRightPadding = messageTextLeftRightPadding;
710d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
711d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Attachment(s) only
712d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentLeftPadding = incoming ? arrowWidth : 0;
713d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                contentRightPadding = outgoing ? arrowWidth : 0;
714d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textBackground = null;
715d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textMinHeight = 0;
716d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textTopMargin = 0;
717d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textTopPadding = 0;
718d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textBottomPadding = 0;
719d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textLeftPadding = 0;
720d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textRightPadding = 0;
721d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
722d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
723d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Text only
724d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            contentLeftPadding = (!showArrow && incoming) ? arrowWidth : 0;
725d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            contentRightPadding = (!showArrow && outgoing) ? arrowWidth : 0;
726d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textBackground = drawableProvider.getBubbleDrawable(
727d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    isSelected(),
728d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    incoming,
729d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    shouldShowMessageBubbleArrow(),
730d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.hasIncomingErrorStatus());
731d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textMinHeight = messageTextMinHeightDefault;
732d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textTopMargin = 0;
733d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textTopPadding = textTopPaddingDefault;
734d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textBottomPadding = textBottomPaddingDefault;
735d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (showArrow && incoming) {
736d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textLeftPadding = messageTextLeftRightPadding + arrowWidth;
737d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
738d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textLeftPadding = messageTextLeftRightPadding;
739d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
740d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (showArrow && outgoing) {
741d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textRightPadding = messageTextLeftRightPadding + arrowWidth;
742d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
743d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                textRightPadding = messageTextLeftRightPadding;
744d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
745d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
746d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
747d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // These values do not depend on whether the message includes attachments
748d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int gravity = incoming ? (Gravity.START | Gravity.CENTER_VERTICAL) :
749d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                (Gravity.END | Gravity.CENTER_VERTICAL);
750d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageTopPadding = shouldShowSimplifiedVisualStyle() ?
751d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                messageTopPaddingClustered : messageTopPaddingDefault;
752d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int metadataTopPadding = res.getDimensionPixelOffset(
753d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.message_metadata_top_padding);
754d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
755d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update the message text/info views
756d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ImageUtils.setBackgroundDrawableOnView(mMessageTextAndInfoView, textBackground);
757d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextAndInfoView.setMinimumHeight(textMinHeight);
758d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final LinearLayout.LayoutParams textAndInfoLayoutParams =
759d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                (LinearLayout.LayoutParams) mMessageTextAndInfoView.getLayoutParams();
760d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        textAndInfoLayoutParams.topMargin = textTopMargin;
761d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
762d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (UiUtils.isRtlMode()) {
763d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Need to switch right and left padding in RtL mode
764d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextAndInfoView.setPadding(textRightPadding, textTopPadding, textLeftPadding,
765d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    textBottomPadding);
766d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageBubble.setPadding(contentRightPadding, 0, contentLeftPadding, 0);
767d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
768d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageTextAndInfoView.setPadding(textLeftPadding, textTopPadding, textRightPadding,
769d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    textBottomPadding);
770d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageBubble.setPadding(contentLeftPadding, 0, contentRightPadding, 0);
771d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
772d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
773d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Update the message row and message bubble views
774d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setPadding(getPaddingLeft(), messageTopPadding, getPaddingRight(), 0);
775d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageBubble.setGravity(gravity);
776d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateMessageAttachmentsAppearance(gravity);
777d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
778d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageMetadataView.setPadding(0, metadataTopPadding, 0, 0);
779d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
780d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        updateTextAppearance();
781d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
782d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        requestLayout();
783d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
784d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
785d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateContentDescription() {
786d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        StringBuilder description = new StringBuilder();
787d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
788d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Resources res = getResources();
789d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String separator = res.getString(R.string.enumeration_comma);
790d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
791d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Sender information
792d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean hasPlainTextMessage = !(TextUtils.isEmpty(mData.getText()) ||
793d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageTextHasLinks);
794d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mData.getIsIncoming()) {
795d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int senderResId = hasPlainTextMessage
796d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ? R.string.incoming_text_sender_content_description
797d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                : R.string.incoming_sender_content_description;
798d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(res.getString(senderResId, mData.getSenderDisplayName()));
799d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
800d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            int senderResId = hasPlainTextMessage
801d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ? R.string.outgoing_text_sender_content_description
802d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                : R.string.outgoing_sender_content_description;
803d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(res.getString(senderResId));
804d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
805d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
806d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mSubjectView.getVisibility() == View.VISIBLE) {
807d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(separator);
808d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(mSubjectText.getText());
809d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
810d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
811d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mMessageTextView.getVisibility() == View.VISIBLE) {
812d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // If the message has hyperlinks, we will let the user navigate to the text message so
813d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // that the hyperlink can be clicked. Otherwise, the text message does not need to
814d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // be reachable.
815d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (mMessageTextHasLinks) {
816d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
817d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
818d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageTextView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
819d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                description.append(separator);
820d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                description.append(mMessageTextView.getText());
821d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
822d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
823d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
824d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mMessageTitleLayout.getVisibility() == View.VISIBLE) {
825d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(separator);
826d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(mTitleTextView.getText());
827d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
828d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(separator);
829d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(mMmsInfoTextView.getText());
830d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
831d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
832d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mStatusTextView.getVisibility() == View.VISIBLE) {
833d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(separator);
834d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(mStatusTextView.getText());
835d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
836d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
837d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mSimNameView.getVisibility() == View.VISIBLE) {
838d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(separator);
839d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(mSimNameView.getText());
840d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
841d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
842d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mDeliveredBadge.getVisibility() == View.VISIBLE) {
843d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(separator);
844d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            description.append(res.getString(R.string.delivered_status_content_description));
845d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
846d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
847d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setContentDescription(description);
848d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
849d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
850d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateMessageAttachmentsAppearance(final int gravity) {
851d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageAttachmentsView.setGravity(gravity);
852d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
853d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Tint image/video attachments when selected
854d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int selectedImageTint = getResources().getColor(R.color.message_image_selected_tint);
855d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mMessageImageView.getVisibility() == View.VISIBLE) {
856d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isSelected()) {
857d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageImageView.setColorFilter(selectedImageTint);
858d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
859d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMessageImageView.clearColorFilter();
860d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
861d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
862d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mMultiAttachmentView.getVisibility() == View.VISIBLE) {
863d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isSelected()) {
864d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMultiAttachmentView.setColorFilter(selectedImageTint);
865d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
866d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mMultiAttachmentView.clearColorFilter();
867d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
868d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
869d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0, size = mMessageAttachmentsView.getChildCount(); i < size; i++) {
870d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View attachmentView = mMessageAttachmentsView.getChildAt(i);
871d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (attachmentView instanceof VideoThumbnailView
872d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    && attachmentView.getVisibility() == View.VISIBLE) {
873d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final VideoThumbnailView videoView = (VideoThumbnailView) attachmentView;
874d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (isSelected()) {
875d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    videoView.setColorFilter(selectedImageTint);
876d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
877d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    videoView.clearColorFilter();
878d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
879d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
880d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
881d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
882d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // If there are multiple attachment bubbles in a single message, add some separation.
883d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int multipleAttachmentPadding =
884d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                getResources().getDimensionPixelSize(R.dimen.message_padding_same_author);
885d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
886d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean previousVisibleView = false;
887d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0, size = mMessageAttachmentsView.getChildCount(); i < size; i++) {
888d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View attachmentView = mMessageAttachmentsView.getChildAt(i);
889d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (attachmentView.getVisibility() == View.VISIBLE) {
890d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final int margin = previousVisibleView ? multipleAttachmentPadding : 0;
891d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ((LinearLayout.LayoutParams) attachmentView.getLayoutParams()).topMargin = margin;
892d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // updateViewAppearance calls requestLayout() at the end, so we don't need to here
893d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                previousVisibleView = true;
894d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
895d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
896d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
897d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
898d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void updateTextAppearance() {
899d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int messageColorResId;
900d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int statusColorResId = -1;
901d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int infoColorResId = -1;
902d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int timestampColorResId;
903d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int subjectLabelColorResId;
904d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (isSelected()) {
905d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            messageColorResId = R.color.message_text_color_incoming;
906d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            statusColorResId = R.color.message_action_status_text;
907d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            infoColorResId = R.color.message_action_info_text;
908d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (shouldShowMessageTextBubble()) {
909d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                timestampColorResId = R.color.message_action_timestamp_text;
910d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                subjectLabelColorResId = R.color.message_action_timestamp_text;
911d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
912d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // If there's no text, the timestamp will be shown below the attachments,
913d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // against the conversation view background.
914d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                timestampColorResId = R.color.timestamp_text_outgoing;
915d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                subjectLabelColorResId = R.color.timestamp_text_outgoing;
916d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
917d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
918d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            messageColorResId = (mData.getIsIncoming() ?
919d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    R.color.message_text_color_incoming : R.color.message_text_color_outgoing);
920d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            statusColorResId = messageColorResId;
921d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            infoColorResId = R.color.timestamp_text_incoming;
922d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            switch(mData.getStatus()) {
923d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
924d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_FAILED:
925d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER:
926d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    timestampColorResId = R.color.message_failed_timestamp_text;
927d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    subjectLabelColorResId = R.color.timestamp_text_outgoing;
928d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
929d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
930d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND:
931d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_SENDING:
932d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_RESENDING:
933d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY:
934d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_COMPLETE:
935d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_OUTGOING_DELIVERED:
936d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    timestampColorResId = R.color.timestamp_text_outgoing;
937d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    subjectLabelColorResId = R.color.timestamp_text_outgoing;
938d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
939d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
940d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE:
941d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED:
942d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    messageColorResId = R.color.message_text_color_incoming_download_failed;
943d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    timestampColorResId = R.color.message_download_failed_timestamp_text;
944d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    subjectLabelColorResId = R.color.message_text_color_incoming_download_failed;
945d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    statusColorResId = R.color.message_download_failed_status_text;
946d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    infoColorResId = R.color.message_info_text_incoming_download_failed;
947d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
948d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
949d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING:
950d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING:
951d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD:
952d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD:
953d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD:
954d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    timestampColorResId = R.color.message_text_color_incoming;
955d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    subjectLabelColorResId = R.color.message_text_color_incoming;
956d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    infoColorResId = R.color.timestamp_text_incoming;
957d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
958d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
959d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                case MessageData.BUGLE_STATUS_INCOMING_COMPLETE:
960d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                default:
961d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    timestampColorResId = R.color.timestamp_text_incoming;
962d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    subjectLabelColorResId = R.color.timestamp_text_incoming;
963d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    infoColorResId = -1; // Not used
964d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
965d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
966d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
967d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int messageColor = getResources().getColor(messageColorResId);
968d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextView.setTextColor(messageColor);
969d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mMessageTextView.setLinkTextColor(messageColor);
970d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSubjectText.setTextColor(messageColor);
971d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (statusColorResId >= 0) {
972d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mTitleTextView.setTextColor(getResources().getColor(statusColorResId));
973d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
974d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (infoColorResId >= 0) {
975d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMmsInfoTextView.setTextColor(getResources().getColor(infoColorResId));
976d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
977d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (timestampColorResId == R.color.timestamp_text_incoming &&
978d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mData.hasAttachments() && !shouldShowMessageTextBubble()) {
979d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            timestampColorResId = R.color.timestamp_text_outgoing;
980d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
981d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mStatusTextView.setTextColor(getResources().getColor(timestampColorResId));
982d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
983d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSubjectLabel.setTextColor(getResources().getColor(subjectLabelColorResId));
984d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mSenderNameTextView.setTextColor(getResources().getColor(timestampColorResId));
985d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
986d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
987d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
988d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * If we don't know the size of the image, we want to show it in a fixed-sized frame to
989d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * avoid janks when the image is loaded and resized. Otherwise, we can set the imageview to
990d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * take on normal layout params.
991d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
992d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void adjustImageViewBounds(final MessagePartData imageAttachment) {
993d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.isTrue(ContentType.isImageType(imageAttachment.getContentType()));
994d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ViewGroup.LayoutParams layoutParams = mMessageImageView.getLayoutParams();
995d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (imageAttachment.getWidth() == MessagePartData.UNSPECIFIED_SIZE ||
996d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                imageAttachment.getHeight() == MessagePartData.UNSPECIFIED_SIZE) {
997d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // We don't know the size of the image attachment, enable letterboxing on the image
998d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // and show a fixed sized attachment. This should happen at most once per image since
999d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // after the image is loaded we then save the image dimensions to the db so that the
1000d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // next time we can display the full size.
1001d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            layoutParams.width = getResources()
1002d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    .getDimensionPixelSize(R.dimen.image_attachment_fallback_width);
1003d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            layoutParams.height = getResources()
1004d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    .getDimensionPixelSize(R.dimen.image_attachment_fallback_height);
1005d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageImageView.setScaleType(ScaleType.CENTER_CROP);
1006d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
1007d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
1008d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
1009d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // ScaleType.CENTER_INSIDE and FIT_CENTER behave similarly for most images. However,
1010d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // FIT_CENTER works better for small images as it enlarges the image such that the
1011d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // minimum size ("android:minWidth" etc) is honored.
1012d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mMessageImageView.setScaleType(ScaleType.FIT_CENTER);
1013d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1014d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1015d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1016d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
1017d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void onClick(final View view) {
1018d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Object tag = view.getTag();
1019d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (tag instanceof MessagePartData) {
1020d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Rect bounds = UiUtils.getMeasuredBoundsOnScreen(view);
1021d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            onAttachmentClick((MessagePartData) tag, bounds, false /* longPress */);
1022d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else if (tag instanceof String) {
1023d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Currently the only object that would make a tag of a string is a youtube preview
1024d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // image
1025d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            UIIntents.get().launchBrowserForUrl(getContext(), (String) tag);
1026d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1027d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1028d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1029d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
1030d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean onLongClick(final View view) {
1031d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (view == mMessageTextView) {
1032d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Preemptively handle the long click event on message text so it's not handled by
1033d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // the link spans.
1034d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return performLongClick();
1035d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1036d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1037d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Object tag = view.getTag();
1038d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (tag instanceof MessagePartData) {
1039d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Rect bounds = UiUtils.getMeasuredBoundsOnScreen(view);
1040d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return onAttachmentClick((MessagePartData) tag, bounds, true /* longPress */);
1041d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1042d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1043d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return false;
1044d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1045d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1046d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
1047d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean onAttachmentClick(final MessagePartData attachment,
1048d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Rect viewBoundsOnScreen, final boolean longPress) {
1049d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mHost.onAttachmentClick(this, attachment, viewBoundsOnScreen, longPress);
1050d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1051d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1052d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public ContactIconView getContactIconView() {
1053d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mContactIconView;
1054d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1055d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1056d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // Sort photos in MultiAttachLayout in the same order as the ConversationImagePartsView
1057d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final Comparator<MessagePartData> sImageComparator = new Comparator<MessagePartData>(){
1058d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1059d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int compare(final MessagePartData x, final MessagePartData y) {
1060d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return x.getPartId().compareTo(y.getPartId());
1061d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1062d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1063d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1064d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final Predicate<MessagePartData> sVideoFilter = new Predicate<MessagePartData>() {
1065d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1066d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean apply(final MessagePartData part) {
1067d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return part.isVideo();
1068d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1069d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1070d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1071d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final Predicate<MessagePartData> sAudioFilter = new Predicate<MessagePartData>() {
1072d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1073d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean apply(final MessagePartData part) {
1074d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return part.isAudio();
1075d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1076d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1077d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1078d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final Predicate<MessagePartData> sVCardFilter = new Predicate<MessagePartData>() {
1079d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1080d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean apply(final MessagePartData part) {
1081d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return part.isVCard();
1082d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1083d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1084d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1085d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static final Predicate<MessagePartData> sImageFilter = new Predicate<MessagePartData>() {
1086d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1087d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean apply(final MessagePartData part) {
1088d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return part.isImage();
1089d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1090d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1091d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1092d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    interface AttachmentViewBinder {
1093d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        void bindView(View view, MessagePartData attachment);
1094d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        void unbind(View view);
1095d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1096d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1097d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    final AttachmentViewBinder mVideoViewBinder = new AttachmentViewBinder() {
1098d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1099d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void bindView(final View view, final MessagePartData attachment) {
1100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ((VideoThumbnailView) view).setSource(attachment, mData.getIsIncoming());
1101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void unbind(final View view) {
1105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ((VideoThumbnailView) view).setSource((Uri) null, mData.getIsIncoming());
1106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    final AttachmentViewBinder mAudioViewBinder = new AttachmentViewBinder() {
1110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void bindView(final View view, final MessagePartData attachment) {
1112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final AudioAttachmentView audioView = (AudioAttachmentView) view;
1113eba0949bc60e9002adf0c96044677b4c281b2819Shri Borde            audioView.bindMessagePartData(attachment, mData.getIsIncoming(), isSelected());
1114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            audioView.setBackground(ConversationDrawables.get().getBubbleDrawable(
1115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    isSelected(), mData.getIsIncoming(), false /* needArrow */,
1116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.hasIncomingErrorStatus()));
1117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void unbind(final View view) {
1121eba0949bc60e9002adf0c96044677b4c281b2819Shri Borde            ((AudioAttachmentView) view).bindMessagePartData(null, mData.getIsIncoming(), false);
1122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    final AttachmentViewBinder mVCardViewBinder = new AttachmentViewBinder() {
1126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void bindView(final View view, final MessagePartData attachment) {
1128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final PersonItemView personView = (PersonItemView) view;
1129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            personView.bind(DataModel.get().createVCardContactItemData(getContext(),
1130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    attachment));
1131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            personView.setBackground(ConversationDrawables.get().getBubbleDrawable(
1132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    isSelected(), mData.getIsIncoming(), false /* needArrow */,
1133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mData.hasIncomingErrorStatus()));
1134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int nameTextColorRes;
1135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int detailsTextColorRes;
1136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (isSelected()) {
1137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                nameTextColorRes = R.color.message_text_color_incoming;
1138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                detailsTextColorRes = R.color.message_text_color_incoming;
1139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
1140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                nameTextColorRes = mData.getIsIncoming() ? R.color.message_text_color_incoming
1141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        : R.color.message_text_color_outgoing;
1142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                detailsTextColorRes = mData.getIsIncoming() ? R.color.timestamp_text_incoming
1143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        : R.color.timestamp_text_outgoing;
1144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            personView.setNameTextColor(getResources().getColor(nameTextColorRes));
1146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            personView.setDetailsTextColor(getResources().getColor(detailsTextColorRes));
1147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public void unbind(final View view) {
1151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ((PersonItemView) view).bind(null);
1152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
1154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
1156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * A helper class that allows us to handle long clicks on linkified message text view (i.e. to
1157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * select the message) so it's not handled by the link spans to launch apps for the links.
1158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
1159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static class IgnoreLinkLongClickHelper implements OnLongClickListener, OnTouchListener {
1160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private boolean mIsLongClick;
1161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private final OnLongClickListener mDelegateLongClickListener;
1162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        /**
1164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * Ignore long clicks on linkified texts for a given text view.
1165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * @param textView the TextView to ignore long clicks on
1166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         * @param longClickListener a delegate OnLongClickListener to be called when the view is
1167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         *        long clicked.
1168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd         */
1169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static void ignoreLinkLongClick(final TextView textView,
1170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                @Nullable final OnLongClickListener longClickListener) {
1171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final IgnoreLinkLongClickHelper helper =
1172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new IgnoreLinkLongClickHelper(longClickListener);
1173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textView.setOnLongClickListener(helper);
1174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            textView.setOnTouchListener(helper);
1175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private IgnoreLinkLongClickHelper(@Nullable final OnLongClickListener longClickListener) {
1178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mDelegateLongClickListener = longClickListener;
1179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean onLongClick(final View v) {
1183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Record that this click is a long click.
1184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mIsLongClick = true;
1185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (mDelegateLongClickListener != null) {
1186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return mDelegateLongClickListener.onLongClick(v);
1187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
1189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
1192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public boolean onTouch(final View v, final MotionEvent event) {
1193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (event.getActionMasked() == MotionEvent.ACTION_UP && mIsLongClick) {
1194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // This touch event is a long click, preemptively handle this touch event so that
1195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // the link span won't get a onClicked() callback.
1196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mIsLongClick = false;
1197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return true;
1198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
1200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
1201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mIsLongClick = false;
1202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
1203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
1204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
1205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
1206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
1207