1326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira/**
2326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Copyright (c) 2011, Google Inc.
3326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira *
4326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
5326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * you may not use this file except in compliance with the License.
6326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * You may obtain a copy of the License at
7326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira *
8326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira *     http://www.apache.org/licenses/LICENSE-2.0
9326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira *
10326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Unless required by applicable law or agreed to in writing, software
11326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
12326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * See the License for the specific language governing permissions and
14326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * limitations under the License.
15326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */
16326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.browse;
18326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sappersteinimport android.app.DialogFragment;
2021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sappersteinimport android.app.FragmentManager;
213233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huangimport android.content.AsyncQueryHandler;
22326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.content.Context;
23a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwalimport android.content.res.Resources;
24b8331b4565566ca733997398e8c07a26cd2bee98Andy Huangimport android.database.DataSetObserver;
25c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sappersteinimport android.graphics.Bitmap;
26326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.graphics.Typeface;
27c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sappersteinimport android.os.Build;
28326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.text.Spannable;
29326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.text.SpannableStringBuilder;
303de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sappersteinimport android.text.Spanned;
31326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.text.TextUtils;
32326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.text.style.StyleSpan;
333de76eca03ed7ec1d40f2cce23cbbbe8e5e6d70fAndrew Sappersteinimport android.text.style.URLSpan;
34326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.util.AttributeSet;
35326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.LayoutInflater;
3675b52a50a7b8382d9046d48ea8cda97b5471cbc8Andy Huangimport android.view.Menu;
37326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.MenuItem;
38326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View;
39326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.view.View.OnClickListener;
40bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huangimport android.view.ViewGroup;
41326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.ImageView;
42326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.LinearLayout;
43326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.PopupMenu;
44bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huangimport android.widget.PopupMenu.OnMenuItemClickListener;
45326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.QuickContactBadge;
46326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.TextView;
47326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.widget.Toast;
48326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
49b8331b4565566ca733997398e8c07a26cd2bee98Andy Huangimport com.android.mail.ContactInfo;
5030e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.ContactInfoSource;
51bb56a1512559a5f024ba213c4bdcfe3d9d9387deAndy Huangimport com.android.mail.R;
52cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sappersteinimport com.android.mail.browse.ConversationViewAdapter.BorderItem;
53c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huangimport com.android.mail.browse.ConversationViewAdapter.MessageHeaderItem;
5430e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.compose.ComposeActivity;
5530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.perf.Timer;
56c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sappersteinimport com.android.mail.photomanager.LetterTileProvider;
5733fe908589dca6a7f58aa9f56d73f74a48ac42f6Mindy Pereiraimport com.android.mail.providers.Account;
5830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.Address;
594ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sappersteinimport com.android.mail.providers.Conversation;
600a135884c7452225bc0c86c5f768d581c0ce6c04Mark Weiimport com.android.mail.providers.Folder;
613ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereiraimport com.android.mail.providers.Message;
6230e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.providers.UIProvider;
63c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sappersteinimport com.android.mail.ui.ImageCanvas;
64b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
6530e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.LogUtils;
6630e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangimport com.android.mail.utils.Utils;
67a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwalimport com.android.mail.utils.VeiledAddressMatcher;
68bec5115726f24733a0a1577caaf05fb6e9ef9c6fMarc Blankimport com.google.common.annotations.VisibleForTesting;
69326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
70326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport java.io.IOException;
71326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport java.io.StringReader;
7265fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huangimport java.util.Map;
73326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
74326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereirapublic class MessageHeaderView extends LinearLayout implements OnClickListener,
752b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah        OnMenuItemClickListener, ConversationContainer.DetachListener {
76326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
77326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
78326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Cap very long recipient lists during summary construction for efficiency.
79326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
80326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final int SUMMARY_MAX_RECIPIENTS = 50;
81326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
82326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final int MAX_SNIPPET_LENGTH = 100;
83326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
84326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final int SHOW_IMAGE_PROMPT_ONCE = 1;
85326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final int SHOW_IMAGE_PROMPT_ALWAYS = 2;
86326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
87326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String HEADER_INFLATE_TAG = "message header inflate";
88326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String HEADER_ADDVIEW_TAG = "message header addView";
89326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String HEADER_RENDER_TAG = "message header render";
90326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String PREMEASURE_TAG = "message header pre-measure";
91326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String LAYOUT_TAG = "message header layout";
92326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String MEASURE_TAG = "message header measure";
93326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
94326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static final String RECIPIENT_HEADING_DELIMITER = "   ";
95326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
96b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
97326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
9877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    public static final int DEFAULT_MODE = 0;
9977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    public static final int POPUP_MODE = 1;
10077a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
1011ebc2db723ed29093d724eb5da906a496ee57224Alice Yang    // This is a debug only feature
102ce03eaa2663f543bbd49819515a5835dfb4ea77eAlice Yang    public static final boolean ENABLE_REPORT_RENDERING_PROBLEM = false;
1031ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
10421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    private static final String DETAILS_DIALOG_TAG = "details-dialog";
10521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
106326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private MessageHeaderViewCallbacks mCallbacks;
107326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1089f369596f1dc59184cdabe683c2ebfc19ead4f83Andy Huang    private ViewGroup mUpperHeaderView;
1096a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein    private View mSnapHeaderBottomBorder;
110326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private TextView mSenderNameView;
111326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private TextView mSenderEmailView;
11235c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein    private TextView mDateView;
11335c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein    private TextView mSnippetView;
114326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private QuickContactBadge mPhotoView;
115326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ImageView mStarView;
116326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ViewGroup mTitleContainerView;
1172862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein    private ViewGroup mExtraContentView;
118326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ViewGroup mCollapsedDetailsView;
119326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ViewGroup mExpandedDetailsView;
1203b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein    private SpamWarningView mSpamWarningView;
12114f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein    private TextView mImagePromptView;
122a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang    private MessageInviteView mInviteView;
12365fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mForwardButton;
12465fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mOverflowButton;
12565fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mDraftIcon;
12665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mEditDraftButton;
12765fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private TextView mUpperDateView;
12865fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mReplyButton;
12965fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mReplyAllButton;
13065fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private View mAttachmentIcon;
1312b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah    private final EmailCopyContextMenu mEmailCopyMenu;
132326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
133326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    // temporary fields to reference raw data between initial render and details
134326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    // expansion
135d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein    private String[] mFrom;
136326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private String[] mTo;
137326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private String[] mCc;
138326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private String[] mBcc;
139326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private String[] mReplyTo;
140326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
141326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private boolean mIsDraft = false;
142326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
143326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private boolean mIsSending;
144326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
145326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
146326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * The snappy header has special visibility rules (i.e. no details header,
147326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * even though it has an expanded appearance)
148326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
149326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private boolean mIsSnappy;
150326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
151326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private String mSnippet;
152326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
153326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private Address mSender;
154326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
155326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private ContactInfoSource mContactInfoSource;
156326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
157326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private boolean mPreMeasuring;
158326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
15928b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang    private ConversationAccountController mAccountController;
160326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
16165fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    private Map<String, Address> mAddressCache;
16265fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang
163326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private boolean mShowImagePrompt;
164326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
165326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
166326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Take the initial visibility of the star view to mean its collapsed
167326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * visibility. Star is always visible when expanded, but sometimes, like on
168326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * phones, there isn't enough room to warrant showing star when collapsed.
169326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
1700a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei    private boolean mCollapsedStarVisible;
1710a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei    private boolean mStarShown;
172326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
173326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
174c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein     * End margin of the text when collapsed. When expanded, the margin is 0.
175326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
176c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein    private int mTitleContainerCollapsedMarginEnd;
177326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
178326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private PopupMenu mPopup;
179326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
180c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang    private MessageHeaderItem mMessageHeaderItem;
181839ada22ea84251dde3305003d2f8fc5bf14914eAndy Huang    private ConversationMessage mMessage;
1823ce64e7ceb6246130342385d91550bcf33b31cc8Mindy Pereira
183f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private boolean mCollapsedDetailsValid;
184f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang    private boolean mExpandedDetailsValid;
185f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
18688fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang    private final LayoutInflater mInflater;
18788fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
1883233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    private AsyncQueryHandler mQueryHandler;
1893233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
19059e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang    private boolean mObservingContactInfo;
19159e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang
1927faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal    /**
1937faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal     * What I call myself? "me" in English, and internationalized correctly.
1947faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal     */
1957faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal    private final String mMyName;
1967faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal
197b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang    private final DataSetObserver mContactInfoObserver = new DataSetObserver() {
198b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang        @Override
199b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang        public void onChanged() {
200b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang            updateContactInfo();
201b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang        }
202b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang    };
203b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang
204f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp    private boolean mExpandable = true;
205f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp
20677a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    private int mExpandMode = DEFAULT_MODE;
20777a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
20821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    private DialogFragment mDetailsPopup;
20977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
21069a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal    private VeiledAddressMatcher mVeiledMatcher;
211a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal
2124ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein    private boolean mIsViewOnlyMode = false;
2134ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein
2145fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein    private LetterTileProvider mLetterTileProvider;
2155fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein    private final int mContactPhotoWidth;
2165fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein    private final int mContactPhotoHeight;
217c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein
2183233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    public interface MessageHeaderViewCallbacks {
219c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        void setMessageSpacerHeight(MessageHeaderItem item, int newSpacerHeight);
2203233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
221cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        void setMessageExpanded(MessageHeaderItem item, int newSpacerHeight,
222cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                int topBorderHeight, int bottomBorderHeight);
2233233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
2241b3cc47f54072105c161d6ed557550e0e149b8bbmindyp        void setMessageDetailsExpanded(MessageHeaderItem messageHeaderItem, boolean expanded,
2251b3cc47f54072105c161d6ed557550e0e149b8bbmindyp                int previousMessageHeaderItemHeight);
2261b3cc47f54072105c161d6ed557550e0e149b8bbmindyp
2273233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang        void showExternalResources(Message msg);
228eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy
229eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy        void showExternalResources(String senderRawAddress);
2301ebc2db723ed29093d724eb5da906a496ee57224Alice Yang
23175b52a50a7b8382d9046d48ea8cda97b5471cbc8Andy Huang        boolean supportsMessageTransforms();
2324ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein
2331ebc2db723ed29093d724eb5da906a496ee57224Alice Yang        String getMessageTransforms(Message msg);
23421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
23521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        FragmentManager getFragmentManager();
2363233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    }
2373233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
238326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public MessageHeaderView(Context context) {
239326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        this(context, null);
240326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
241326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
242326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public MessageHeaderView(Context context, AttributeSet attrs) {
243326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        this(context, attrs, -1);
244326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
245326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
246326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public MessageHeaderView(Context context, AttributeSet attrs, int defStyle) {
247326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        super(context, attrs, defStyle);
24888fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang
2492b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah        mEmailCopyMenu = new EmailCopyContextMenu(getContext());
25088fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang        mInflater = LayoutInflater.from(context);
251d4de4aa5c73a9e68e1887c2b3de233acd0c51761Paul Westbrook        mMyName = context.getString(R.string.me_object_pronun);
2525fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein
2535fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein        final Resources resources = getResources();
2546a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein        mContactPhotoWidth = resources.getDimensionPixelSize(
2556a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein                R.dimen.message_header_contact_photo_width);
2566a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein        mContactPhotoHeight = resources.getDimensionPixelSize(
2576a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein                R.dimen.message_header_contact_photo_height);
258326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
259326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
26077a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    /**
26177a4605e6fbc368b2b87b4888f2ffd6329620807mindyp     * Expand mode is DEFAULT_MODE by default.
26277a4605e6fbc368b2b87b4888f2ffd6329620807mindyp     */
26377a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    public void setExpandMode(int mode) {
26477a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        mExpandMode = mode;
26577a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    }
26677a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
267326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
268326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    protected void onFinishInflate() {
269326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        super.onFinishInflate();
2709f369596f1dc59184cdabe683c2ebfc19ead4f83Andy Huang        mUpperHeaderView = (ViewGroup) findViewById(R.id.upper_header);
2716a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein        mSnapHeaderBottomBorder = findViewById(R.id.snap_header_bottom_border);
272326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mSenderNameView = (TextView) findViewById(R.id.sender_name);
273326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mSenderEmailView = (TextView) findViewById(R.id.sender_email);
27435c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein        mDateView = (TextView) findViewById(R.id.send_date);
27535c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein        mSnippetView = (TextView) findViewById(R.id.email_snippet);
276326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mPhotoView = (QuickContactBadge) findViewById(R.id.photo);
27765fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mReplyButton = findViewById(R.id.reply);
27865fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mReplyAllButton = findViewById(R.id.reply_all);
27965fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mForwardButton = findViewById(R.id.forward);
280326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mStarView = (ImageView) findViewById(R.id.star);
281326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mTitleContainerView = (ViewGroup) findViewById(R.id.title_container);
28265fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mOverflowButton = findViewById(R.id.overflow);
28365fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mDraftIcon = findViewById(R.id.draft);
28465fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mEditDraftButton = findViewById(R.id.edit_draft);
28565fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mUpperDateView = (TextView) findViewById(R.id.upper_date);
28665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mAttachmentIcon = findViewById(R.id.attachment);
2872862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein        mExtraContentView = (ViewGroup) findViewById(R.id.header_extra_content);
288326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
2890a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei        mCollapsedStarVisible = mStarView.getVisibility() == VISIBLE;
290c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        final Resources resources = getResources();
291c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        mTitleContainerCollapsedMarginEnd = resources.getDimensionPixelSize(
292c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein                R.dimen.message_header_title_container_margin_end_collapsed);
2939f369596f1dc59184cdabe683c2ebfc19ead4f83Andy Huang
294326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        setExpanded(true);
295326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
296326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        registerMessageClickTargets(R.id.reply, R.id.reply_all, R.id.forward, R.id.star,
297326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                R.id.edit_draft, R.id.overflow, R.id.upper_header);
2982b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah
2992b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah        mUpperHeaderView.setOnCreateContextMenuListener(mEmailCopyMenu);
300326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
301326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
302326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void registerMessageClickTargets(int... ids) {
303326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        for (int id : ids) {
304326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            View v = findViewById(id);
305326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (v != null) {
306326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                v.setOnClickListener(this);
307326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
308326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
309326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
310326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
311326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
312326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Associate the header with a contact info source for later contact
313326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * presence/photo lookup.
314326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
315326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void setContactInfoSource(ContactInfoSource contactInfoSource) {
316326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mContactInfoSource = contactInfoSource;
317326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
318326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
319326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void setCallbacks(MessageHeaderViewCallbacks callbacks) {
320326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mCallbacks = callbacks;
321326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
322326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
32369a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal    public void setVeiledMatcher(VeiledAddressMatcher matcher) {
32469a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal        mVeiledMatcher = matcher;
32569a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal    }
32669a6cdff8afde77ec9bcd75a5651ee212344019eVikram Aggarwal
327326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean isExpanded() {
328c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        // (let's just arbitrarily say that unbound views are expanded by default)
329c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        return mMessageHeaderItem == null || mMessageHeaderItem.isExpanded();
330326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
331326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
332326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void setSnappy(boolean snappy) {
333326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mIsSnappy = snappy;
334326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        hideMessageDetails();
335326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
336326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
337b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang    @Override
338b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang    public void onDetachedFromParent() {
339b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang        unbind();
340b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang    }
341b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang
342326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
343326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Headers that are unbound will not match any rendered header (matches()
344326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * will return false). Unbinding is not guaranteed to *hide* the view's old
345326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * data, though. To re-bind this header to message data, call render() or
346326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * renderUpperHeaderFrom().
347326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
348326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void unbind() {
349c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        mMessageHeaderItem = null;
3503233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang        mMessage = null;
351b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang
35259e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        if (mObservingContactInfo) {
35359e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            mContactInfoSource.unregisterObserver(mContactInfoObserver);
35459e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            mObservingContactInfo = false;
35559e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        }
356326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
357326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
35814f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein    public void initialize(ConversationAccountController accountController,
35965fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            Map<String, Address> addressCache) {
36028b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang        mAccountController = accountController;
36165fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mAddressCache = addressCache;
362326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
363326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
36428b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang    private Account getAccount() {
3654ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        return mAccountController != null ? mAccountController.getAccount() : null;
36628b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang    }
36728b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang
36828b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang    public void bind(MessageHeaderItem headerItem, boolean measureOnly) {
36959e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        if (mMessageHeaderItem != null && mMessageHeaderItem == headerItem) {
37059e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            return;
37159e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        }
37259e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang
3736b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang        mMessageHeaderItem = headerItem;
3746b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang        render(measureOnly);
3756b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    }
3766b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang
377968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein    /**
378968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * Rebinds the view to its data. This will only update the view
379968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * if the {@link MessageHeaderItem} sent as a parameter is the
380968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * same as the view's current {@link MessageHeaderItem} and the
381968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     * view's expanded state differs from the item's expanded state.
382968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein     */
383968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein    public void rebind(MessageHeaderItem headerItem) {
384968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein        if (mMessageHeaderItem == null || mMessageHeaderItem != headerItem ||
385968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein                isActivated() == isExpanded()) {
386968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein            return;
387968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein        }
388968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein
389968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein        render(false /* measureOnly */);
390968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein    }
391968e014c857439de821cf2590ec6aa44363352d0Andrew Sapperstein
3926b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    public void refresh() {
3936b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang        render(false);
3946b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    }
3956b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang
3966b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang    private void render(boolean measureOnly) {
3974baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang        if (mMessageHeaderItem == null) {
3984baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang            return;
3994baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang        }
4004baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang
401326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        Timer t = new Timer();
402326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        t.start(HEADER_RENDER_TAG);
403326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
404f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        mCollapsedDetailsValid = false;
405f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        mExpandedDetailsValid = false;
406f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang
4076b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang        mMessage = mMessageHeaderItem.getMessage();
408c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        mShowImagePrompt = mMessage.shouldShowImagePrompt();
4096b3d0d9ab407c3d8b6bcb73bddbfd23f2513bb83Andy Huang        setExpanded(mMessageHeaderItem.isExpanded());
410326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
411d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein        mFrom = mMessage.getFromAddresses();
412bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mTo = mMessage.getToAddresses();
413bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mCc = mMessage.getCcAddresses();
414bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mBcc = mMessage.getBccAddresses();
415bb87b7fa57f25fc9cee1f572dd253f33f58f81daPaul Westbrook        mReplyTo = mMessage.getReplyToAddresses();
416326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
417326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        /**
418326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira         * Turns draft mode on or off. Draft mode hides message operations other
419326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira         * than "edit", hides contact photo, hides presence, and changes the
42014f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein         * sender name to "Draft".
421326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira         */
42214f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein        mIsDraft = mMessage.draftType != UIProvider.DraftType.NOT_A_DRAFT;
4232a1e8e30bdd02dc08bdf2f878201b279f60d5142Andy Huang        mIsSending = mMessage.isSending;
424326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
425326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // If this was a sent message AND:
426326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // 1. the account has a custom from, the cursor will populate the
427326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // selected custom from as the fromAddress when a message is sent but
428326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // not yet synced.
429326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // 2. the account has no custom froms, fromAddress will be empty, and we
430326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // can safely fall back and show the account name as sender since it's
431326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // the only possible fromAddress.
4328960f0af431bc164003e09b3c8981aab808d9ec1Scott Kennedy        String from = mMessage.getFrom();
433326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (TextUtils.isEmpty(from)) {
43428b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang            from = getAccount().name;
435326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
43665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        mSender = getAddress(from);
437326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
4380a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei        mStarView.setSelected(mMessage.starred);
4390a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei        mStarView.setContentDescription(getResources().getString(
4400a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei                mStarView.isSelected() ? R.string.remove_star : R.string.add_star));
4410a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei        mStarShown = true;
4424ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein
4434ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        final Conversation conversation = mMessage.getConversation();
4444ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        if (conversation != null) {
4454ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein            for (Folder folder : conversation.getRawFolders()) {
4464ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                if (folder.isTrash()) {
4474ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                    mStarShown = false;
4484ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                    break;
4494ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                }
4500a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei            }
4510a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei        }
4520a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei
4533b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        updateChildVisibility();
4543b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein
4552a1e8e30bdd02dc08bdf2f878201b279f60d5142Andy Huang        if (mIsDraft || mIsSending) {
4563b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            mSnippet = makeSnippet(mMessage.snippet);
4573b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        } else {
4583b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            mSnippet = mMessage.snippet;
4593b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        }
4603b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein
461326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mSenderNameView.setText(getHeaderTitle());
462326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mSenderEmailView.setText(getHeaderSubtitle());
46314f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein        mDateView.setText(mMessageHeaderItem.getTimestampLong());
46435c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein        mSnippetView.setText(mSnippet);
4652b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah        setAddressOnContextMenu();
466326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
46765fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        if (mUpperDateView != null) {
46814f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein            mUpperDateView.setText(mMessageHeaderItem.getTimestampShort());
469326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
470326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
47159e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        if (measureOnly) {
47259e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            // avoid leaving any state around that would interfere with future regular bind() calls
47359e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            unbind();
47459e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang        } else {
475b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang            updateContactInfo();
47659e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            if (!mObservingContactInfo) {
47759e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang                mContactInfoSource.registerObserver(mContactInfoObserver);
47859e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang                mObservingContactInfo = true;
47959e0b18db1bd06cfb74693d7dbb0cb48112a69b1Andy Huang            }
480b8331b4565566ca733997398e8c07a26cd2bee98Andy Huang        }
481326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
482326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        t.pause(HEADER_RENDER_TAG);
483326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
484326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
4852b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah    /**
4862b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah     * Update context menu's address field for when the user long presses
4872b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah     * on the message header and attempts to copy/send email.
4882b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah     */
4892b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah    private void setAddressOnContextMenu() {
4902b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah        mEmailCopyMenu.setAddress(mSender.getAddress());
4912b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah    }
4922b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah
4934baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang    public boolean isBoundTo(ConversationOverlayItem item) {
4944baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang        return item == mMessageHeaderItem;
4954baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang    }
4964baafcbb39e20a81a1585270fc270a560ec8824dAndy Huang
49721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    public Address getAddress(String emailStr) {
49865fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        return getAddress(mAddressCache, emailStr);
49965fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    }
50065fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang
50121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    public static Address getAddress(Map<String, Address> cache, String emailStr) {
50265fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        Address addr = null;
503543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang        synchronized (cache) {
50465fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            if (cache != null) {
505543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang                addr = cache.get(emailStr);
506543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang            }
507543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang            if (addr == null) {
508543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang                addr = Address.getEmailAddress(emailStr);
509543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang                if (cache != null) {
510543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang                    cache.put(emailStr, addr);
511543e709c976ce954a072020ba6f75d12f41b1fbaAndy Huang                }
51265fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            }
51365fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        }
51465fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        return addr;
51565fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang    }
51665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang
517c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang    private void updateSpacerHeight() {
518c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        final int h = measureHeight();
519c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang
520c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        mMessageHeaderItem.setHeight(h);
521c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        if (mCallbacks != null) {
522c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang            mCallbacks.setMessageSpacerHeight(mMessageHeaderItem, h);
523c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        }
524c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang    }
525c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang
526c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang    private int measureHeight() {
527c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        ViewGroup parent = (ViewGroup) getParent();
528326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (parent == null) {
529c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang            LogUtils.e(LOG_TAG, new Error(), "Unable to measure height of detached header");
530326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return getHeight();
531326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
532326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mPreMeasuring = true;
533c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        final int h = Utils.measureViewHeight(this, parent);
534326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mPreMeasuring = false;
535326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return h;
536326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
537326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
538326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private CharSequence getHeaderTitle() {
539326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        CharSequence title;
540326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
541326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mIsDraft) {
542326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            title = getResources().getQuantityText(R.plurals.draft, 1);
543326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else if (mIsSending) {
544326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            title = getResources().getString(R.string.sending);
545326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
546326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            title = getSenderName(mSender);
547326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
548326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
549326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return title;
550326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
551326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
552326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private CharSequence getHeaderSubtitle() {
553326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        CharSequence sub;
554326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mIsSending) {
555326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            sub = null;
556326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
557d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein            if (isExpanded()) {
558d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                if (mMessage.viaDomain != null) {
559d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                    sub = getResources().getString(
560d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                            R.string.via_domain, mMessage.viaDomain);
561d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                } else {
562d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                    sub = getSenderAddress(mSender);
563d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                }
564d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein            } else {
565d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein                sub = mSnippet;
566d5b369b324a22d28b63def902eefaf6591edf004Andrew Sapperstein            }
567326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
568326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return sub;
569326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
570326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
571326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
572326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Return the name, if known, or just the address.
573326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
574326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static CharSequence getSenderName(Address sender) {
57565fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        final String displayName = sender.getName();
57665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        return TextUtils.isEmpty(displayName) ? sender.getAddress() : displayName;
577326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
578326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
579326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
580326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Return the address, if a name is present, or null if not.
581326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
582326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static CharSequence getSenderAddress(Address sender) {
5836a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein        return sender.getAddress();
584326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
585326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
5863b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy    private static void setChildVisibility(int visibility, View... children) {
58765fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        for (View v : children) {
588326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (v != null) {
589326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                v.setVisibility(visibility);
590326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
591326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
592326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
593326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
594326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void setExpanded(final boolean expanded) {
595326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // use View's 'activated' flag to store expanded state
596326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // child view state lists can use this to toggle drawables
597326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        setActivated(expanded);
598c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        if (mMessageHeaderItem != null) {
599c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang            mMessageHeaderItem.setExpanded(expanded);
600c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        }
601326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
602326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
603326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
604326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Update the visibility of the many child views based on expanded/collapsed
605326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * and draft/normal state.
606326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
607326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void updateChildVisibility() {
608326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // Too bad this can't be done with an XML state list...
609326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
6104ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        if (mIsViewOnlyMode) {
6114ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein            setMessageDetailsVisibility(VISIBLE);
6126a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein            setChildVisibility(GONE, mSnapHeaderBottomBorder);
6134ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein
6144ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein            setChildVisibility(GONE, mReplyButton, mReplyAllButton, mForwardButton,
6154ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                    mOverflowButton, mDraftIcon, mEditDraftButton, mStarView,
61635c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein                    mAttachmentIcon, mUpperDateView, mSnippetView);
61735c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein            setChildVisibility(VISIBLE, mPhotoView, mSenderEmailView, mDateView);
6184ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein
619c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein            setChildMarginEnd(mTitleContainerView, 0);
6204ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        } else if (isExpanded()) {
621326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            int normalVis, draftVis;
622326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
623326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            setMessageDetailsVisibility((mIsSnappy) ? GONE : VISIBLE);
6246a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein            setChildVisibility(mIsSnappy ? VISIBLE : GONE, mSnapHeaderBottomBorder);
625326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
626326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mIsDraft) {
627326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                normalVis = GONE;
628326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                draftVis = VISIBLE;
629326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            } else {
630326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                normalVis = VISIBLE;
631326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                draftVis = GONE;
632326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
633326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
634326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            setReplyOrReplyAllVisible();
63514f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein            setChildVisibility(normalVis, mPhotoView, mForwardButton, mOverflowButton);
63665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            setChildVisibility(draftVis, mDraftIcon, mEditDraftButton);
63714f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein            setChildVisibility(VISIBLE, mSenderEmailView, mDateView);
63835c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein            setChildVisibility(GONE, mAttachmentIcon, mUpperDateView, mSnippetView);
6390a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei            setChildVisibility(mStarShown ? VISIBLE : GONE, mStarView);
640326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
641c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein            setChildMarginEnd(mTitleContainerView, 0);
642326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
643326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
644326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
645326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            setMessageDetailsVisibility(GONE);
6466a187d5113518435d13c60e2f1cabc418238c600Andrew Sapperstein            setChildVisibility(GONE, mSnapHeaderBottomBorder);
64735c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein            setChildVisibility(VISIBLE, mSnippetView, mUpperDateView);
648326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
64965fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            setChildVisibility(GONE, mEditDraftButton, mReplyButton, mReplyAllButton,
65035c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein                    mForwardButton, mOverflowButton, mSenderEmailView, mDateView);
651326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
65288fc42e48ee4e927eb77e5cab23f2f5151cac649Andy Huang            setChildVisibility(mMessage.hasAttachments ? VISIBLE : GONE,
65365fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang                    mAttachmentIcon);
654326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
6550a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei            setChildVisibility(mCollapsedStarVisible && mStarShown ? VISIBLE : GONE, mStarView);
656326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
657c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein            setChildMarginEnd(mTitleContainerView, mTitleContainerCollapsedMarginEnd);
658326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
659326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mIsDraft) {
660326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
66165fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang                setChildVisibility(VISIBLE, mDraftIcon);
662c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein                setChildVisibility(GONE, mPhotoView);
663326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
664326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            } else {
665326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
66665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang                setChildVisibility(GONE, mDraftIcon);
667c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein                setChildVisibility(VISIBLE, mPhotoView);
668326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
669326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
670326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
671326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
672326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
673326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
674326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * If an overflow menu is present in this header's layout, set the
675326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * visibility of "Reply" and "Reply All" actions based on a user preference.
676326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Only one of those actions will be visible when an overflow is present. If
677326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * no overflow is present (e.g. big phone or tablet), it's assumed we have
678326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * plenty of screen real estate and can show both.
679326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
680326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void setReplyOrReplyAllVisible() {
681326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mIsDraft) {
68265fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            setChildVisibility(GONE, mReplyButton, mReplyAllButton);
683326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return;
68465fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        } else if (mOverflowButton == null) {
68565fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            setChildVisibility(VISIBLE, mReplyButton, mReplyAllButton);
686326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return;
687326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
688326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
6894ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        final Account account = getAccount();
6904ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        final boolean defaultReplyAll = (account != null) ? account.settings.replyBehavior
6914ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                == UIProvider.DefaultReplyBehavior.REPLY_ALL : false;
69228b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang        setChildVisibility(defaultReplyAll ? GONE : VISIBLE, mReplyButton);
69328b7aee7fa1f7d096d33fc823a88a64f7a3fa79dAndy Huang        setChildVisibility(defaultReplyAll ? VISIBLE : GONE, mReplyAllButton);
694326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
695326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
696c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein    private static void setChildMarginEnd(View childView, int marginEnd) {
697326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        MarginLayoutParams mlp = (MarginLayoutParams) childView.getLayoutParams();
698c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
699c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein            mlp.setMarginEnd(marginEnd);
700c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        } else {
701c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein            mlp.rightMargin = marginEnd;
702c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        }
703326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        childView.setLayoutParams(mlp);
704326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
705326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
706a8dc86faac4d1ac07901be75dc92b7a877ca46ffVikram Aggarwal    /**
707326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Utility class to build a list of recipient lists.
708326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
709326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private static class RecipientListsBuilder {
710326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private final Context mContext;
711326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private final String mMe;
7127faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal        private final String mMyName;
713326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private final SpannableStringBuilder mBuilder = new SpannableStringBuilder();
714326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private final CharSequence mComma;
71565fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang        private final Map<String, Address> mAddressCache;
7167faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal        private final VeiledAddressMatcher mMatcher;
717326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
718326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        int mRecipientCount = 0;
719326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        boolean mFirst = true;
720326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
7217faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal        public RecipientListsBuilder(Context context, String me, String myName,
7227faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                Map<String, Address> addressCache, VeiledAddressMatcher matcher) {
723326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mContext = context;
724326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mMe = me;
7257faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal            mMyName = myName;
726326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mComma = mContext.getText(R.string.enumeration_comma);
72765fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            mAddressCache = addressCache;
7287faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal            mMatcher = matcher;
729326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
730326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
731326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public void append(String[] recipients, int headingRes) {
732326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            int addLimit = SUMMARY_MAX_RECIPIENTS - mRecipientCount;
733326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            CharSequence recipientList = getSummaryTextForHeading(headingRes, recipients, addLimit);
734326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (recipientList != null) {
735326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                // duplicate TextUtils.join() logic to minimize temporary
736326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                // allocations, and because we need to support spans
737326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                if (mFirst) {
738326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    mFirst = false;
739326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                } else {
740326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    mBuilder.append(RECIPIENT_HEADING_DELIMITER);
741326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                }
742326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mBuilder.append(recipientList);
743326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mRecipientCount += Math.min(addLimit, recipients.length);
744326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
745326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
746326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
747326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        private CharSequence getSummaryTextForHeading(int headingStrRes, String[] rawAddrs,
748326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                int maxToCopy) {
749326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (rawAddrs == null || rawAddrs.length == 0 || maxToCopy == 0) {
750326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                return null;
751326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
752326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
753326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            SpannableStringBuilder ssb = new SpannableStringBuilder(
754326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    mContext.getString(headingStrRes));
75535c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein            ssb.setSpan(new StyleSpan(Typeface.NORMAL), 0, ssb.length(),
756326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
757326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
758326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            final int len = Math.min(maxToCopy, rawAddrs.length);
759326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            boolean first = true;
760326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            for (int i = 0; i < len; i++) {
7617faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                final Address email = getAddress(mAddressCache, rawAddrs[i]);
7627faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                final String emailAddress = email.getAddress();
7637faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                final String name;
7644ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                if (mMatcher != null && mMatcher.isVeiledAddress(emailAddress)) {
7657faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                    if (TextUtils.isEmpty(email.getName())) {
7667faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                        // Let's write something more readable.
7677faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                        name = mContext.getString(VeiledAddressMatcher.VEILED_SUMMARY_UNKNOWN);
7687faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                    } else {
7697faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                        name = email.getSimplifiedName();
7707faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                    }
7717faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                } else {
7727faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                    // Not a veiled address, show first part of email, or "me".
7737faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                    name = mMe.equals(emailAddress) ? mMyName : email.getSimplifiedName();
7747faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                }
775326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
776326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                // duplicate TextUtils.join() logic to minimize temporary
777326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                // allocations, and because we need to support spans
778326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                if (first) {
779326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    first = false;
780326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                } else {
781326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    ssb.append(mComma);
782326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                }
783326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                ssb.append(name);
784326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
785326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
786326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return ssb;
787326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
788326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
789326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        public CharSequence build() {
790326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return mBuilder;
791326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
792326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
793326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
794326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @VisibleForTesting
7957faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal    static CharSequence getRecipientSummaryText(Context context, String me, String myName,
7967faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal            String[] to, String[] cc, String[] bcc, Map<String, Address> addressCache,
7977faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal            VeiledAddressMatcher matcher) {
798326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
7997faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal        final RecipientListsBuilder builder =
8007faa4d0a0ee25200f4fdc6dee30bb98b8e18b24aVikram Aggarwal                new RecipientListsBuilder(context, me, myName, addressCache, matcher);
801326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
802326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        builder.append(to, R.string.to_heading);
803326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        builder.append(cc, R.string.cc_heading);
804326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        builder.append(bcc, R.string.bcc_heading);
805326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
806326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return builder.build();
807326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
808326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
80931c38a8247b4583ac1cc506acf8454d8922ee491Andy Huang    private void updateContactInfo() {
810326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mContactInfoSource == null || mSender == null) {
811326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mPhotoView.setImageToDefault();
812326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mPhotoView.setContentDescription(getResources().getString(
813326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    R.string.contact_info_string_default));
814326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return;
815326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
816326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
817326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // Set the photo to either a found Bitmap or the default
818326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // and ensure either the contact URI or email is set so the click
819326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // handling works
820326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        String contentDesc = getResources().getString(R.string.contact_info_string,
821326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                !TextUtils.isEmpty(mSender.getName()) ? mSender.getName() : mSender.getAddress());
822326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mPhotoView.setContentDescription(contentDesc);
823326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        boolean photoSet = false;
824c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        final String email = mSender.getAddress();
825c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        final ContactInfo info = mContactInfoSource.getContactInfo(email);
826326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (info != null) {
827326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mPhotoView.assignContactUri(info.contactUri);
828326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (info.photo != null) {
829326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mPhotoView.setImageBitmap(info.photo);
830326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                photoSet = true;
831326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
832326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
833326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mPhotoView.assignContactFromEmail(email, true /* lazyLookup */);
834326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
835326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
836326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (!photoSet) {
8375fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein            mPhotoView.setImageBitmap(makeLetterTile(mSender.getName(), email));
838326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
839326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
840326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
841c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein    private Bitmap makeLetterTile(
8425fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein            String displayName, String senderAddress) {
8435fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein        if (mLetterTileProvider == null) {
8445fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein            mLetterTileProvider = new LetterTileProvider(getContext());
845c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein        }
8465fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein
8475fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein        final ImageCanvas.Dimensions dimensions = new ImageCanvas.Dimensions(
8485fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein                mContactPhotoWidth, mContactPhotoHeight, ImageCanvas.Dimensions.SCALE_ONE);
8495fbc58bc22df9642385e35da34f0ba8e218620b4Andrew Sapperstein        return mLetterTileProvider.getLetterTile(dimensions, displayName, senderAddress);
850c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein    }
851c5499cdd4627df39b935c3569c2b8e6e4b6ed38eAndrew Sapperstein
852326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
853326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
854326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public boolean onMenuItemClick(MenuItem item) {
855326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mPopup.dismiss();
856326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return onClick(null, item.getItemId());
857326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
858326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
859326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
860326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void onClick(View v) {
861326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        onClick(v, v.getId());
862326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
863326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
864326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
865326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Handles clicks on either views or menu items. View parameter can be null
866326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * for menu item clicks.
867326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
8682b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy    public boolean onClick(final View v, final int id) {
869e952353a26db3e2e6e422072daf2213e5f7b9f82Andy Huang        if (mMessage == null) {
870e952353a26db3e2e6e422072daf2213e5f7b9f82Andy Huang            LogUtils.i(LOG_TAG, "ignoring message header tap on unbound view");
871e952353a26db3e2e6e422072daf2213e5f7b9f82Andy Huang            return false;
872e952353a26db3e2e6e422072daf2213e5f7b9f82Andy Huang        }
873e952353a26db3e2e6e422072daf2213e5f7b9f82Andy Huang
874326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        boolean handled = true;
875326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
8762b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (id == R.id.reply) {
8772b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ComposeActivity.reply(getContext(), getAccount(), mMessage);
8782b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.reply_all) {
8792b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ComposeActivity.replyAll(getContext(), getAccount(), mMessage);
8802b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.forward) {
8812b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ComposeActivity.forward(getContext(), getAccount(), mMessage);
8822b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.report_rendering_problem) {
8832b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final String text = getContext().getString(R.string.report_rendering_problem_desc);
8842b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ComposeActivity.reportRenderingFeedback(getContext(), getAccount(), mMessage,
8852b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                text + "\n\n" + mCallbacks.getMessageTransforms(mMessage));
8862b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.report_rendering_improvement) {
8872b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final String text = getContext().getString(R.string.report_rendering_improvement_desc);
8882b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ComposeActivity.reportRenderingFeedback(getContext(), getAccount(), mMessage,
8892b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                text + "\n\n" + mCallbacks.getMessageTransforms(mMessage));
8902b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.star) {
8912b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final boolean newValue = !v.isSelected();
8922b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            v.setSelected(newValue);
8932b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            mMessage.star(newValue);
8942b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.edit_draft) {
8952b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ComposeActivity.editDraft(getContext(), getAccount(), mMessage);
8962b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.overflow) {
8972b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            if (mPopup == null) {
8982b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mPopup = new PopupMenu(getContext(), v);
8992b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mPopup.getMenuInflater().inflate(R.menu.message_header_overflow_menu,
9002b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                        mPopup.getMenu());
9012b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                mPopup.setOnMenuItemClickListener(this);
902326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
9032b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final boolean defaultReplyAll = getAccount().settings.replyBehavior
9042b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                    == UIProvider.DefaultReplyBehavior.REPLY_ALL;
9052b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final Menu m = mPopup.getMenu();
9062b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            m.findItem(R.id.reply).setVisible(defaultReplyAll);
9072b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            m.findItem(R.id.reply_all).setVisible(!defaultReplyAll);
9082b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy
9092b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final boolean reportRendering = ENABLE_REPORT_RENDERING_PROBLEM
9102b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                && mCallbacks.supportsMessageTransforms();
9112b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            m.findItem(R.id.report_rendering_improvement).setVisible(reportRendering);
9122b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            m.findItem(R.id.report_rendering_problem).setVisible(reportRendering);
9132b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy
9142b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            mPopup.show();
9152b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.details_collapsed_content
9162b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                || id == R.id.details_expanded_content) {
9172b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            toggleMessageDetails(v);
9182b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.upper_header) {
9192b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            toggleExpanded();
9202b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (id == R.id.show_pictures_text) {
9212b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            handleShowImagePromptClick(v);
9222b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else {
9232b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            LogUtils.i(LOG_TAG, "unrecognized header tap: %d", id);
9242b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            handled = false;
925326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
926326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return handled;
927326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
928326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
9294ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein    /**
9304ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein     * Set to true if the user should not be able to perfrom message actions
9314ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein     * on the message such as reply/reply all/forward/star/etc.
9324ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein     *
9334ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein     * Default is false.
9344ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein     */
9354ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein    public void setViewOnlyMode(boolean isViewOnlyMode) {
9364ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein        mIsViewOnlyMode = isViewOnlyMode;
9374ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein    }
9384ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein
939f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp    public void setExpandable(boolean expandable) {
940f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        mExpandable = expandable;
941f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp    }
942f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp
943326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void toggleExpanded() {
944f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        if (!mExpandable) {
945f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp            return;
946f4fce1227d8b49f45e6569f1590565f2df9e8d6emindyp        }
947c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        setExpanded(!isExpanded());
948326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
949f69a05bc8aabf7d3ae37b1f7ba76ac0a5eeb252dmindyp        // The snappy header will disappear; no reason to update text.
950f69a05bc8aabf7d3ae37b1f7ba76ac0a5eeb252dmindyp        if (!mIsSnappy) {
951f69a05bc8aabf7d3ae37b1f7ba76ac0a5eeb252dmindyp            mSenderNameView.setText(getHeaderTitle());
952f69a05bc8aabf7d3ae37b1f7ba76ac0a5eeb252dmindyp            mSenderEmailView.setText(getHeaderSubtitle());
95314f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein            mDateView.setText(mMessageHeaderItem.getTimestampLong());
95435c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein            mSnippetView.setText(mSnippet);
955f69a05bc8aabf7d3ae37b1f7ba76ac0a5eeb252dmindyp        }
956326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
957326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        updateChildVisibility();
958326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
959cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final BorderHeights borderHeights = updateBorderExpandedState();
960cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
961326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // Force-measure the new header height so we can set the spacer size and
962f69a05bc8aabf7d3ae37b1f7ba76ac0a5eeb252dmindyp        // reveal the message div in one pass. Force-measuring makes it unnecessary to set
963326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // mSizeChanged.
964c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        int h = measureHeight();
965c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        mMessageHeaderItem.setHeight(h);
966326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mCallbacks != null) {
967cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            mCallbacks.setMessageExpanded(mMessageHeaderItem, h,
968cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                    borderHeights.topHeight, borderHeights.bottomHeight);
969cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        }
970cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
971cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
972cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    /**
973cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * Checks the neighboring messages to this message and
974cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * updates the {@link BorderItem}s of the borders of this message
975cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * in case they should be collapsed or expanded.
976cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * @return a {@link BorderHeights} object containing
977cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * the new heights of the top and bottom borders.
978cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     */
979cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    private BorderHeights updateBorderExpandedState() {
980cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final int position = mMessageHeaderItem.getPosition();
981cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final boolean isExpanded = mMessageHeaderItem.isExpanded();
982cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final int abovePosition = position - 2; // position of MessageFooterItem above header
983cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final int belowPosition = position + 3; // position of next MessageHeaderItem
984cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final ConversationViewAdapter adapter = mMessageHeaderItem.getAdapter();
985cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final int size = adapter.getCount();
986cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        final BorderHeights borderHeights = new BorderHeights();
987cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
988cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        // if an above message exists, update the border above this message
989cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        if (isValidPosition(abovePosition, size)) {
990cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            final ConversationOverlayItem item = adapter.getItem(abovePosition);
991cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            final int type = item.getType();
992cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            if (type == ConversationViewAdapter.VIEW_TYPE_MESSAGE_FOOTER ||
993cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                    type == ConversationViewAdapter.VIEW_TYPE_SUPER_COLLAPSED_BLOCK) {
994cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                final BorderItem borderItem = (BorderItem) adapter.getItem(abovePosition + 1);
995cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                final boolean borderIsExpanded = isExpanded || item.isExpanded();
996cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                borderItem.setExpanded(borderIsExpanded);
997cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                borderHeights.topHeight = borderIsExpanded ?
998cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                        BorderView.getExpandedHeight() : BorderView.getCollapsedHeight();
999cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                borderItem.setHeight(borderHeights.topHeight);
1000cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            }
1001cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        }
1002cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
1003cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
1004cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        // if a below message exists, update the border below this message
1005cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        if (isValidPosition(belowPosition, size)) {
1006cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            final ConversationOverlayItem item = adapter.getItem(belowPosition);
1007cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            if (item.getType() == ConversationViewAdapter.VIEW_TYPE_MESSAGE_HEADER) {
1008cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                final BorderItem borderItem = (BorderItem) adapter.getItem(belowPosition - 1);
1009cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                final boolean borderIsExpanded = isExpanded || item.isExpanded();
1010cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                borderItem.setExpanded(borderIsExpanded);
1011cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                borderHeights.bottomHeight = borderIsExpanded ?
1012cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                        BorderView.getExpandedHeight() : BorderView.getCollapsedHeight();
1013cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein                borderItem.setHeight(borderHeights.bottomHeight);
1014cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein            }
1015326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1016cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
1017cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        return borderHeights;
1018cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
1019cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
1020cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    /**
1021cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * A plain-old-data class used to return the new heights of the top and bottom borders
1022cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * in {@link #updateBorderExpandedState()}.
1023cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * If {@link #topHeight} or {@link #bottomHeight} are -1 after returning,
1024cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * do not update the heights of the spacer for their respective borders
1025cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     * as their state has not changed.
1026cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein     */
1027cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    private class BorderHeights {
1028cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        public int topHeight = -1;
1029cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        public int bottomHeight = -1;
1030cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    }
1031cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein
1032cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein    private boolean isValidPosition(int position, int size) {
1033cee3c90574b48ccaa0f8b9f9341383c231ed41d2Andrew Sapperstein        return position >= 0 && position < size;
1034326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1035326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1036326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void toggleMessageDetails(View visibleDetailsView) {
10371b3cc47f54072105c161d6ed557550e0e149b8bbmindyp        int heightBefore = measureHeight();
1038c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        final boolean detailsExpanded = (visibleDetailsView == mCollapsedDetailsView);
1039c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        setMessageDetailsExpanded(detailsExpanded);
1040c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        updateSpacerHeight();
10411b3cc47f54072105c161d6ed557550e0e149b8bbmindyp        if (mCallbacks != null) {
10421b3cc47f54072105c161d6ed557550e0e149b8bbmindyp            mCallbacks.setMessageDetailsExpanded(mMessageHeaderItem, detailsExpanded, heightBefore);
10431b3cc47f54072105c161d6ed557550e0e149b8bbmindyp        }
1044326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1045326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1046326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void setMessageDetailsExpanded(boolean expand) {
104777a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        if (mExpandMode == DEFAULT_MODE) {
104877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp            if (expand) {
104977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                showExpandedDetails();
105077a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                hideCollapsedDetails();
105177a4605e6fbc368b2b87b4888f2ffd6329620807mindyp            } else {
105277a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                hideExpandedDetails();
105377a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                showCollapsedDetails();
105477a4605e6fbc368b2b87b4888f2ffd6329620807mindyp            }
105577a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        } else if (mExpandMode == POPUP_MODE) {
105677a4605e6fbc368b2b87b4888f2ffd6329620807mindyp            if (expand) {
105777a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                showDetailsPopup();
105877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp            } else {
105977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                hideDetailsPopup();
106077a4605e6fbc368b2b87b4888f2ffd6329620807mindyp                showCollapsedDetails();
106177a4605e6fbc368b2b87b4888f2ffd6329620807mindyp            }
1062326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1063c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        if (mMessageHeaderItem != null) {
1064c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang            mMessageHeaderItem.detailsExpanded = expand;
1065c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang        }
1066326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1067326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1068326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void setMessageDetailsVisibility(int vis) {
1069326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (vis == GONE) {
1070326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            hideCollapsedDetails();
1071326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            hideExpandedDetails();
10723b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            hideSpamWarning();
1073326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            hideShowImagePrompt();
1074a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang            hideInvite();
10752b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah            mUpperHeaderView.setOnCreateContextMenuListener(null);
1076326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } else {
1077c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang            setMessageDetailsExpanded(mMessageHeaderItem.detailsExpanded);
10783b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            if (mMessage.spamWarningString == null) {
10793b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein                hideSpamWarning();
10803b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            } else {
10813b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein                showSpamWarning();
10823b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            }
1083326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            if (mShowImagePrompt) {
1084202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy                if (mMessageHeaderItem.getShowImages()) {
1085202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy                    showImagePromptAlways(true);
1086202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy                } else {
1087202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy                    showImagePromptOnce();
1088202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy                }
10893233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang            } else {
10903233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang                hideShowImagePrompt();
1091326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1092a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang            if (mMessage.isFlaggedCalendarInvite()) {
1093a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang                showInvite();
1094a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang            } else {
1095a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang                hideInvite();
1096a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang            }
10972b7bbb53344b1e2c1d970a8da051a7431565db1fRohan Shah            mUpperHeaderView.setOnCreateContextMenuListener(mEmailCopyMenu);
1098326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1099326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1100326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1101326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    public void hideMessageDetails() {
1102326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        setMessageDetailsVisibility(GONE);
1103326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1104326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1105326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void hideCollapsedDetails() {
1106326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mCollapsedDetailsView != null) {
1107326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mCollapsedDetailsView.setVisibility(GONE);
1108326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1109326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1110326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1111326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void hideExpandedDetails() {
1112326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mExpandedDetailsView != null) {
1113326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mExpandedDetailsView.setVisibility(GONE);
1114326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1115326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1116326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1117a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang    private void hideInvite() {
1118a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang        if (mInviteView != null) {
1119a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang            mInviteView.setVisibility(GONE);
1120a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang        }
1121a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang    }
1122a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang
1123a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang    private void showInvite() {
1124a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang        if (mInviteView == null) {
1125a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang            mInviteView = (MessageInviteView) mInflater.inflate(
1126a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang                    R.layout.conversation_message_invite, this, false);
11272862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein            mExtraContentView.addView(mInviteView);
1128a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang        }
1129a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang        mInviteView.bind(mMessage);
1130a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang        mInviteView.setVisibility(VISIBLE);
1131a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang    }
1132a71f1f3368f26b6627512298f64484611fd6b0e8Andy Huang
1133326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void hideShowImagePrompt() {
1134326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mImagePromptView != null) {
1135326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mImagePromptView.setVisibility(GONE);
1136326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1137326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1138326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1139202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy    private void showImagePromptOnce() {
1140326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mImagePromptView == null) {
114114f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein            mImagePromptView = (TextView) mInflater.inflate(
114214f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein                    R.layout.conversation_message_show_pics, this, false);
11432862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein            mExtraContentView.addView(mImagePromptView);
114414f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein            mImagePromptView.setOnClickListener(this);
1145326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1146326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mImagePromptView.setVisibility(VISIBLE);
114714f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein        mImagePromptView.setText(R.string.show_images);
1148eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy        mImagePromptView.setTag(SHOW_IMAGE_PROMPT_ONCE);
1149326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1150326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1151202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy    /**
1152202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy     * Shows the "Always show pictures" message
1153202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy     *
1154202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy     * @param initialShowing <code>true</code> if this is the first time we are showing the prompt
1155202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy     *        for "show images", <code>false</code> if we are transitioning from "Show pictures"
1156202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy     */
1157202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy    private void showImagePromptAlways(final boolean initialShowing) {
1158202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy        if (initialShowing) {
1159202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy            // Initialize the view
1160202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy            showImagePromptOnce();
1161202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy        }
1162202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy
116314f937408fe2451a91b44d3cd7d141347e716775Andrew Sapperstein        mImagePromptView.setText(R.string.always_show_images);
1164202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy        mImagePromptView.setTag(SHOW_IMAGE_PROMPT_ALWAYS);
1165202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy
1166202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy        if (!initialShowing) {
1167202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy            // the new text's line count may differ, so update the spacer height
1168202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy            updateSpacerHeight();
1169202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy        }
1170202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy    }
1171202738427ede23dd5863583aa3df17e4abfbf5e2Scott Kennedy
11723b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein    private void hideSpamWarning() {
11733b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        if (mSpamWarningView != null) {
11743b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            mSpamWarningView.setVisibility(GONE);
11753b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        }
11763b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein    }
11773b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein
11783b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein    private void showSpamWarning() {
11793b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        if (mSpamWarningView == null) {
11803b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein            mSpamWarningView = (SpamWarningView)
11813b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein                    mInflater.inflate(R.layout.conversation_message_spam_warning, this, false);
11822862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein            mExtraContentView.addView(mSpamWarningView);
11833b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        }
11843b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein
11853b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein        mSpamWarningView.showSpamWarning(mMessage, mSender);
11863b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein    }
11873b08c51ec46794b3c22c8649eb86bf77c72e0d9aAndrew Sapperstein
1188326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void handleShowImagePromptClick(View v) {
1189326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        Integer state = (Integer) v.getTag();
1190326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (state == null) {
1191326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            return;
1192326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1193326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        switch (state) {
1194326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            case SHOW_IMAGE_PROMPT_ONCE:
1195326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                if (mCallbacks != null) {
11963233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang                    mCallbacks.showExternalResources(mMessage);
1197326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                }
1198470aa42b2b33d3ec5cdffa967d47e7a7b4b7209aAndy Huang                if (mMessageHeaderItem != null) {
1199470aa42b2b33d3ec5cdffa967d47e7a7b4b7209aAndy Huang                    mMessageHeaderItem.setShowImages(true);
1200470aa42b2b33d3ec5cdffa967d47e7a7b4b7209aAndy Huang                }
12014ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                if (mIsViewOnlyMode) {
12024ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                    hideShowImagePrompt();
12034ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                } else {
12044ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                    showImagePromptAlways(false);
12054ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                }
1206326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                break;
1207326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            case SHOW_IMAGE_PROMPT_ALWAYS:
12083233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang                mMessage.markAlwaysShowImages(getQueryHandler(), 0 /* token */, null /* cookie */);
12093233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
1210eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy                if (mCallbacks != null) {
1211eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy                    mCallbacks.showExternalResources(mMessage.getFrom());
1212eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy                }
1213eb9a4bdc53269ee05fe11870b9ebf03f18196585Scott Kennedy
1214326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                mShowImagePrompt = false;
1215326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                v.setTag(null);
1216326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                v.setVisibility(GONE);
1217c7543579c6a97c0ae3341578332f56d4d226f34cAndy Huang                updateSpacerHeight();
1218326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                Toast.makeText(getContext(), R.string.always_show_images_toast, Toast.LENGTH_SHORT)
1219326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        .show();
1220326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                break;
1221326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1222326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1223326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
12243233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    private AsyncQueryHandler getQueryHandler() {
12253233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang        if (mQueryHandler == null) {
12263233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang            mQueryHandler = new AsyncQueryHandler(getContext().getContentResolver()) {};
12273233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang        }
12283233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang        return mQueryHandler;
12293233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang    }
12303233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang
1231326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
1232326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Makes collapsed details visible. If necessary, will inflate details
1233326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * layout and render using saved-off state (senders, timestamp, etc).
1234326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
1235326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void showCollapsedDetails() {
1236326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mCollapsedDetailsView == null) {
12379f369596f1dc59184cdabe683c2ebfc19ead4f83Andy Huang            mCollapsedDetailsView = (ViewGroup) mInflater.inflate(
12389f369596f1dc59184cdabe683c2ebfc19ead4f83Andy Huang                    R.layout.conversation_message_details_header, this, false);
12392862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein            mExtraContentView.addView(mCollapsedDetailsView, 0);
1240326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            mCollapsedDetailsView.setOnClickListener(this);
1241f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
1242f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        if (!mCollapsedDetailsValid) {
124365fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            if (mMessageHeaderItem.recipientSummaryText == null) {
12444ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                final Account account = getAccount();
12454ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                final String name = (account != null) ? account.name : "";
124665fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang                mMessageHeaderItem.recipientSummaryText = getRecipientSummaryText(getContext(),
12474ddda2f0a4ee5381a90779a6939b05b064ce5d11Andrew Sapperstein                        name, mMyName, mTo, mCc, mBcc, mAddressCache, mVeiledMatcher);
124865fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            }
124965fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang            ((TextView) findViewById(R.id.recipients_summary))
125065fe28fa88daad08f3be4c084ca5b4eaa366d1a7Andy Huang                    .setText(mMessageHeaderItem.recipientSummaryText);
1251326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1252f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            mCollapsedDetailsValid = true;
1253326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1254326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        mCollapsedDetailsView.setVisibility(VISIBLE);
1255326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1256326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1257326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
1258326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Makes expanded details visible. If necessary, will inflate expanded
1259326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * details layout and render using saved-off state (senders, timestamp,
1260326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * etc).
1261326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
1262326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    private void showExpandedDetails() {
1263326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        // lazily create expanded details view
126463f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook        final boolean expandedViewCreated = ensureExpandedDetailsView();
126563f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook        if (expandedViewCreated) {
12662862cba002c7805a8f8e28146c6d5504831dcec7Andrew Sapperstein            mExtraContentView.addView(mExpandedDetailsView, 0);
126763f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook        }
126877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        mExpandedDetailsView.setVisibility(VISIBLE);
126977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    }
127077a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
127163f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook    private boolean ensureExpandedDetailsView() {
127263f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook        boolean viewCreated = false;
1273326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (mExpandedDetailsView == null) {
127421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            View v = inflateExpandedDetails(mInflater);
1275326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            v.setOnClickListener(this);
1276326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1277f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            mExpandedDetailsView = (ViewGroup) v;
127863f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook            viewCreated = true;
1279f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        }
1280f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang        if (!mExpandedDetailsValid) {
128121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            renderExpandedDetails(getResources(), mExpandedDetailsView, mMessage.viaDomain,
128231b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein                    mAddressCache, getAccount(), mVeiledMatcher, mFrom, mReplyTo, mTo, mCc, mBcc,
128331b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein                    mMessageHeaderItem.getTimestampLong());
1284326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1285f70fc4052b72a850bbb9be585d0f5a4877ee9448Andy Huang            mExpandedDetailsValid = true;
1286326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
128763f9b48ee0d54faf9ddc802e4582b7e499d87e04Paul Westbrook        return viewCreated;
128877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    }
128977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
129021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    public static View inflateExpandedDetails(LayoutInflater inflater) {
129121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        return inflater.inflate(R.layout.conversation_message_details_header_expanded, null,
129221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                false);
129321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    }
129421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
129521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    public static void renderExpandedDetails(Resources res, View detailsView,
129621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            String viaDomain, Map<String, Address> addressCache, Account account,
129721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            VeiledAddressMatcher veiledMatcher, String[] from, String[] replyTo,
129831b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein            String[] to, String[] cc, String[] bcc, CharSequence receivedTimestamp) {
1299ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        renderEmailList(res, R.id.from_heading, R.id.from_details, from, viaDomain,
130021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                detailsView, addressCache, account, veiledMatcher);
1301ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        renderEmailList(res, R.id.replyto_heading, R.id.replyto_details, replyTo, viaDomain,
130221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                detailsView, addressCache, account, veiledMatcher);
1303ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        renderEmailList(res, R.id.to_heading, R.id.to_details, to, viaDomain,
130421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                detailsView, addressCache, account, veiledMatcher);
1305ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        renderEmailList(res, R.id.cc_heading, R.id.cc_details, cc, viaDomain,
130621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                detailsView, addressCache, account, veiledMatcher);
1307ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        renderEmailList(res, R.id.bcc_heading, R.id.bcc_details, bcc, viaDomain,
130821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                detailsView, addressCache, account, veiledMatcher);
130931b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein
131031b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein        // Render date
131131b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein        detailsView.findViewById(R.id.date_heading).setVisibility(VISIBLE);
131231b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein        final TextView date = (TextView) detailsView.findViewById(R.id.date_details);
131331b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein        date.setText(receivedTimestamp);
131431b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein        date.setVisibility(VISIBLE);
131521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    }
131621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
131721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    /**
131821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein     * Render an email list for the expanded message details view.
131921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein     */
1320ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein    private static void renderEmailList(Resources res, int headerId, int detailsId,
132121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            String[] emails, String viaDomain, View rootView,
132221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            Map<String, Address> addressCache, Account account,
132321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            VeiledAddressMatcher veiledMatcher) {
132421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        if (emails == null || emails.length == 0) {
132521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            return;
132621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        }
132721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        final String[] formattedEmails = new String[emails.length];
132821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        for (int i = 0; i < emails.length; i++) {
132921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            final Address email = getAddress(addressCache, emails[i]);
133021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            String name = email.getName();
133121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            final String address = email.getAddress();
133221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            // Check if the address here is a veiled address.  If it is, we need to display an
133321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            // alternate layout
133421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            final boolean isVeiledAddress = veiledMatcher != null &&
133521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    veiledMatcher.isVeiledAddress(address);
133621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            final String addressShown;
133721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            if (isVeiledAddress) {
133821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                // Add the warning at the end of the name, and remove the address.  The alternate
133921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                // text cannot be put in the address part, because the address is made into a link,
134021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                // and the alternate human-readable text is not a link.
134121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                addressShown = "";
134221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                if (TextUtils.isEmpty(name)) {
134321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    // Empty name and we will block out the address. Let's write something more
134421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    // readable.
134521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    name = res.getString(VeiledAddressMatcher.VEILED_ALTERNATE_TEXT_UNKNOWN_PERSON);
134621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                } else {
134721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    name = name + res.getString(VeiledAddressMatcher.VEILED_ALTERNATE_TEXT);
134821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                }
134921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            } else {
135021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                addressShown = address;
135121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            }
135221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            if (name == null || name.length() == 0) {
135321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                formattedEmails[i] = addressShown;
135421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            } else {
135521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                // The one downside to having the showViaDomain here is that
135621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                // if the sender does not have a name, it will not show the via info
135721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                if (viaDomain != null) {
135821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    formattedEmails[i] = res.getString(
135921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                            R.string.address_display_format_with_via_domain,
136021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                            name, addressShown, viaDomain);
136121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                } else {
136221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                    formattedEmails[i] = res.getString(R.string.address_display_format,
136321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                            name, addressShown);
136421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein                }
136521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            }
136621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        }
136721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
1368ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        rootView.findViewById(headerId).setVisibility(VISIBLE);
136921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        final TextView detailsText = (TextView) rootView.findViewById(detailsId);
1370ef8d379fa5a6dadf0602159d3aa3f498327adde7Andrew Sapperstein        detailsText.setText(TextUtils.join("\n", formattedEmails));
137121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        stripUnderlines(detailsText, account);
137221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        detailsText.setVisibility(VISIBLE);
137321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    }
137421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
137521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    private static void stripUnderlines(TextView textView, Account account) {
137621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        final Spannable spannable = (Spannable) textView.getText();
137721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        final URLSpan[] urls = textView.getUrls();
137821a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
137921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        for (URLSpan span : urls) {
138021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            final int start = spannable.getSpanStart(span);
138121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            final int end = spannable.getSpanEnd(span);
138221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            spannable.removeSpan(span);
138321a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            span = new EmailAddressSpan(account, span.getURL().substring(7));
138421a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            spannable.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
138521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        }
138621a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein    }
138721a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein
138877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    private void showDetailsPopup() {
138921a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        final FragmentManager manager = mCallbacks.getFragmentManager();
139021a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein        mDetailsPopup = (DialogFragment) manager.findFragmentByTag(DETAILS_DIALOG_TAG);
139177a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        if (mDetailsPopup == null) {
139221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            mDetailsPopup = MessageHeaderDetailsDialogFragment.newInstance(
139331b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein                    mAddressCache, getAccount(), mFrom, mReplyTo, mTo, mCc, mBcc,
139431b828da09beb6ef3d8ffaf4a72bf80dc4030b62Andrew Sapperstein                    mMessageHeaderItem.getTimestampLong());
139521a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            mDetailsPopup.show(manager, DETAILS_DIALOG_TAG);
139677a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        }
139777a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    }
139877a4605e6fbc368b2b87b4888f2ffd6329620807mindyp
139977a4605e6fbc368b2b87b4888f2ffd6329620807mindyp    private void hideDetailsPopup() {
140077a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        if (mDetailsPopup != null) {
140121a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            mDetailsPopup.dismiss();
140221a6ed2bdd46ccfdf9aa3e8aecd4cb1af6c2539fAndrew Sapperstein            mDetailsPopup = null;
140377a4605e6fbc368b2b87b4888f2ffd6329620807mindyp        }
1404326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1405326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1406326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    /**
1407326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * Returns a short plaintext snippet generated from the given HTML message
1408326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * body. Collapses whitespace, ignores '&lt;' and '&gt;' characters and
1409326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * everything in between, and truncates the snippet to no more than 100
1410326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * characters.
1411326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     *
1412326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     * @return Short plaintext snippet
1413326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira     */
1414326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @VisibleForTesting
1415326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    static String makeSnippet(final String messageBody) {
1416e805ab4b4e4dcdfc21dd58d4341ec226bf70b65dAndy Huang        if (TextUtils.isEmpty(messageBody)) {
1417e805ab4b4e4dcdfc21dd58d4341ec226bf70b65dAndy Huang            return null;
1418e805ab4b4e4dcdfc21dd58d4341ec226bf70b65dAndy Huang        }
1419e805ab4b4e4dcdfc21dd58d4341ec226bf70b65dAndy Huang
1420e805ab4b4e4dcdfc21dd58d4341ec226bf70b65dAndy Huang        final StringBuilder snippet = new StringBuilder(MAX_SNIPPET_LENGTH);
1421326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1422e805ab4b4e4dcdfc21dd58d4341ec226bf70b65dAndy Huang        final StringReader reader = new StringReader(messageBody);
1423326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        try {
1424326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            int c;
1425326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            while ((c = reader.read()) != -1 && snippet.length() < MAX_SNIPPET_LENGTH) {
1426326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                // Collapse whitespace.
1427326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                if (Character.isWhitespace(c)) {
1428326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    snippet.append(' ');
1429326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    do {
1430326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        c = reader.read();
1431326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } while (Character.isWhitespace(c));
1432326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    if (c == -1) {
1433326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        break;
1434326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    }
1435326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                }
1436326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1437326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                if (c == '<') {
1438326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // Ignore everything up to and including the next '>'
1439326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // character.
1440326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    while ((c = reader.read()) != -1) {
1441326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        if (c == '>') {
1442326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                            break;
1443326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        }
1444326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    }
1445326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1446326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // If we reached the end of the message body, exit.
1447326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    if (c == -1) {
1448326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        break;
1449326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    }
1450326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                } else if (c == '&') {
1451326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // Read HTML entity.
1452326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    StringBuilder sb = new StringBuilder();
1453326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1454326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    while ((c = reader.read()) != -1) {
1455326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        if (c == ';') {
1456326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                            break;
1457326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        }
1458326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        sb.append((char) c);
1459326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    }
1460326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1461326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    String entity = sb.toString();
1462326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    if ("nbsp".equals(entity)) {
1463326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append(' ');
1464326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } else if ("lt".equals(entity)) {
1465326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append('<');
1466326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } else if ("gt".equals(entity)) {
1467326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append('>');
1468326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } else if ("amp".equals(entity)) {
1469326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append('&');
1470326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } else if ("quot".equals(entity)) {
1471326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append('"');
1472326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } else if ("apos".equals(entity) || "#39".equals(entity)) {
1473326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append('\'');
1474326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    } else {
1475326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        // Unknown entity; just append the literal string.
1476326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        snippet.append('&').append(entity);
1477326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        if (c == ';') {
1478326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                            snippet.append(';');
1479326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        }
1480326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    }
1481326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1482326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // If we reached the end of the message body, exit.
1483326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    if (c == -1) {
1484326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                        break;
1485326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    }
1486326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                } else {
1487326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // The current character is a non-whitespace character that
1488326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // isn't inside some
1489326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    // HTML tag and is not part of an HTML entity.
1490326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                    snippet.append((char) c);
1491326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira                }
1492326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            }
1493326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        } catch (IOException e) {
1494326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            LogUtils.wtf(LOG_TAG, e, "Really? IOException while reading a freaking string?!? ");
1495326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1496326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1497326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        return snippet.toString();
1498326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1499326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1500326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
1501326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    protected void onLayout(boolean changed, int l, int t, int r, int b) {
1502326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        Timer perf = new Timer();
1503326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        perf.start(LAYOUT_TAG);
1504326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        super.onLayout(changed, l, t, r, b);
1505326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        perf.pause(LAYOUT_TAG);
1506326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1507326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira
1508326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    @Override
1509326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1510326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        Timer t = new Timer();
1511326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (Timer.ENABLE_TIMER && !mPreMeasuring) {
15123233bff8ae08a56543c9f5abf1bc6ab38f0574ceAndy Huang            t.count("header measure id=" + mMessage.id);
1513326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            t.start(MEASURE_TAG);
1514326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1515326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
1516326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        if (!mPreMeasuring) {
1517326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira            t.pause(MEASURE_TAG);
1518326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira        }
1519326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira    }
1520326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira}
1521