15e5ac748eadbb17eee84b39a424b8b9270ade46cVikram Aggarwal/*
25e5ac748eadbb17eee84b39a424b8b9270ade46cVikram Aggarwal * Copyright (C) 2012 Google Inc.
35e5ac748eadbb17eee84b39a424b8b9270ade46cVikram Aggarwal * Licensed to The Android Open Source Project.
46f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira *
56f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
66f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * you may not use this file except in compliance with the License.
76f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * You may obtain a copy of the License at
86f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira *
95e5ac748eadbb17eee84b39a424b8b9270ade46cVikram Aggarwal *      http://www.apache.org/licenses/LICENSE-2.0
106f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira *
116f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * Unless required by applicable law or agreed to in writing, software
126f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
136f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
146f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * See the License for the specific language governing permissions and
156f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira * limitations under the License.
166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira */
175e5ac748eadbb17eee84b39a424b8b9270ade46cVikram Aggarwal
1830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.browse;
196f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
20bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereiraimport android.animation.Animator;
21bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereiraimport android.animation.AnimatorSet;
22866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport android.animation.ObjectAnimator;
23a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sappersteinimport android.content.BroadcastReceiver;
24304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blankimport android.content.Context;
25a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sappersteinimport android.content.Intent;
26a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sappersteinimport android.content.IntentFilter;
276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.res.Resources;
286f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Bitmap;
296f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.BitmapFactory;
306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Canvas;
311fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedyimport android.graphics.Color;
32b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport android.graphics.Paint;
33479505d71969e26b0785d8e0e1b81108731cf827Mark Weiimport android.graphics.Rect;
346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Typeface;
356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.drawable.Drawable;
36be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.graphics.drawable.InsetDrawable;
372cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Caoimport android.support.annotation.Nullable;
384eb909e1ef9656dfc06d2518842357827dcfb068Jin Caoimport android.support.v4.text.BidiFormatter;
39928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieuximport android.support.v4.text.TextUtilsCompat;
40a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sappersteinimport android.support.v4.view.ViewCompat;
416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.Layout.Alignment;
426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.Spannable;
43b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereiraimport android.text.SpannableString;
446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableStringBuilder;
456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.StaticLayout;
466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.TextPaint;
476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.TextUtils;
486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.TextUtils.TruncateAt;
496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.format.DateUtils;
50be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sappersteinimport android.text.style.BackgroundColorSpan;
516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.CharacterStyle;
526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.ForegroundColorSpan;
532615aea2ce57f5fa3a9cd2e672282818aee6ce94mindypimport android.text.style.TextAppearanceSpan;
546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.util.SparseArray;
55fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huangimport android.util.TypedValue;
566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.view.MotionEvent;
576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.view.View;
58850c55ee2cab6b1c224366c66502f5d5f55018ebmindypimport android.view.ViewGroup;
59370f868c834861e7732faaa9bdd07a0fa0105596Andy Huangimport android.view.ViewParent;
60866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport android.view.animation.DecelerateInterpolator;
61850c55ee2cab6b1c224366c66502f5d5f55018ebmindypimport android.widget.TextView;
626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
63732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.R;
64042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huangimport com.android.mail.analytics.Analytics;
655f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieuximport com.android.mail.bitmap.CheckableContactFlipDrawable;
66a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.bitmap.ContactDrawable;
67732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.perf.Timer;
683dbfbc210a607382ba9c150d7ae373ca0508267cJin Caoimport com.android.mail.providers.Account;
69732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.providers.Conversation;
70b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport com.android.mail.providers.Folder;
714a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huangimport com.android.mail.providers.UIProvider;
72c8a994227b9c686d88ee05840544162711a85712Marc Blankimport com.android.mail.providers.UIProvider.ConversationColumns;
73b4a222726f3f1c78b7146fa5f7d4d45974bcef47Andy Huangimport com.android.mail.providers.UIProvider.ConversationListIcon;
7467aa9e5162a15fb8b46b4113ac627cd20668f095Scott Kennedyimport com.android.mail.providers.UIProvider.FolderType;
75bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.ui.AnimatedAdapter;
76e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereiraimport com.android.mail.ui.ControllableActivity;
77ec0fa48764bede0772e9c711f3e33361b62f3608Jin Caoimport com.android.mail.ui.ConversationCheckedSet;
78a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.ui.ConversationSetObserver;
79b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport com.android.mail.ui.FolderDisplayer;
806c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereiraimport com.android.mail.ui.SwipeableItemView;
81a538984fcc19e7624f2650b119ede39bf1f35846mindypimport com.android.mail.ui.SwipeableListView;
82259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedyimport com.android.mail.utils.FolderUri;
83370f868c834861e7732faaa9bdd07a0fa0105596Andy Huangimport com.android.mail.utils.HardwareLayerEnabler;
842f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwalimport com.android.mail.utils.LogTag;
855390fcabb7baf683fc14bd68d8612913dac70a81mindypimport com.android.mail.utils.LogUtils;
86732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.utils.Utils;
87a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sappersteinimport com.android.mail.utils.ViewUtils;
88304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blankimport com.google.common.annotations.VisibleForTesting;
89732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang
9010ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieuximport java.util.List;
91928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieuximport java.util.Locale;
9288acafa03a87f5c84b959697d13b81df8f11a96emindyp
9379c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huangpublic class ConversationItemView extends View
943dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao        implements SwipeableItemView, ToggleableItem, ConversationSetObserver,
950e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux        BadgeSpan.BadgeSpanDimensions {
96479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
976f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Timer.
986f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static int sLayoutCount = 0;
99bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook    private static Timer sTimer; // Create the sTimer here if you need to do
100bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                                 // perf analysis.
1016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final int PERF_LAYOUT_ITERATIONS = 50;
1026f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_LAYOUT = "CCHV.layout";
1036f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_CALCULATE_TEXTS_BITMAPS = "CCHV.txtsbmps";
1046f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_CALCULATE_SENDER_SUBJECT = "CCHV.sendersubj";
10530fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira    private static final String PERF_TAG_CALCULATE_FOLDERS = "CCHV.folders";
1066f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_CALCULATE_COORDINATES = "CCHV.coordinates";
1072f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal    private static final String LOG_TAG = LogTag.getLogTag();
1086f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
109ff35c4d206132d389cc5b77c488bd1fd41926e4dJames Lemieux    private static final Typeface SANS_SERIF_BOLD = Typeface.create("sans-serif", Typeface.BOLD);
110ff35c4d206132d389cc5b77c488bd1fd41926e4dJames Lemieux
111f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux    private static final Typeface SANS_SERIF_LIGHT = Typeface.create("sans-serif-light",
112f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux            Typeface.NORMAL);
113f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux
114ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    private static final int[] CHECKED_STATE = new int[] { android.R.attr.state_checked };
115ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao
1166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Static bitmaps.
1176f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap STAR_OFF;
1186f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap STAR_ON;
1196f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap ATTACHMENT;
1204a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang    private static Bitmap ONLY_TO_ME;
1214a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang    private static Bitmap TO_ME_AND_OTHERS;
1224a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang    private static Bitmap IMPORTANT_ONLY_TO_ME;
1234a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang    private static Bitmap IMPORTANT_TO_ME_AND_OTHERS;
12417646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    private static Bitmap IMPORTANT;
12554467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira    private static Bitmap STATE_REPLIED;
12654467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira    private static Bitmap STATE_FORWARDED;
12754467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira    private static Bitmap STATE_REPLIED_AND_FORWARDED;
1288d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira    private static Bitmap STATE_CALENDAR_INVITE;
1290532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    private static Drawable FOCUSED_CONVERSATION_HIGHLIGHT;
1306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
131ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static String sSendersSplitToken;
132ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static String sElidedPaddingToken;
13324538e893ef2db41a4c1b341f676b64422920304Mindy Pereira
1346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Static colors.
1355750406080090ed22bf93036525c2ff30f41b28aJames Lemieux    private static int sSendersTextColor;
1361c6d71b47e7af11b3cf7bd6da4a89594941be968James Lemieux    private static int sDateTextColorRead;
1371c6d71b47e7af11b3cf7bd6da4a89594941be968James Lemieux    private static int sDateTextColorUnread;
138ce2c0a15773909bfd09935673c4974b5922eba68Alice Yang    private static int sStarTouchSlop;
139ce2c0a15773909bfd09935673c4974b5922eba68Alice Yang    private static int sSenderImageTouchSlop;
140067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private static int sShrinkAnimationDuration;
141067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private static int sSlideAnimationDuration;
1421fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy    private static int sCabAnimationDuration;
143be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private static int sBadgePaddingExtraWidth;
144be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private static int sBadgeRoundedCornerRadius;
1456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Static paints.
1471fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy    private static final TextPaint sPaint = new TextPaint();
1481fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy    private static final TextPaint sFoldersPaint = new TextPaint();
1491fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy    private static final Paint sCheckBackgroundPaint = new Paint();
150cace3194e9b7b0e2b6554bda2fa8b2f98da04175James Lemieux    private static final Paint sDividerPaint = new Paint();
151cace3194e9b7b0e2b6554bda2fa8b2f98da04175James Lemieux
152cace3194e9b7b0e2b6554bda2fa8b2f98da04175James Lemieux    private static int sDividerHeight;
1536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
154a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein    private static BroadcastReceiver sConfigurationChangedReceiver;
155a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
1566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Backgrounds for different states.
1576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private final SparseArray<Drawable> mBackgrounds = new SparseArray<Drawable>();
1586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Dimensions and coordinates.
1606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mViewWidth = -1;
1610d1ed12c6e70f4204ff28092ed51ce540f9f3f67Vikram Aggarwal    /** The view mode at which we calculated mViewWidth previously. */
1620d1ed12c6e70f4204ff28092ed51ce540f9f3f67Vikram Aggarwal    private int mPreviousMode;
163479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
16452b280a82df262f62632bd12bba84b4752f14634Scott Kennedy    private int mInfoIconX;
1656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mDateX;
166a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein    private int mDateWidth;
1676f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mPaperclipX;
168a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein    private int mSendersX;
1696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mSendersWidth;
1706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
171fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal    /** Whether we are on a tablet device or not */
172fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal    private final boolean mTabletDevice;
173f0aebd32d750d6e108c8f9b551b1760682123ebbAndy Huang    /** When in conversation mode, true if the list is hidden */
174f0aebd32d750d6e108c8f9b551b1760682123ebbAndy Huang    private final boolean mListCollapsible;
1756f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1766f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @VisibleForTesting
1770944e5e69312666b89fda025430b7cf03bca4305Mindy Pereira    ConversationItemViewCoordinates mCoordinates;
1786f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
179fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    private ConversationItemViewCoordinates.Config mConfig;
180fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
1816f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private final Context mContext;
1826f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1833dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao    private ConversationItemViewModel mHeader;
184c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    private boolean mDownEvent;
185ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    private boolean mChecked = false;
186ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    private ConversationCheckedSet mCheckedConversationSet;
1874584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    private Folder mDisplayedFolder;
1880a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei    private boolean mStarEnabled;
189f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira    private boolean mSwipeEnabled;
190a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux    private boolean mDividerEnabled;
191bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook    private AnimatedAdapter mAdapter;
192370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    private float mAnimatedHeightFraction = 1.0f;
1933dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao    private final Account mAccount;
194e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira    private ControllableActivity mActivity;
19547cb510ea11c8886434575118068fc91eaa25facMark Wei    private final TextView mSendersTextView;
196928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux    private final TextView mSubjectTextView;
197928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux    private final TextView mSnippetTextView;
1984758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang    private int mGadgetMode;
199479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
200ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao    private static int sFoldersMaxCount;
2016a4c4f62db0ddf6660d889bf1f21e37d25a99363mindyp    private static TextAppearanceSpan sSubjectTextUnreadSpan;
2022615aea2ce57f5fa3a9cd2e672282818aee6ce94mindyp    private static TextAppearanceSpan sSubjectTextReadSpan;
203be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private static TextAppearanceSpan sBadgeTextSpan;
204be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private static BackgroundColorSpan sBadgeBackgroundSpan;
205d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp    private static int sScrollSlop;
2065d07da885ae9d4fdd373995f9c67e2d8f6ebaab9Vikram Aggarwal    private static CharacterStyle sActivatedTextSpan;
207479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
2085f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux    private final CheckableContactFlipDrawable mSendersImageView;
20979c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
210103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy    /** The resource id of the color to use to override the background. */
211103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy    private int mBackgroundOverrideResId = -1;
212103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy    /** The bitmap to use, or <code>null</code> for the default */
213103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy    private Bitmap mPhotoBitmap = null;
214c12da4a53eee911765975f0d8afe62f749806b60Jin Cao    private Rect mPhotoRect = new Rect();
215103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy
216d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    /**
217d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy     * A listener for clicks on the various areas of a conversation item.
218d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy     */
219d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    public interface ConversationItemAreaClickListener {
220d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        /** Called when the info icon is clicked. */
221d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        void onInfoIconClicked();
222d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
223d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        /** Called when the star is clicked. */
224d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        void onStarClicked();
225d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    }
226d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
227d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    /** If set, it will steal all clicks for which the interface has a click method. */
228d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    private ConversationItemAreaClickListener mConversationItemAreaClickListener = null;
229d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
2306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    static {
2316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setAntiAlias(true);
23230fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira        sFoldersPaint.setAntiAlias(true);
2331fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy
2341fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy        sCheckBackgroundPaint.setColor(Color.GRAY);
2356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
2366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
237b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira    /**
238b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira     * Handles displaying folders in a conversation header view.
239b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira     */
240b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira    static class ConversationItemFolderDisplayer extends FolderDisplayer {
2414eb909e1ef9656dfc06d2518842357827dcfb068Jin Cao        private final BidiFormatter mFormatter;
242b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        private int mFoldersCount;
243b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
2444eb909e1ef9656dfc06d2518842357827dcfb068Jin Cao        public ConversationItemFolderDisplayer(Context context, BidiFormatter formatter) {
245c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            super(context);
2464eb909e1ef9656dfc06d2518842357827dcfb068Jin Cao            mFormatter = formatter;
247c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang        }
248c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang
249b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        @Override
2505edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao        protected void initializeDrawableResources() {
2515edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            super.initializeDrawableResources();
2525edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            final Resources res = mContext.getResources();
2535edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            mFolderDrawableResources.overflowGradientPadding =
2545edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    res.getDimensionPixelOffset(R.dimen.folder_tl_gradient_padding);
2555edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            mFolderDrawableResources.folderHorizontalPadding =
2565edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    res.getDimensionPixelOffset(R.dimen.folder_tl_cell_content_padding);
2575edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            mFolderDrawableResources.folderFontSize =
2585edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    res.getDimensionPixelOffset(R.dimen.folder_tl_font_size);
2595edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao        }
2605edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao
2615edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao        @Override
262259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy        public void loadConversationFolders(Conversation conv, final FolderUri ignoreFolderUri,
26367aa9e5162a15fb8b46b4113ac627cd20668f095Scott Kennedy                final int ignoreFolderType) {
26467aa9e5162a15fb8b46b4113ac627cd20668f095Scott Kennedy            super.loadConversationFolders(conv, ignoreFolderUri, ignoreFolderType);
265c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            mFoldersCount = mFoldersSortedSet.size();
266b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
267b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
26869495b0a5551aaf4b70b6b29348946b730cfc3e8mindyp        @Override
26969495b0a5551aaf4b70b6b29348946b730cfc3e8mindyp        public void reset() {
27069495b0a5551aaf4b70b6b29348946b730cfc3e8mindyp            super.reset();
27169495b0a5551aaf4b70b6b29348946b730cfc3e8mindyp            mFoldersCount = 0;
27269495b0a5551aaf4b70b6b29348946b730cfc3e8mindyp        }
27369495b0a5551aaf4b70b6b29348946b730cfc3e8mindyp
274b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        public boolean hasVisibleFolders() {
275b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            return mFoldersCount > 0;
276b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
277b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
278ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao        /**
279ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao         * @return how much total space the folders list requires.
280ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao         */
281ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao        private int measureFolders(ConversationItemViewCoordinates coordinates) {
2825edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            final int[] measurements = measureFolderDimen(
2835edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    mFoldersSortedSet, coordinates.folderCellWidth, coordinates.folderLayoutWidth,
2845edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    mFolderDrawableResources.folderInBetweenPadding,
2855edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    mFolderDrawableResources.folderHorizontalPadding, sFoldersMaxCount,
2865edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    sFoldersPaint);
2875edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            return sumWidth(measurements);
288ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao        }
289ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao
290ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao        private int sumWidth(int[] arr) {
291ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            int sum = 0;
2925edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            for (int i : arr) {
2935edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                sum += i;
294ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            }
2955edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            return sum + (arr.length - 1) * mFolderDrawableResources.folderInBetweenPadding;
296b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
297b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
2985edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao        public void drawFolders(Canvas canvas, ConversationItemViewCoordinates coordinates,
2995edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                boolean isRtl) {
300b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            if (mFoldersCount == 0) {
301b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                return;
302b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            }
303ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao
3045edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            final int[] measurements = measureFolderDimen(
3055edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    mFoldersSortedSet, coordinates.folderCellWidth, coordinates.folderLayoutWidth,
3065edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    mFolderDrawableResources.folderInBetweenPadding,
3075edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    mFolderDrawableResources.folderHorizontalPadding, sFoldersMaxCount,
3085edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                    sFoldersPaint);
309ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao
310a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            final int right = coordinates.foldersRight;
311fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            final int y = coordinates.foldersY;
31295f9e1b167f4945adfa4ca62f4b72a102b621794mindyp
313b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            sFoldersPaint.setTextSize(coordinates.foldersFontSize);
314fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            sFoldersPaint.setTypeface(coordinates.foldersTypeface);
315b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
316b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            // Initialize space and cell size based on the current mode.
3176fce8bb099fc38a68b96486921e9bf03a5b095d4Jin Cao            final Paint.FontMetricsInt fm = sFoldersPaint.getFontMetricsInt();
318ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            final int foldersCount = measurements.length;
319ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            final int width = sumWidth(measurements);
3206fce8bb099fc38a68b96486921e9bf03a5b095d4Jin Cao            final int height = fm.bottom - fm.top;
3216adc0bf59acb0e633d0063f16085c286b8423e1bJin Cao            int xStart = (isRtl) ? coordinates.snippetX + width : right - width;
322ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao
323ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            int index = 0;
3245edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao            for (Folder folder : mFoldersSortedSet) {
325ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao                if (index > foldersCount - 1) {
326fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                    break;
327fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                }
328ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao
3295edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                final int actualStart = isRtl ? xStart - measurements[index] : xStart;
3305edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                drawFolder(canvas, actualStart, y, measurements[index], height, folder,
3315edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                        mFolderDrawableResources, mFormatter, sFoldersPaint);
332b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
3336adc0bf59acb0e633d0063f16085c286b8423e1bJin Cao                // Increment the starting position accordingly for the next item
3345edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                final int usedWidth = measurements[index++] +
3355edf5fd7327691b73dcb57c3cba340fd25576d18Jin Cao                        mFolderDrawableResources.folderInBetweenPadding;
3366adc0bf59acb0e633d0063f16085c286b8423e1bJin Cao                xStart += (isRtl) ? -usedWidth : usedWidth;
337ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            }
338ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao        }
3392cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao
3402cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao        public @Nullable String getFoldersDesc() {
3412cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao            if (mFoldersSortedSet != null && !mFoldersSortedSet.isEmpty()) {
3422cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                final StringBuilder builder = new StringBuilder();
3432cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                final String comma = mContext.getString(R.string.enumeration_comma);
3442cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                for (Folder f : mFoldersSortedSet) {
3452cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                    builder.append(f.name).append(comma);
3462cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                }
3472cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                return builder.toString();
3482cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao            }
3492cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao            return null;
3502cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao        }
351acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
352b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
3533dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao    public ConversationItemView(Context context, Account account) {
3546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        super(context);
355479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("CIVC constructor");
356960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        setClickable(true);
357960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        setLongClickable(true);
3586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mContext = context.getApplicationContext();
359bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal        final Resources res = mContext.getResources();
360bcb16b98140a83a4db3c51568d21c839595f73dfVikram Aggarwal        mTabletDevice = Utils.useTabletUI(res);
36177db7fda313ed4c001eb05fb6b619f9f2798c635Rohan Shah        mListCollapsible = !res.getBoolean(R.bool.is_tablet_landscape);
362c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira        mAccount = account;
3636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
364a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        getItemViewResources(mContext);
365a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
366928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        final int layoutDir = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault());
367928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux
368a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        mSendersTextView = new TextView(mContext);
369a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        mSendersTextView.setIncludeFontPadding(false);
370a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
371a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        mSubjectTextView = new TextView(mContext);
372a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        mSubjectTextView.setEllipsize(TextUtils.TruncateAt.END);
373a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        mSubjectTextView.setIncludeFontPadding(false);
374928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        ViewCompat.setLayoutDirection(mSubjectTextView, layoutDir);
375928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        ViewUtils.setTextAlignment(mSubjectTextView, View.TEXT_ALIGNMENT_VIEW_START);
376a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
377928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView = new TextView(mContext);
378928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView.setEllipsize(TextUtils.TruncateAt.END);
379928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView.setIncludeFontPadding(false);
380f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux        mSnippetTextView.setTypeface(SANS_SERIF_LIGHT);
381f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux        mSnippetTextView.setTextColor(getResources().getColor(R.color.snippet_text_color));
382928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        ViewCompat.setLayoutDirection(mSnippetTextView, layoutDir);
383928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        ViewUtils.setTextAlignment(mSnippetTextView, View.TEXT_ALIGNMENT_VIEW_START);
384a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
385f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein        // hack for b/16345519. Root cause is b/17280038.
386f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein        if (layoutDir == LAYOUT_DIRECTION_RTL) {
387f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein            mSubjectTextView.setMaxLines(1);
388f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein            mSnippetTextView.setMaxLines(1);
389f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein        } else {
390f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein            mSubjectTextView.setSingleLine();
391f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein            mSnippetTextView.setSingleLine();
392f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein        }
393f06f4b7bf661125a822606b626de1ab7dbdb188dAndrew Sapperstein
3945f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux        mSendersImageView = new CheckableContactFlipDrawable(res, sCabAnimationDuration);
395a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        mSendersImageView.setCallback(this);
396a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
397a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        Utils.traceEndSection();
398a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein    }
399a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein
400a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein    private static synchronized void getItemViewResources(Context context) {
401a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        if (sConfigurationChangedReceiver == null) {
402a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein            sConfigurationChangedReceiver = new BroadcastReceiver() {
403a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein                @Override
404a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein                public void onReceive(Context context, Intent intent) {
405a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein                    STAR_OFF = null;
406a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein                    getItemViewResources(context);
407a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein                }
408a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein            };
409a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein            context.registerReceiver(sConfigurationChangedReceiver, new IntentFilter(
410a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein                    Intent.ACTION_CONFIGURATION_CHANGED));
411a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein        }
4124758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang        if (STAR_OFF == null) {
413a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein            final Resources res = context.getResources();
4146f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Initialize static bitmaps.
415eb58a092961773a8da67c0e0dd5770346381d938Andrew Sapperstein            STAR_OFF = BitmapFactory.decodeResource(res, R.drawable.ic_star_outline_20dp);
416eb58a092961773a8da67c0e0dd5770346381d938Andrew Sapperstein            STAR_ON = BitmapFactory.decodeResource(res, R.drawable.ic_star_20dp);
417091484627a207de3fceea8727439082b022748aeJames Lemieux            ATTACHMENT = BitmapFactory.decodeResource(res, R.drawable.ic_attach_file_18dp);
4184a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang            ONLY_TO_ME = BitmapFactory.decodeResource(res, R.drawable.ic_email_caret_double);
4194a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang            TO_ME_AND_OTHERS = BitmapFactory.decodeResource(res, R.drawable.ic_email_caret_single);
4204a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang            IMPORTANT_ONLY_TO_ME = BitmapFactory.decodeResource(res,
4214a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang                    R.drawable.ic_email_caret_double_important_unread);
4224a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang            IMPORTANT_TO_ME_AND_OTHERS = BitmapFactory.decodeResource(res,
4234a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang                    R.drawable.ic_email_caret_single_important_unread);
42417646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            IMPORTANT = BitmapFactory.decodeResource(res,
4254a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang                    R.drawable.ic_email_caret_none_important_unread);
42654467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            STATE_REPLIED =
42754467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_reply_holo_light);
42854467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            STATE_FORWARDED =
42954467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_forward_holo_light);
43054467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            STATE_REPLIED_AND_FORWARDED =
43154467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_reply_forward_holo_light);
4328d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira            STATE_CALENDAR_INVITE =
4338d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_invite_holo_light);
4340532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            FOCUSED_CONVERSATION_HIGHLIGHT = res.getDrawable(
435f58e4c3c942033fce12b5f75f9e4d9e708c9ea6aAndy Huang                    R.drawable.visible_conversation_highlight);
4366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Initialize colors.
438371e0ad5de82585a0a0613ac5410c9ead65613caTony Mantler            sActivatedTextSpan = CharacterStyle.wrap(new ForegroundColorSpan(
4395750406080090ed22bf93036525c2ff30f41b28aJames Lemieux                    res.getColor(R.color.senders_text_color)));
4405750406080090ed22bf93036525c2ff30f41b28aJames Lemieux            sSendersTextColor = res.getColor(R.color.senders_text_color);
441a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein            sSubjectTextUnreadSpan = new TextAppearanceSpan(context,
4426a4c4f62db0ddf6660d889bf1f21e37d25a99363mindyp                    R.style.SubjectAppearanceUnreadStyle);
443f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux            sSubjectTextReadSpan = new TextAppearanceSpan(
444f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux                    context, R.style.SubjectAppearanceReadStyle);
445f75cf1157b7168cd4c501b1b34ad473e2ab724f0James Lemieux
446a5dfa98bbafd402fa15c32efe4a0b55ebdfd7d11Andrew Sapperstein            sBadgeTextSpan = new TextAppearanceSpan(context, R.style.BadgeTextStyle);
447be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            sBadgeBackgroundSpan = new BackgroundColorSpan(
448be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    res.getColor(R.color.badge_background_color));
4491c6d71b47e7af11b3cf7bd6da4a89594941be968James Lemieux            sDateTextColorRead = res.getColor(R.color.date_text_color_read);
4501c6d71b47e7af11b3cf7bd6da4a89594941be968James Lemieux            sDateTextColorUnread = res.getColor(R.color.date_text_color_unread);
451ce2c0a15773909bfd09935673c4974b5922eba68Alice Yang            sStarTouchSlop = res.getDimensionPixelSize(R.dimen.star_touch_slop);
452ce2c0a15773909bfd09935673c4974b5922eba68Alice Yang            sSenderImageTouchSlop = res.getDimensionPixelSize(R.dimen.sender_image_touch_slop);
453067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            sShrinkAnimationDuration = res.getInteger(R.integer.shrink_animation_duration);
454067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            sSlideAnimationDuration = res.getInteger(R.integer.slide_animation_duration);
4556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Initialize static color.
456ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSendersSplitToken = res.getString(R.string.senders_split_token);
457ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sElidedPaddingToken = res.getString(R.string.elided_padding_token);
458d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp            sScrollSlop = res.getInteger(R.integer.swipeScrollSlop);
459ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao            sFoldersMaxCount = res.getInteger(R.integer.conversation_list_max_folder_count);
460a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            sCabAnimationDuration = res.getInteger(R.integer.conv_item_view_cab_anim_duration);
461be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            sBadgePaddingExtraWidth = res.getDimensionPixelSize(R.dimen.badge_padding_extra_width);
462be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            sBadgeRoundedCornerRadius =
463be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    res.getDimensionPixelSize(R.dimen.badge_rounded_corner_radius);
464a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux            sDividerPaint.setColor(res.getColor(R.color.divider_color));
465cace3194e9b7b0e2b6554bda2fa8b2f98da04175James Lemieux            sDividerHeight = res.getDimensionPixelSize(R.dimen.divider_height);
466a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        }
4676f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
4686f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
469aa76bdfae889b995395a7636742128b3585727f9Mark Wei    public void bind(final Conversation conversation, final ControllableActivity activity,
470ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            final ConversationCheckedSet set, final Folder folder,
4710e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux            final int checkboxOrSenderImage,
47217646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            final boolean swipeEnabled, final boolean importanceMarkersEnabled,
473f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            final boolean showChevronsEnabled, final AnimatedAdapter adapter) {
474479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("CIVC.bind");
4753dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao        bind(ConversationItemViewModel.forConversation(mAccount.getEmailAddress(), conversation),
4763dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao                activity, null /* conversationItemAreaClickListener */,
4770e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                set, folder, checkboxOrSenderImage, swipeEnabled, importanceMarkersEnabled,
4780e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                showChevronsEnabled, adapter, -1 /* backgroundOverrideResId */,
479a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux                null /* photoBitmap */, false /* useFullMargins */, true /* mDividerEnabled */);
480103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        Utils.traceEndSection();
481103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy    }
482103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy
483103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy    public void bindAd(final ConversationItemViewModel conversationItemViewModel,
484103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy            final ControllableActivity activity,
485d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            final ConversationItemAreaClickListener conversationItemAreaClickListener,
486d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            final Folder folder, final int checkboxOrSenderImage, final AnimatedAdapter adapter,
487cc8ed8dca4080649c4fff3f6b0e3b35dbf0145f2Scott Kennedy            final int backgroundOverrideResId, final Bitmap photoBitmap) {
488103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        Utils.traceBeginSection("CIVC.bindAd");
489a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        bind(conversationItemViewModel, activity, conversationItemAreaClickListener, null /* set */,
4900e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                folder, checkboxOrSenderImage, true /* swipeEnabled */,
49117646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                false /* importanceMarkersEnabled */, false /* showChevronsEnabled */,
492a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux                adapter, backgroundOverrideResId, photoBitmap, true /* useFullMargins */,
493a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux                false /* mDividerEnabled */);
494479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceEndSection();
495acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
496acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
497aa76bdfae889b995395a7636742128b3585727f9Mark Wei    private void bind(final ConversationItemViewModel header, final ControllableActivity activity,
498d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            final ConversationItemAreaClickListener conversationItemAreaClickListener,
499ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            final ConversationCheckedSet set, final Folder folder,
5000e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux            final int checkboxOrSenderImage,
50117646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            boolean swipeEnabled, final boolean importanceMarkersEnabled,
50217646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            final boolean showChevronsEnabled, final AnimatedAdapter adapter,
503be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final int backgroundOverrideResId, final Bitmap photoBitmap,
504a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux            final boolean useFullMargins, final boolean dividerEnabled) {
505103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        mBackgroundOverrideResId = backgroundOverrideResId;
506103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        mPhotoBitmap = photoBitmap;
507d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        mConversationItemAreaClickListener = conversationItemAreaClickListener;
508a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux        mDividerEnabled = dividerEnabled;
509103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy
510f832d5f8b490e184d0c9cd70bba8f32ed29ff51amindyp        if (mHeader != null) {
511a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            Utils.traceBeginSection("unbind");
512a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            final boolean newlyBound = header.conversation.id != mHeader.conversation.id;
513479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            // If this was previously bound to a different conversation, remove any contact photo
514479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            // manager requests.
5153dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao            if (newlyBound || (!mHeader.displayableNames.equals(header.displayableNames))) {
5165f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux                mSendersImageView.getContactDrawable().unbind();
517479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            }
518479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
519a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            if (newlyBound) {
5208c843a7610fed6ecd8e4e6d9f43c4eea2a7ff3a1Scott Kennedy                // Stop the photo flip animation
521ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao                final boolean showSenders = !mChecked;
522a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei                mSendersImageView.reset(showSenders);
5238c843a7610fed6ecd8e4e6d9f43c4eea2a7ff3a1Scott Kennedy            }
524a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            Utils.traceEndSection();
525f832d5f8b490e184d0c9cd70bba8f32ed29ff51amindyp        }
526b53fe05fb867685d0d3f2f37daf0f93bc6488dedAndy Huang        mCoordinates = null;
527acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        mHeader = header;
528e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        mActivity = activity;
529ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        mCheckedConversationSet = set;
530ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mCheckedConversationSet != null) {
531ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            mCheckedConversationSet.addObserver(this);
532f1566b1e77e9d7ac66ebb47897b5c652e2b18943Andrew Sapperstein        }
533b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        mDisplayedFolder = folder;
53498aeca3818c3b696f304c1bfb5657a1e1f277a04Paul Westbrook        mStarEnabled = folder != null && !folder.isTrash();
535f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        mSwipeEnabled = swipeEnabled;
536bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook        mAdapter = adapter;
537a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
538a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceBeginSection("drawables");
5395f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux        mSendersImageView.getContactDrawable().setBitmapCache(mAdapter.getSendersImagesCache());
5405f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux        mSendersImageView.getContactDrawable().setContactResolver(mAdapter.getContactResolver());
541a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
542fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
5434758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang        if (checkboxOrSenderImage == ConversationListIcon.SENDER_IMAGE) {
5444758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang            mGadgetMode = ConversationItemViewCoordinates.GADGET_CONTACT_PHOTO;
545fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        } else {
5464758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang            mGadgetMode = ConversationItemViewCoordinates.GADGET_NONE;
547fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
548fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
549a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceBeginSection("folder displayer");
550fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        // Initialize folder displayer.
551fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (mHeader.folderDisplayer == null) {
5524eb909e1ef9656dfc06d2518842357827dcfb068Jin Cao            mHeader.folderDisplayer = new ConversationItemFolderDisplayer(mContext,
5534eb909e1ef9656dfc06d2518842357827dcfb068Jin Cao                    mAdapter.getBidiFormatter());
554fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        } else {
555fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mHeader.folderDisplayer.reset();
556fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
557a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
558fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
559fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        final int ignoreFolderType;
560fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (mDisplayedFolder.isInbox()) {
561fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            ignoreFolderType = FolderType.INBOX;
562fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        } else {
563fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            ignoreFolderType = -1;
564fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
565fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
566a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceBeginSection("load folders");
567259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy        mHeader.folderDisplayer.loadConversationFolders(mHeader.conversation,
568259df5b9e11908c8ef7c91483924891dd96b3c27Scott Kennedy                mDisplayedFolder.folderUri, ignoreFolderType);
569a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
570fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
571be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        if (mHeader.showDateText) {
572a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            Utils.traceBeginSection("relative time");
573103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy            mHeader.dateText = DateUtils.getRelativeTimeSpanString(mContext,
574103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy                    mHeader.conversation.dateMs);
575a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            Utils.traceEndSection();
576103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        } else {
577be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            mHeader.dateText = "";
578103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        }
579fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
580a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceBeginSection("config setup");
581fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        mConfig = new ConversationItemViewCoordinates.Config()
5824758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang            .withGadget(mGadgetMode)
583be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            .setUseFullMargins(useFullMargins);
584fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (header.folderDisplayer.hasVisibleFolders()) {
585fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mConfig.showFolders();
586fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
587fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (header.hasBeenForwarded || header.hasBeenRepliedTo || header.isInvite) {
588fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mConfig.showReplyState();
589fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
590fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (mHeader.conversation.color != 0) {
591fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mConfig.showColorBlock();
592fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        }
593a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
59417646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        // Importance markers and chevrons (personal level indicators).
5954a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang        mHeader.personalLevelBitmap = null;
59617646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        final int personalLevel = mHeader.conversation.personalLevel;
59717646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        final boolean isImportant =
59817646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                mHeader.conversation.priority == UIProvider.ConversationPriority.IMPORTANT;
59917646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        final boolean useImportantMarkers = isImportant && importanceMarkersEnabled;
60017646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        if (showChevronsEnabled &&
60117646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                personalLevel == UIProvider.ConversationPersonalLevel.ONLY_TO_ME) {
60217646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            mHeader.personalLevelBitmap = useImportantMarkers ? IMPORTANT_ONLY_TO_ME
60317646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                    : ONLY_TO_ME;
60417646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        } else if (showChevronsEnabled &&
60517646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                personalLevel == UIProvider.ConversationPersonalLevel.TO_ME_AND_OTHERS) {
60617646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            mHeader.personalLevelBitmap = useImportantMarkers ? IMPORTANT_TO_ME_AND_OTHERS
60717646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                    : TO_ME_AND_OTHERS;
60817646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        } else if (useImportantMarkers) {
60917646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein            mHeader.personalLevelBitmap = IMPORTANT;
6104a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang        }
6114a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang        if (mHeader.personalLevelBitmap != null) {
6124a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang            mConfig.showPersonalIndicator();
6134a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang        }
614a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
615fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
616a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceBeginSection("content description");
617ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp        setContentDescription();
618a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
619f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira        requestLayout();
620f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira    }
621f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira
62279c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang    @Override
623f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei    protected void onDetachedFromWindow() {
624f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei        super.onDetachedFromWindow();
625f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei
626ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mCheckedConversationSet != null) {
627ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            mCheckedConversationSet.removeObserver(this);
628f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei        }
629f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei    }
630f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei
631f4ff7675cbc23c56b9b35f9f26574afef030f0afMark Wei    @Override
632a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    public void invalidateDrawable(final Drawable who) {
63379c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        boolean handled = false;
63479c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        if (mCoordinates != null) {
6350e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux            if (mSendersImageView.equals(who)) {
636a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei                final Rect r = new Rect(who.getBounds());
637a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei                r.offset(mCoordinates.contactImagesX, mCoordinates.contactImagesY);
638a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei                ConversationItemView.this.invalidate(r.left, r.top, r.right, r.bottom);
639a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei                handled = true;
64079c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang            }
64179c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        }
64279c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        if (!handled) {
64379c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang            super.invalidateDrawable(who);
64479c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        }
64579c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang    }
64679c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
647866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
648866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * Get the Conversation object associated with this view.
649866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
650732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang    public Conversation getConversation() {
651732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang        return mHeader.conversation;
652732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang    }
653732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang
6546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static void startTimer(String tag) {
6556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (sTimer != null) {
6566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer.start(tag);
6576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
6586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
6596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static void pauseTimer(String tag) {
6616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (sTimer != null) {
6626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer.pause(tag);
6636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
6646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
6656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6666f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @Override
667fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
668479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("CIVC.measure");
669fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        final int wSize = MeasureSpec.getSize(widthMeasureSpec);
6706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6710d1ed12c6e70f4204ff28092ed51ce540f9f3f67Vikram Aggarwal        final int currentMode = mActivity.getViewMode().getMode();
672fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (wSize != mViewWidth || mPreviousMode != currentMode) {
673fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mViewWidth = wSize;
6740d1ed12c6e70f4204ff28092ed51ce540f9f3f67Vikram Aggarwal            mPreviousMode = currentMode;
6756f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
6766f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.viewWidth = mViewWidth;
677fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
6784958af88fe77f0c5c92ab0f7e1e6cbba645c3180James Lemieux        mConfig.updateWidth(wSize).setLayoutDirection(ViewCompat.getLayoutDirection(this));
679fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
6806f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        Resources res = getResources();
6816f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.standardScaledDimen = res.getDimensionPixelOffset(R.dimen.standard_scaled_dimen);
682fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
683fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        mCoordinates = ConversationItemViewCoordinates.forConfig(mContext, mConfig,
684fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                mAdapter.getCoordinatesCache());
685fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
686103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        if (mPhotoBitmap != null) {
687c12da4a53eee911765975f0d8afe62f749806b60Jin Cao            mPhotoRect.set(0, 0, mCoordinates.contactImagesWidth, mCoordinates.contactImagesHeight);
688103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        }
689103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy
690370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        final int h = (mAnimatedHeightFraction != 1.0f) ?
691370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                Math.round(mAnimatedHeightFraction * mCoordinates.height) : mCoordinates.height;
692fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        setMeasuredDimension(mConfig.getWidth(), h);
693479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceEndSection();
694fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
695fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
696fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    @Override
697fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
698fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        startTimer(PERF_TAG_LAYOUT);
699f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceBeginSection("CIVC.layout");
700fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
701fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        super.onLayout(changed, left, top, right, bottom);
702fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
7032229eddfba6f7517c43ef49ee67c50c24d4b961aMark Wei        Utils.traceBeginSection("text and bitmaps");
7046f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        calculateTextsAndBitmaps();
7052229eddfba6f7517c43ef49ee67c50c24d4b961aMark Wei        Utils.traceEndSection();
7062229eddfba6f7517c43ef49ee67c50c24d4b961aMark Wei
7072229eddfba6f7517c43ef49ee67c50c24d4b961aMark Wei        Utils.traceBeginSection("coordinates");
7086f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        calculateCoordinates();
7092229eddfba6f7517c43ef49ee67c50c24d4b961aMark Wei        Utils.traceEndSection();
710167bddc283a66f210e0484eeca609f4e7f35dac4mindyp
711167bddc283a66f210e0484eeca609f4e7f35dac4mindyp        // Subject.
712a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceBeginSection("subject");
7139e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy        createSubject(mHeader.unread);
714167bddc283a66f210e0484eeca609f4e7f35dac4mindyp
715928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        createSnippet();
716be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
7173b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy        if (!mHeader.isLayoutValid()) {
718ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp            setContentDescription();
719dc0617f3478b21dd3324ab10b8c433517ae95460mindyp        }
7203b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy        mHeader.validate();
721a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
7226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
7236f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        pauseTimer(PERF_TAG_LAYOUT);
7246f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (sTimer != null && ++sLayoutCount >= PERF_LAYOUT_ITERATIONS) {
7256f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer.dumpResults();
7266f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer = new Timer();
7276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sLayoutCount = 0;
7286f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
729f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceEndSection();
7306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
7316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
732ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp    private void setContentDescription() {
7332cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao        String foldersDesc = null;
7342cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao        if (mHeader != null && mHeader.folderDisplayer != null) {
7352cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao            foldersDesc = mHeader.folderDisplayer.getFoldersDesc();
7362cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao        }
7372cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao
738ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp        if (mActivity.isAccessibilityEnabled()) {
739ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp            mHeader.resetContentDescription();
7402cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao            setContentDescription(mHeader.getContentDescription(
7412cff0881131d3cd4469d3494a3f7bf0ee3f2f09eJin Cao                    mContext, mDisplayedFolder.shouldShowRecipients(), foldersDesc));
742ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp        }
743ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp    }
744ca87de41285bde382a894b6cb2d13c112c5d7a2fmindyp
7456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @Override
7466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    public void setBackgroundResource(int resourceId) {
747479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("set background resource");
7486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        Drawable drawable = mBackgrounds.get(resourceId);
7496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (drawable == null) {
7506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            drawable = getResources().getDrawable(resourceId);
751be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            final int insetPadding = mHeader.insetPadding;
752be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            if (insetPadding > 0) {
753be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                drawable = new InsetDrawable(drawable, insetPadding);
754be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            }
7556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mBackgrounds.put(resourceId, drawable);
7566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
7576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (getBackground() != drawable) {
758f5de30d2bccf2e5eaace2424ad91784c43d42075Jin Cao            super.setBackgroundDrawable(drawable);
7596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
760479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceEndSection();
7616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
7626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
7636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void calculateTextsAndBitmaps() {
7646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
765f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp
766ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mCheckedConversationSet != null) {
767ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            setChecked(mCheckedConversationSet.contains(mHeader.conversation));
768d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal        }
7694758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang        mHeader.gadgetMode = mGadgetMode;
7706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
771be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        updateBackground();
7726f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
773f27e08e98db1496610c9f216ef6eeb26c39c2da3Scott Kennedy        mHeader.hasDraftMessage = mHeader.conversation.numDrafts() > 0;
774f27e08e98db1496610c9f216ef6eeb26c39c2da3Scott Kennedy
7758335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp        // Parse senders fragments.
7763b2039afbcd8465ab829ecda8a5b207e988e773cScott Kennedy        if (mHeader.preserveSendersText) {
7773b2039afbcd8465ab829ecda8a5b207e988e773cScott Kennedy            // This is a special view that doesn't need special sender formatting
7783b2039afbcd8465ab829ecda8a5b207e988e773cScott Kennedy            mHeader.sendersDisplayText = new SpannableStringBuilder(mHeader.sendersText);
7793b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux            loadImages();
7803b2039afbcd8465ab829ecda8a5b207e988e773cScott Kennedy        } else if (mHeader.conversation.conversationInfo != null) {
7818335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp            Context context = getContext();
7828335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp            mHeader.messageInfoString = SendersView
783d5fd04656f364a209703a67debc33d91dabfb83fScott Kennedy                    .createMessageInfo(context, mHeader.conversation, true);
7844958af88fe77f0c5c92ab0f7e1e6cbba645c3180James Lemieux            final int maxChars = ConversationItemViewCoordinates.getSendersLength(context,
7854958af88fe77f0c5c92ab0f7e1e6cbba645c3180James Lemieux                    mHeader.conversation.hasAttachments);
7863dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao
7873dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao            mHeader.mSenderAvatarModel.clear();
7883dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao            mHeader.displayableNames.clear();
7893dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao            mHeader.styledNames.clear();
7903b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux
79188acafa03a87f5c84b959697d13b81df8f11a96emindyp            SendersView.format(context, mHeader.conversation.conversationInfo,
7923b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux                    mHeader.messageInfoString.toString(), maxChars, mHeader.styledNames,
7933dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao                    mHeader.displayableNames, mHeader.mSenderAvatarModel,
794c9e00fcb05c5311633dc3a414b9bf685816b4350James Lemieux                    mAccount, mDisplayedFolder.shouldShowRecipients(), true);
795f27e08e98db1496610c9f216ef6eeb26c39c2da3Scott Kennedy
796d198fa7ddb2d0c730847af34f06aa2e940b2537dMark Wei            // If we have displayable senders, load their thumbnails
7973b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux            loadImages();
7988335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp        } else {
799edd6c1a2807d2ade930dfd4622707298dc470d64Tony Mantler            LogUtils.wtf(LOG_TAG, "Null conversationInfo");
8008335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp        }
8018335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp
8023b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy        if (mHeader.isLayoutValid()) {
803f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp            pauseTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
804f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp            return;
805f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp        }
806f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp        startTimer(PERF_TAG_CALCULATE_FOLDERS);
807f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp
808f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp
809f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp        pauseTimer(PERF_TAG_CALCULATE_FOLDERS);
810f2caf91209e4e2d4182d6b379a3cd79eed81af71mindyp
8116f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Paper clip icon.
8126f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.paperclip = null;
813732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang        if (mHeader.conversation.hasAttachments) {
8146f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mHeader.paperclip = ATTACHMENT;
8156f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
816d198fa7ddb2d0c730847af34f06aa2e940b2537dMark Wei
8176f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_CALCULATE_SENDER_SUBJECT);
8186f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
8198335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp        pauseTimer(PERF_TAG_CALCULATE_SENDER_SUBJECT);
8208335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp        pauseTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
8218335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp    }
8226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
823fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    // FIXME(ath): maybe move this to bind(). the only dependency on layout is on tile W/H, which
824fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    // is immutable.
8253b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux    private void loadImages() {
826a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        if (mGadgetMode != ConversationItemViewCoordinates.GADGET_CONTACT_PHOTO
8273dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao                || mHeader.mSenderAvatarModel.isNotPopulated()) {
828a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            return;
829a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        }
830a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        if (mCoordinates.contactImagesWidth <= 0 || mCoordinates.contactImagesHeight <= 0) {
831a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            LogUtils.w(LOG_TAG,
8324958af88fe77f0c5c92ab0f7e1e6cbba645c3180James Lemieux                    "Contact image width(%d) or height(%d) is 0",
8334958af88fe77f0c5c92ab0f7e1e6cbba645c3180James Lemieux                    mCoordinates.contactImagesWidth, mCoordinates.contactImagesHeight);
834a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            return;
835a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        }
836479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
837a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        mSendersImageView
838a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei                .setBounds(0, 0, mCoordinates.contactImagesWidth, mCoordinates.contactImagesHeight);
839479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
8405f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux        Utils.traceBeginSection("load sender image");
8415f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux        final ContactDrawable drawable = mSendersImageView.getContactDrawable();
8425f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux        drawable.setDecodeDimensions(mCoordinates.contactImagesWidth,
8435f79af7b356c3a8ecd8cd77fcbde673de9023b50James Lemieux                mCoordinates.contactImagesHeight);
8443dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao        drawable.bind(mHeader.mSenderAvatarModel.getName(),
8453dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao                mHeader.mSenderAvatarModel.getEmailAddress());
846a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        Utils.traceEndSection();
8476d11c8fbca5d54a013d78c85d6eb28f590093e3cmindyp    }
8486d11c8fbca5d54a013d78c85d6eb28f590093e3cmindyp
849fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    private static int makeExactSpecForSize(int size) {
850fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
851fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
852fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
853fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    private static void layoutViewExactly(View v, int w, int h) {
854fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        v.measure(makeExactSpecForSize(w), makeExactSpecForSize(h));
855fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        v.layout(0, 0, w, h);
856fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
857fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
85810ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux    private void layoutParticipantText(SpannableStringBuilder participantText) {
85910ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        if (participantText != null) {
8608335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp            if (isActivated() && showActivatedText()) {
86110ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux                participantText.setSpan(sActivatedTextSpan, 0,
8628335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp                        mHeader.styledMessageInfoStringOffset, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
8638335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp            } else {
86410ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux                participantText.removeSpan(sActivatedTextSpan);
8658335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp            }
866d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang
867fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            final int w = mSendersWidth;
868fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            final int h = mCoordinates.sendersHeight;
869fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mSendersTextView.setLayoutParams(new ViewGroup.LayoutParams(w, h));
870fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mSendersTextView.setMaxLines(mCoordinates.sendersLineCount);
871fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            mSendersTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCoordinates.sendersFontSize);
872fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            layoutViewExactly(mSendersTextView, w, h);
873fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
87410ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            mSendersTextView.setText(participantText);
875c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira        }
8766f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
8776f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
8789e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy    private void createSubject(final boolean isUnread) {
879928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        final String badgeText = mHeader.badgeText == null ? "" : mHeader.badgeText;
88094033deeb31df739a27fce15887a3f0a2e808b12James Lemieux        String subject = filterTag(getContext(), mHeader.conversation.subject);
88131702cbfde9055e528ac43addaf1ab0eb791d900James Lemieux        subject = mAdapter.getBidiFormatter().unicodeWrap(subject);
88294033deeb31df739a27fce15887a3f0a2e808b12James Lemieux        subject = Conversation.getSubjectForDisplay(mContext, badgeText, subject);
88394033deeb31df739a27fce15887a3f0a2e808b12James Lemieux        final Spannable displayedStringBuilder = new SpannableString(subject);
884c046e4a310462aa6998a34ff50439eb5e2508d85mindyp
88531702cbfde9055e528ac43addaf1ab0eb791d900James Lemieux        // since spans affect text metrics, add spans to the string before measure/layout or eliding
886be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
887be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        final int badgeTextLength = formatBadgeText(displayedStringBuilder, badgeText);
888be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
889c244f29b6f9af500fedf8aad48db4c80df52c5c1Scott Kennedy        if (!TextUtils.isEmpty(subject)) {
890c244f29b6f9af500fedf8aad48db4c80df52c5c1Scott Kennedy            displayedStringBuilder.setSpan(TextAppearanceSpan.wrap(
891be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    isUnread ? sSubjectTextUnreadSpan : sSubjectTextReadSpan),
892961aada3d12af6cd31ae620e53358beb7e5d5062James Lemieux                    badgeTextLength, subject.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
893c244f29b6f9af500fedf8aad48db4c80df52c5c1Scott Kennedy        }
8948335d37d0e6b6e06ba4666223945c2a3f24103c1mindyp        if (isActivated() && showActivatedText()) {
895be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            displayedStringBuilder.setSpan(sActivatedTextSpan, badgeTextLength,
896be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    displayedStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
8975d6773c773401a259e6b6db957c34f36c508816bAndy Huang        }
8985d6773c773401a259e6b6db957c34f36c508816bAndy Huang
8995d6773c773401a259e6b6db957c34f36c508816bAndy Huang        final int subjectWidth = mCoordinates.subjectWidth;
900fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        final int subjectHeight = mCoordinates.subjectHeight;
901fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        mSubjectTextView.setLayoutParams(new ViewGroup.LayoutParams(subjectWidth, subjectHeight));
902fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        mSubjectTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCoordinates.subjectFontSize);
903fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        layoutViewExactly(mSubjectTextView, subjectWidth, subjectHeight);
904fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
905fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        mSubjectTextView.setText(displayedStringBuilder);
9066f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
9076f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
908928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux    private void createSnippet() {
909928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        final String snippet = mHeader.conversation.getSnippet();
910928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        final Spannable displayedStringBuilder = new SpannableString(snippet);
911be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
91264f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        // measure the width of the folders which overlap the snippet view
913ff404bb78dec989c1660434915b1b027a2d86bf3Jin Cao        final int folderWidth = mHeader.folderDisplayer.measureFolders(mCoordinates);
91464f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux
91564f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        // size the snippet view by subtracting the folder width from the maximum snippet width
91664f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        final int snippetWidth = mCoordinates.maxSnippetWidth - folderWidth;
917928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        final int snippetHeight = mCoordinates.snippetHeight;
918928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView.setLayoutParams(new ViewGroup.LayoutParams(snippetWidth, snippetHeight));
919928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCoordinates.snippetFontSize);
920928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        layoutViewExactly(mSnippetTextView, snippetWidth, snippetHeight);
921be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
922928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView.setText(displayedStringBuilder);
923be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
924be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
925be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private int formatBadgeText(Spannable displayedStringBuilder, String badgeText) {
926be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        final int badgeTextLength = (badgeText != null) ? badgeText.length() : 0;
927be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        if (!TextUtils.isEmpty(badgeText)) {
928be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            displayedStringBuilder.setSpan(TextAppearanceSpan.wrap(sBadgeTextSpan),
929be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    0, badgeTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
930be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            displayedStringBuilder.setSpan(TextAppearanceSpan.wrap(sBadgeBackgroundSpan),
931be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    0, badgeTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
932be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein            displayedStringBuilder.setSpan(new BadgeSpan(displayedStringBuilder, this),
933be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein                    0, badgeTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
934be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        }
935be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
936be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        return badgeTextLength;
937be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
938be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
939be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    // START BadgeSpan.BadgeSpanDimensions override
940be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
941be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    @Override
942be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    public int getHorizontalPadding() {
943be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        return sBadgePaddingExtraWidth;
944be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
945be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
946be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    @Override
947be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    public float getRoundedCornerRadius() {
948be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein        return sBadgeRoundedCornerRadius;
949be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
950be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
951be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    // END BadgeSpan.BadgeSpanDimensions override
952be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
9530b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    private boolean showActivatedText() {
95497f573d41eb1ab6e0b3683f081452391cf2a76aeVikram Aggarwal        // For activated elements in tablet in conversation mode, we show an activated color, since
95597f573d41eb1ab6e0b3683f081452391cf2a76aeVikram Aggarwal        // the background is dark blue for activated versus gray for non-activated.
9567fdf34185f0d41bdebf25bcf6d14927b16658136Andy Huang        return mTabletDevice && !mListCollapsible;
9570b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    }
9580b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira
9596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void calculateCoordinates() {
9606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_CALCULATE_COORDINATES);
9616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
9626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTextSize(mCoordinates.dateFontSize);
9636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTypeface(Typeface.DEFAULT);
96452b280a82df262f62632bd12bba84b4752f14634Scott Kennedy
965a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        final boolean isRtl = ViewUtils.isViewRtl(this);
966a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein
967a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        mDateWidth = (int) sPaint.measureText(
968a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein                mHeader.dateText != null ? mHeader.dateText.toString() : "");
96952b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        if (mHeader.infoIcon != null) {
970a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            mInfoIconX = (isRtl) ? mCoordinates.infoIconX :
971a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein                    mCoordinates.infoIconXRight - mHeader.infoIcon.getWidth();
97252b280a82df262f62632bd12bba84b4752f14634Scott Kennedy
97352b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            // If we have an info icon, we start drawing the date text:
97452b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            // At the end of the date TextView minus the width of the date text
975a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            // In RTL mode, we just use dateX
976a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            mDateX = (isRtl) ? mCoordinates.dateX : mCoordinates.dateXRight - mDateWidth;
97752b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        } else {
97852b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            // If there is no info icon, we start drawing the date text:
97952b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            // At the end of the info icon ImageView minus the width of the date text
98052b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            // We use the info icon ImageView for positioning, since we want the date text to be
98152b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            // at the right, since there is no info icon
982a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            // In RTL, we just use infoIconX
9831c6d71b47e7af11b3cf7bd6da4a89594941be968James Lemieux            mDateX = (isRtl) ? mCoordinates.infoIconX : mCoordinates.infoIconXRight - mDateWidth;
98452b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        }
9856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
986a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        // The paperclip is drawn starting at the start of the date text minus
987a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        // the width of the paperclip and the date padding.
988a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        // In RTL mode, it is at the end of the date (mDateX + mDateWidth) plus the
989a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        // start date padding.
990a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        mPaperclipX = (isRtl) ? mDateX + mDateWidth + mCoordinates.datePaddingStart :
991a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein                mDateX - ATTACHMENT.getWidth() - mCoordinates.datePaddingStart;
9926f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
993928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        // In normal mode, the senders x and width is based
994928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        // on where the date/attachment icon start.
995928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        final int dateAttachmentStart;
996928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        // Have this end near the paperclip or date, not the folders.
997928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        if (mHeader.paperclip != null) {
998928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // If there is a paperclip, the date/attachment start is at the start
999928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // of the paperclip minus the paperclip padding.
1000928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // In RTL, it is at the end of the paperclip plus the paperclip padding.
1001928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            dateAttachmentStart = (isRtl) ?
1002928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux                    mPaperclipX + ATTACHMENT.getWidth() + mCoordinates.paperclipPaddingStart
1003928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux                    : mPaperclipX - mCoordinates.paperclipPaddingStart;
10043fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira        } else {
1005928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // If no paperclip, just use the start of the date minus the date padding start.
1006928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // In RTL mode, this is just the paperclipX.
1007928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            dateAttachmentStart = (isRtl) ?
1008928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux                    mPaperclipX : mDateX - mCoordinates.datePaddingStart;
1009928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        }
1010928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        // Senders width is the dateAttachmentStart - sendersX.
1011928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        // In RTL, it is sendersWidth + sendersX - dateAttachmentStart.
1012928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSendersWidth = (isRtl) ?
1013928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux                mCoordinates.sendersWidth + mCoordinates.sendersX - dateAttachmentStart
1014928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux                : dateAttachmentStart - mCoordinates.sendersX;
1015928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSendersX = (isRtl) ? dateAttachmentStart : mCoordinates.sendersX;
10166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
10176f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Second pass to layout each fragment.
1018bcab7611959549a955be8a30115d6a4c937afd24Andy Huang        sPaint.setTextSize(mCoordinates.sendersFontSize);
1019bcab7611959549a955be8a30115d6a4c937afd24Andy Huang        sPaint.setTypeface(Typeface.DEFAULT);
1020bcab7611959549a955be8a30115d6a4c937afd24Andy Huang
102142b362587928704ea17b0a09a5e4e16037d14491Jin Cao        // First pass to calculate width of each fragment.
102242b362587928704ea17b0a09a5e4e16037d14491Jin Cao        if (mSendersWidth < 0) {
102342b362587928704ea17b0a09a5e4e16037d14491Jin Cao            mSendersWidth = 0;
102442b362587928704ea17b0a09a5e4e16037d14491Jin Cao        }
1025a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein
102642b362587928704ea17b0a09a5e4e16037d14491Jin Cao        // sendersDisplayText is only set when preserveSendersText is true.
102742b362587928704ea17b0a09a5e4e16037d14491Jin Cao        if (mHeader.preserveSendersText) {
1028b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            mHeader.sendersDisplayLayout = new StaticLayout(mHeader.sendersDisplayText, sPaint,
1029b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                    mSendersWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
103042b362587928704ea17b0a09a5e4e16037d14491Jin Cao        } else {
103142b362587928704ea17b0a09a5e4e16037d14491Jin Cao            final SpannableStringBuilder participantText = elideParticipants(mHeader.styledNames);
103242b362587928704ea17b0a09a5e4e16037d14491Jin Cao            layoutParticipantText(participantText);
1033b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        }
1034b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
1035b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        pauseTimer(PERF_TAG_CALCULATE_COORDINATES);
1036b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira    }
1037b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
103810ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux    // The rules for displaying elided participants are as follows:
103958ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // 1) If there is message info (either a COUNT or DRAFT info to display), it MUST be shown
104058ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // 2) If senders do not fit, ellipsize the last one that does fit, and stop
104158ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // appending new senders
104210ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux    SpannableStringBuilder elideParticipants(List<SpannableString> parts) {
104310ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        final SpannableStringBuilder builder = new SpannableStringBuilder();
104484cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira        float totalWidth = 0;
1045b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        boolean ellipsize = false;
104684cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira        float width;
104710ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        boolean skipToHeader = false;
104810ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux
104910ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        // start with "To: " if we're showing recipients
105010ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        if (mDisplayedFolder.shouldShowRecipients() && !parts.isEmpty()) {
105110ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            final SpannableString toHeader = SendersView.getFormattedToHeader();
105210ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            CharacterStyle[] spans = toHeader.getSpans(0, toHeader.length(),
105310ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux                    CharacterStyle.class);
105410ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            // There is only 1 character style span; make sure we apply all the
105510ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            // styles to the paint object before measuring.
105610ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            if (spans.length > 0) {
105710ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux                spans[0].updateDrawState(sPaint);
105810ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            }
105910ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            totalWidth += sPaint.measureText(toHeader.toString());
106010ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            builder.append(toHeader);
106110ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            skipToHeader = true;
106210ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        }
106310ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux
106410ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux        final SpannableStringBuilder messageInfoString = mHeader.messageInfoString;
106542b362587928704ea17b0a09a5e4e16037d14491Jin Cao        if (!TextUtils.isEmpty(messageInfoString)) {
10660c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            CharacterStyle[] spans = messageInfoString.getSpans(0, messageInfoString.length(),
10670c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira                    CharacterStyle.class);
10680c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            // There is only 1 character style span; make sure we apply all the
10690c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            // styles to the paint object before measuring.
10700c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            if (spans.length > 0) {
10710c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira                spans[0].updateDrawState(sPaint);
10720c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            }
10730c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            // Paint the message info string to see if we lose space.
10740c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            float messageInfoWidth = sPaint.measureText(messageInfoString.toString());
10750c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            totalWidth += messageInfoWidth;
10760c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira        }
107742b362587928704ea17b0a09a5e4e16037d14491Jin Cao        SpannableString prevSender = null;
107842b362587928704ea17b0a09a5e4e16037d14491Jin Cao        SpannableString ellipsizedText;
10793b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux        for (SpannableString sender : parts) {
1080feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira            // There may be null sender strings if there were dupes we had to remove.
1081feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira            if (sender == null) {
1082feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira                continue;
1083feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira            }
108458ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            // No more width available, we'll only show fixed fragments.
108558ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            if (ellipsize) {
108658ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira                break;
108758ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            }
10886c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            CharacterStyle[] spans = sender.getSpans(0, sender.length(), CharacterStyle.class);
10896c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            // There is only 1 character style span.
10906c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            if (spans.length > 0) {
10916c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira                spans[0].updateDrawState(sPaint);
10926c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            }
10931152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            // If there are already senders present in this string, we need to
10941152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            // make sure we prepend the dividing token
1095b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            if (SendersView.sElidedString.equals(sender.toString())) {
1096ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                sender = copyStyles(spans, sElidedPaddingToken + sender + sElidedPaddingToken);
109710ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux            } else if (!skipToHeader && builder.length() > 0
1098b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                    && (prevSender == null || !SendersView.sElidedString.equals(prevSender
1099b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                            .toString()))) {
1100ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                sender = copyStyles(spans, sSendersSplitToken + sender);
1101b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            } else {
110210ea28ab588d8e922c0f78f0f47fe479739ec2cfJames Lemieux                skipToHeader = false;
11031152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            }
110442b362587928704ea17b0a09a5e4e16037d14491Jin Cao            prevSender = sender;
110542b362587928704ea17b0a09a5e4e16037d14491Jin Cao
1106ffd21a08c89f78adc2ee7a07b1afe6163c5f1607mindyp            if (spans.length > 0) {
1107ffd21a08c89f78adc2ee7a07b1afe6163c5f1607mindyp                spans[0].updateDrawState(sPaint);
1108ffd21a08c89f78adc2ee7a07b1afe6163c5f1607mindyp            }
11091152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            // Measure the width of the current sender and make sure we have space
1110b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            width = (int) sPaint.measureText(sender.toString());
1111ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            if (width + totalWidth > mSendersWidth) {
1112b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                // The text is too long, new line won't help. We have to
1113b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                // ellipsize text.
11141152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                ellipsize = true;
1115ffd21a08c89f78adc2ee7a07b1afe6163c5f1607mindyp                width = mSendersWidth - totalWidth; // ellipsis width?
11161152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                ellipsizedText = copyStyles(spans,
11171152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                        TextUtils.ellipsize(sender, sPaint, width, TruncateAt.END));
11181152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                width = (int) sPaint.measureText(ellipsizedText.toString());
11191152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            } else {
11201152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                ellipsizedText = null;
1121b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            }
1122b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            totalWidth += width;
1123b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
1124b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            final CharSequence fragmentDisplayText;
1125b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            if (ellipsizedText != null) {
1126b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                fragmentDisplayText = ellipsizedText;
1127b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            } else {
11281152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                fragmentDisplayText = sender;
1129b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            }
1130b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            builder.append(fragmentDisplayText);
1131b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        }
113201bb8d91c8ea039518ee07c8ac83e4e42cd81739Mindy Pereira        mHeader.styledMessageInfoStringOffset = builder.length();
113342b362587928704ea17b0a09a5e4e16037d14491Jin Cao        if (!TextUtils.isEmpty(messageInfoString)) {
113442b362587928704ea17b0a09a5e4e16037d14491Jin Cao            builder.append(messageInfoString);
113542b362587928704ea17b0a09a5e4e16037d14491Jin Cao        }
11363b59b333ad0693f74f9a8cfb24a468a8acbaca8cJames Lemieux        return builder;
113784cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira    }
113884cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira
11399e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy    private static SpannableString copyStyles(CharacterStyle[] spans, CharSequence newText) {
1140d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        SpannableString s = new SpannableString(newText);
1141d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        if (spans != null && spans.length > 0) {
1142d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira            s.setSpan(spans[0], 0, s.length(), 0);
1143d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        }
1144d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        return s;
1145d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira    }
1146d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira
11476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    /**
11486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * If the subject contains the tag of a mailing-list (text surrounded with
11496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * []), return the subject with that tag ellipsized, e.g.
11506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * "[android-gmail-team] Hello" -> "[andr...] Hello"
11516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     */
115289bf7ce646a0ee67e0a8ee10d8834bcf54257d97Andrew Sapperstein    public static String filterTag(Context context, String subject) {
11536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        String result = subject;
115489bf7ce646a0ee67e0a8ee10d8834bcf54257d97Andrew Sapperstein        String formatString = context.getResources().getString(R.string.filtered_tag);
11556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (!TextUtils.isEmpty(subject) && subject.charAt(0) == '[') {
11566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int end = subject.indexOf(']');
11576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (end > 0) {
11586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                String tag = subject.substring(1, end);
11596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                result = String.format(formatString, Utils.ellipsize(tag, 7),
11606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        subject.substring(end + 1));
11616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
11626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
11636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        return result;
11646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
11656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
11666f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @Override
11676f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    protected void onDraw(Canvas canvas) {
11681b87d3f03320eaa897ce5a4712d8bf0910bfd159Paul Westbrook        if (mCoordinates == null) {
11691b87d3f03320eaa897ce5a4712d8bf0910bfd159Paul Westbrook            LogUtils.e(LOG_TAG, "null coordinates in ConversationItemView#onDraw");
11701b87d3f03320eaa897ce5a4712d8bf0910bfd159Paul Westbrook            return;
11711b87d3f03320eaa897ce5a4712d8bf0910bfd159Paul Westbrook        }
11721b87d3f03320eaa897ce5a4712d8bf0910bfd159Paul Westbrook
1173f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceBeginSection("CIVC.draw");
1174479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
11754758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang        // Contact photo
11764758e980c21027ef1a9cacc9847170290b2ae42eAlice Yang        if (mGadgetMode == ConversationItemViewCoordinates.GADGET_CONTACT_PHOTO) {
117795f9e1b167f4945adfa4ca62f4b72a102b621794mindyp            canvas.save();
1178a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            Utils.traceBeginSection("draw senders image");
1179a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            drawSendersImage(canvas);
1180a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            Utils.traceEndSection();
118195f9e1b167f4945adfa4ca62f4b72a102b621794mindyp            canvas.restore();
11826f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
1183479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
11846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Senders.
11858d69d4e10a9a36ff790babb2f3a098a12d0dc732Marc Blank        boolean isUnread = mHeader.unread;
1186ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        // Old style senders; apply text colors/ sizes/ styling.
1187850c55ee2cab6b1c224366c66502f5d5f55018ebmindyp        canvas.save();
1188850c55ee2cab6b1c224366c66502f5d5f55018ebmindyp        if (mHeader.sendersDisplayLayout != null) {
1189ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sPaint.setTextSize(mCoordinates.sendersFontSize);
119077d7f3c3c8c82048b51025428a825f6ac71e8560Mindy Pereira            sPaint.setTypeface(SendersView.getTypeface(isUnread));
11915750406080090ed22bf93036525c2ff30f41b28aJames Lemieux            sPaint.setColor(sSendersTextColor);
1192a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            canvas.translate(mSendersX, mCoordinates.sendersY
119343ac9a0d56faa5cf72a771468838b4c413c82d6fmindyp                    + mHeader.sendersDisplayLayout.getTopPadding());
1194850c55ee2cab6b1c224366c66502f5d5f55018ebmindyp            mHeader.sendersDisplayLayout.draw(canvas);
1195ffd21a08c89f78adc2ee7a07b1afe6163c5f1607mindyp        } else {
11962598be2e9681c24fb5746f7c5efc963378dccf0amindyp            drawSenders(canvas);
1197ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        }
1198d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang        canvas.restore();
11996f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1200850c55ee2cab6b1c224366c66502f5d5f55018ebmindyp
12016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Subject.
12026f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTypeface(Typeface.DEFAULT);
12036f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        canvas.save();
12042598be2e9681c24fb5746f7c5efc963378dccf0amindyp        drawSubject(canvas);
12056f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        canvas.restore();
12066f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1207928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        canvas.save();
1208928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        drawSnippet(canvas);
1209928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        canvas.restore();
1210be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
1211b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        // Folders.
1212fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (mConfig.areFoldersVisible()) {
1213a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein            mHeader.folderDisplayer.drawFolders(canvas, mCoordinates, ViewUtils.isViewRtl(this));
1214b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
1215b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
121692939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank        // If this folder has a color (combined view/Email), show it here
1217fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (mConfig.isColorBlockVisible()) {
121892939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            sFoldersPaint.setColor(mHeader.conversation.color);
121992939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            sFoldersPaint.setStyle(Paint.Style.FILL);
1220fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang            canvas.drawRect(mCoordinates.colorBlockX, mCoordinates.colorBlockY,
1221fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                    mCoordinates.colorBlockX + mCoordinates.colorBlockWidth,
1222fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang                    mCoordinates.colorBlockY + mCoordinates.colorBlockHeight, sFoldersPaint);
122392939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank        }
122492939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank
122554467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira        // Draw the reply state. Draw nothing if neither replied nor forwarded.
1226fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        if (mConfig.isReplyStateVisible()) {
122754467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            if (mHeader.hasBeenRepliedTo && mHeader.hasBeenForwarded) {
122854467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                canvas.drawBitmap(STATE_REPLIED_AND_FORWARDED, mCoordinates.replyStateX,
122954467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                        mCoordinates.replyStateY, null);
123054467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            } else if (mHeader.hasBeenRepliedTo) {
123154467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                canvas.drawBitmap(STATE_REPLIED, mCoordinates.replyStateX,
123254467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                        mCoordinates.replyStateY, null);
123354467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            } else if (mHeader.hasBeenForwarded) {
123454467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                canvas.drawBitmap(STATE_FORWARDED, mCoordinates.replyStateX,
123554467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                        mCoordinates.replyStateY, null);
12368d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira            } else if (mHeader.isInvite) {
1237d5ac9c16e8955abe8366fd1185b86d8bd7c5ac60Mindy Pereira                canvas.drawBitmap(STATE_CALENDAR_INVITE, mCoordinates.replyStateX,
12388d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira                        mCoordinates.replyStateY, null);
123954467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            }
124054467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira        }
124154467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira
12424a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang        if (mConfig.isPersonalIndicatorVisible()) {
12434a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang            canvas.drawBitmap(mHeader.personalLevelBitmap, mCoordinates.personalIndicatorX,
12444a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang                    mCoordinates.personalIndicatorY, null);
12454a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang        }
12464a85e39fbc318359e8a3cacb874df2372fe9d566Andy Huang
124752b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        // Info icon
124852b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        if (mHeader.infoIcon != null) {
124952b280a82df262f62632bd12bba84b4752f14634Scott Kennedy            canvas.drawBitmap(mHeader.infoIcon, mInfoIconX, mCoordinates.infoIconY, sPaint);
125052b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        }
125152b280a82df262f62632bd12bba84b4752f14634Scott Kennedy
12526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Date.
1253ce59fca1cfad3489bc121e9b58a9c67e765ca35aAndy Huang        sPaint.setTextSize(mCoordinates.dateFontSize);
1254ff35c4d206132d389cc5b77c488bd1fd41926e4dJames Lemieux        sPaint.setTypeface(isUnread ? SANS_SERIF_BOLD : SANS_SERIF_LIGHT);
12551c6d71b47e7af11b3cf7bd6da4a89594941be968James Lemieux        sPaint.setColor(isUnread ? sDateTextColorUnread : sDateTextColorRead);
1256928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        drawText(canvas, mHeader.dateText, mDateX, mCoordinates.dateYBaseline, sPaint);
12576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
125852b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        // Paper clip icon.
125952b280a82df262f62632bd12bba84b4752f14634Scott Kennedy        if (mHeader.paperclip != null) {
12606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.drawBitmap(mHeader.paperclip, mPaperclipX, mCoordinates.paperclipY, sPaint);
12616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
12626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1263a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux        // Star.
12648afccad8b03701577bb4b734a0f4fe76f6cab487Scott Kennedy        if (mStarEnabled) {
12658afccad8b03701577bb4b734a0f4fe76f6cab487Scott Kennedy            canvas.drawBitmap(getStarBitmap(), mCoordinates.starX, mCoordinates.starY, sPaint);
12660a135884c7452225bc0c86c5f768d581c0ce6c04Mark Wei        }
1267d198fa7ddb2d0c730847af34f06aa2e940b2537dMark Wei
1268a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux        // Divider.
1269a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux        if (mDividerEnabled) {
12704173d7d25b2eb0caa6ec4adc0b3757d96b7eff6bJames Lemieux            final int dividerBottomY = getHeight();
12714173d7d25b2eb0caa6ec4adc0b3757d96b7eff6bJames Lemieux            final int dividerTopY = dividerBottomY - sDividerHeight;
1272a7003405a9f66b6a7ee6caf62c6eb746f834c64dJames Lemieux            canvas.drawRect(0, dividerTopY, getWidth(), dividerBottomY, sDividerPaint);
12734173d7d25b2eb0caa6ec4adc0b3757d96b7eff6bJames Lemieux        }
1274ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao
1275ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        // The focused bar
12760532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        final SwipeableListView listView = getListView();
1277f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        if (listView != null && listView.isConversationSelected(getConversation())) {
12780532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            final int w = FOCUSED_CONVERSATION_HIGHLIGHT.getIntrinsicWidth();
1279ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            final boolean isRtl = ViewUtils.isViewRtl(this);
1280ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            // This bar is on the right side of the conv list if it's RTL
12810532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            FOCUSED_CONVERSATION_HIGHLIGHT.setBounds(
1282ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao                    (isRtl) ? getWidth() - w : 0, 0,
1283ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao                    (isRtl) ? getWidth() : w, getHeight());
12840532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            FOCUSED_CONVERSATION_HIGHLIGHT.draw(canvas);
1285ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        }
1286ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao
1287f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceEndSection();
12884f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira    }
12894f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira
12900532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    @Override
12910532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    public void setSelected(boolean selected) {
12920532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        // We catch the selected event here instead of using ListView#setOnItemSelectedListener
12930532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        // because when the framework changes selection due to keyboard events, it sets the selected
12940532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        // state, re-draw the affected views, and then call onItemSelected. That approach won't work
12950532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        // because the view won't know about the new selected position during the re-draw.
12960532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        if (selected) {
12970532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            final SwipeableListView listView = getListView();
12980532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            if (listView != null) {
1299f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                listView.setSelectedConversation(getConversation());
13000532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            }
13010532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        }
13020532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        super.setSelected(selected);
13030532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    }
13040532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao
1305a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    private void drawSendersImage(final Canvas canvas) {
1306a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        if (!mSendersImageView.isFlipping()) {
1307ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            final boolean showSenders = !mChecked;
1308a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            mSendersImageView.reset(showSenders);
13091fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy        }
1310a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        canvas.translate(mCoordinates.contactImagesX, mCoordinates.contactImagesY);
1311103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        if (mPhotoBitmap == null) {
1312a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            mSendersImageView.draw(canvas);
1313103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        } else {
1314103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy            canvas.drawBitmap(mPhotoBitmap, null, mPhotoRect, sPaint);
1315103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        }
13161fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy    }
13171fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy
131895f9e1b167f4945adfa4ca62f4b72a102b621794mindyp    private void drawSubject(Canvas canvas) {
1319fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        canvas.translate(mCoordinates.subjectX, mCoordinates.subjectY);
132095f9e1b167f4945adfa4ca62f4b72a102b621794mindyp        mSubjectTextView.draw(canvas);
13216f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
13226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1323928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux    private void drawSnippet(Canvas canvas) {
132464f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        // if folders exist, their width will be the max width - actual width
132564f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        final int folderWidth = mCoordinates.maxSnippetWidth - mSnippetTextView.getWidth();
132664f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux
132764f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        // in RTL layouts we move the snippet to the right so it doesn't overlap the folders
132864f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        final int x = mCoordinates.snippetX + (ViewUtils.isViewRtl(this) ? folderWidth : 0);
132964f56828a81ad7e29cad3a254a6ecdc05c9284e8James Lemieux        canvas.translate(x, mCoordinates.snippetY);
1330928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        mSnippetTextView.draw(canvas);
1331be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    }
1332be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein
133395f9e1b167f4945adfa4ca62f4b72a102b621794mindyp    private void drawSenders(Canvas canvas) {
1334a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        canvas.translate(mSendersX, mCoordinates.sendersY);
133595f9e1b167f4945adfa4ca62f4b72a102b621794mindyp        mSendersTextView.draw(canvas);
1336bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira    }
1337bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira
133895f9e1b167f4945adfa4ca62f4b72a102b621794mindyp    private Bitmap getStarBitmap() {
133995f9e1b167f4945adfa4ca62f4b72a102b621794mindyp        return mHeader.conversation.starred ? STAR_ON : STAR_OFF;
13406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
13416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
13429e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy    private static void drawText(Canvas canvas, CharSequence s, int x, int y, TextPaint paint) {
1343ce59fca1cfad3489bc121e9b58a9c67e765ca35aAndy Huang        canvas.drawText(s, 0, s.length(), x, y, paint);
1344ce59fca1cfad3489bc121e9b58a9c67e765ca35aAndy Huang    }
1345ce59fca1cfad3489bc121e9b58a9c67e765ca35aAndy Huang
13460509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal    /**
13470509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal     * Set the background for this item based on:
13480509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal     * 1. Read / Unread (unread messages have a lighter background)
13490509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal     * 2. Tablet / Phone
13500509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal     * 3. Checkbox checked / Unchecked (controls CAB color for item)
13510509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal     * 4. Activated / Not activated (controls the blue highlight on tablet)
13520509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal     */
1353be0cb1e421831672f49c30ecb46e6eee765cb661Andrew Sapperstein    private void updateBackground() {
13540509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal        final int background;
1355103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        if (mBackgroundOverrideResId > 0) {
1356103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy            background = mBackgroundOverrideResId;
13576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        } else {
13586b57d9cedbe8f905d5845ef7ddebb2e1a053d3eeRohan Shah            background = R.drawable.conversation_item_background;
13596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
13600509bba9a80de474a24368e1f3baebd3cd32cd5eVikram Aggarwal        setBackgroundResource(background);
13616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
1362c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
13636126d72ae2769bd39451872f45781cadb5b90515Mark Wei    @Override
1364ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    protected int[] onCreateDrawableState(int extraSpace) {
1365ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        final int[] curr = super.onCreateDrawableState(extraSpace + 1);
1366ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mChecked) {
1367ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            mergeDrawableStates(curr, CHECKED_STATE);
1368ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        }
1369ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        return curr;
1370ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    }
1371ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao
1372ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    private void setChecked(boolean checked) {
1373ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        mChecked = checked;
1374ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        refreshDrawableState();
1375ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    }
1376ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao
1377ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    @Override
1378ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    public boolean toggleCheckedState() {
1379ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        return toggleCheckedState(null);
1380042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang    }
1381042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
138212a05d22f6ac528e96716de9a451c5b7bee7a26dAndy Huang    @Override
1383ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    public boolean toggleCheckedState(final String sourceOpt) {
1384ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mHeader != null && mHeader.conversation != null && mCheckedConversationSet != null) {
1385ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            setChecked(!mChecked);
1386a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            final Conversation conv = mHeader.conversation;
1387bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            // Set the list position of this item in the conversation
1388a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            final SwipeableListView listView = getListView();
1389a2640038ffe8a17fb435b0007ba4ca9ff14d00bdScott Kennedy
1390a2640038ffe8a17fb435b0007ba4ca9ff14d00bdScott Kennedy            try {
1391f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                conv.position = mChecked && listView != null ? listView.getPositionForView(this)
1392f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                        : Conversation.NO_POSITION;
1393a2640038ffe8a17fb435b0007ba4ca9ff14d00bdScott Kennedy            } catch (final NullPointerException e) {
1394a2640038ffe8a17fb435b0007ba4ca9ff14d00bdScott Kennedy                // TODO(skennedy) Remove this if we find the root cause b/9527863
1395a2640038ffe8a17fb435b0007ba4ca9ff14d00bdScott Kennedy            }
1396042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
1397ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            if (mCheckedConversationSet.isEmpty()) {
1398042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang                final String source = (sourceOpt != null) ? sourceOpt : "checkbox";
1399042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang                Analytics.getInstance().sendEvent("enter_cab_mode", source, null, 0);
1400bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            }
1401042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
1402ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            mCheckedConversationSet.toggle(conv);
1403ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            if (mCheckedConversationSet.isEmpty()) {
140454f120f6ada40c7191811dfff99b151e9e192c78mindyp                listView.commitDestructiveActions(true);
140554f120f6ada40c7191811dfff99b151e9e192c78mindyp            }
14061fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy
1407ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            final boolean front = !mChecked;
1408a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei            mSendersImageView.flipTo(front);
14091fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy
1410bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            // We update the background after the checked state has changed
1411bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            // now that we have a selected background asset. Setting the background
1412bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            // usually waits for a layout pass, but we don't need a full layout,
1413bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            // just an update to the background.
1414bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp            requestLayout();
1415955a766f6c9c30e06dcd504ebc4dd6db510c2fa6Scott Kennedy
1416955a766f6c9c30e06dcd504ebc4dd6db510c2fa6Scott Kennedy            return true;
1417bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp        }
1418955a766f6c9c30e06dcd504ebc4dd6db510c2fa6Scott Kennedy
1419955a766f6c9c30e06dcd504ebc4dd6db510c2fa6Scott Kennedy        return false;
1420bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp    }
1421bad1a93d431bc599ed73fa4f42eeef313cd31626mindyp
1422a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    @Override
1423a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    public void onSetEmpty() {
1424a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        mSendersImageView.flipTo(true);
1425a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    }
1426a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
1427a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    @Override
1428ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    public void onSetPopulated(final ConversationCheckedSet set) { }
1429a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
1430a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    @Override
1431ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    public void onSetChanged(final ConversationCheckedSet set) { }
1432a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
1433c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    /**
1434c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira     * Toggle the star on this view and update the conversation.
1435c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira     */
1436866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public void toggleStar() {
14374f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira        mHeader.conversation.starred = !mHeader.conversation.starred;
14384f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira        Bitmap starBitmap = getStarBitmap();
1439c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        postInvalidate(mCoordinates.starX, mCoordinates.starY, mCoordinates.starX
14404f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira                + starBitmap.getWidth(),
14414f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira                mCoordinates.starY + starBitmap.getHeight());
1442bcdc0f995c05ec1842a74e853a87ae5048799d0cAlice Yang        ConversationCursor cursor = (ConversationCursor) mAdapter.getCursor();
1443bcdc0f995c05ec1842a74e853a87ae5048799d0cAlice Yang        if (cursor != null) {
1444103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy            // TODO(skennedy) What about ads?
14459e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy            cursor.updateBoolean(mHeader.conversation, ConversationColumns.STARRED,
1446bcdc0f995c05ec1842a74e853a87ae5048799d0cAlice Yang                    mHeader.conversation.starred);
1447bcdc0f995c05ec1842a74e853a87ae5048799d0cAlice Yang        }
1448c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1449c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1450479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    private boolean isTouchInContactPhoto(float x, float y) {
1451a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        // Everything before the end edge of contact photo
14529ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy
1453a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        final boolean isRtl = ViewUtils.isViewRtl(this);
1454a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        final int threshold = (isRtl) ? mCoordinates.contactImagesX - sSenderImageTouchSlop :
1455a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein                mCoordinates.contactImagesX + mCoordinates.contactImagesWidth
14569ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy                + sSenderImageTouchSlop;
14579ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy
14589ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy        // Allow touching a little right of the contact photo when we're already in selection mode
14599ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy        final float extra;
1460ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mCheckedConversationSet == null || mCheckedConversationSet.isEmpty()) {
14619ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy            extra = 0;
14629ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy        } else {
14639ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy            extra = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16,
14649ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy                    getResources().getDisplayMetrics());
14659ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy        }
14669ba7fba9213027c6f763001d32d4c88f0d086388Scott Kennedy
1467479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        return mHeader.gadgetMode == ConversationItemViewCoordinates.GADGET_CONTACT_PHOTO
14680e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                && ((isRtl) ? x > (threshold - extra) : x < (threshold + extra));
1469c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1470c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1471d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    private boolean isTouchInInfoIcon(final float x, final float y) {
1472d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        if (mHeader.infoIcon == null) {
1473d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            // We have no info icon
1474d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            return false;
1475d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        }
1476d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
1477a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        final boolean isRtl = ViewUtils.isViewRtl(this);
1478a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        // Regardless of device, we always want to be end of the date's start touch slop
1479a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        if (((isRtl) ? x > mDateX + mDateWidth + sStarTouchSlop : x < mDateX - sStarTouchSlop)) {
1480d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            return false;
1481d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        }
1482d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
1483d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        if (mStarEnabled) {
1484928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // We allow touches all the way to the right edge, so no x check is necessary
1485d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
1486928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // We need to be above the star's touch area, which ends at the top of the subject
1487928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            // text
1488928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux            return y < mCoordinates.subjectY;
1489d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        }
1490d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
1491d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        // With no star below the info icon, we allow touches anywhere from the top edge to the
14920e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux        // bottom edge
14930e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux        return true;
1494d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy    }
1495d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
1496866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private boolean isTouchInStar(float x, float y) {
1497928308d6b10d353493492ad05e0227f960ddaa7eJames Lemieux        if (mHeader.infoIcon != null) {
1498d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            // We have an info icon, and it's above the star
1499d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            // We allow touches everywhere below the top of the subject text
1500d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            if (y < mCoordinates.subjectY) {
1501d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                return false;
1502d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy            }
1503d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy        }
1504d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy
1505c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        // Everything after the star and include a touch slop.
15060e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux        return mStarEnabled && isTouchInStarTargetX(ViewUtils.isViewRtl(this), x);
1507479505d71969e26b0785d8e0e1b81108731cf827Mark Wei    }
1508479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
1509a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein    private boolean isTouchInStarTargetX(boolean isRtl, float x) {
1510a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein        return (isRtl) ? x < mCoordinates.starX + mCoordinates.starWidth + sStarTouchSlop
1511a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein                : x >= mCoordinates.starX - sStarTouchSlop;
1512a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein    }
1513a4296c179cd4eb12e7c4912d72c22dd2ec724a7eAndrew Sapperstein
1514304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blank    @Override
1515a538984fcc19e7624f2650b119ede39bf1f35846mindyp    public boolean canChildBeDismissed() {
1516512821c11d89d49908f3cfdee0b582601f500f3dJin Cao        return mSwipeEnabled;
1517a538984fcc19e7624f2650b119ede39bf1f35846mindyp    }
1518a538984fcc19e7624f2650b119ede39bf1f35846mindyp
1519a538984fcc19e7624f2650b119ede39bf1f35846mindyp    @Override
1520a538984fcc19e7624f2650b119ede39bf1f35846mindyp    public void dismiss() {
1521ffd39aa99f185385941595c1da7e09c2a4a4c146mindyp        SwipeableListView listView = getListView();
15225254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        if (listView != null) {
1523e1ba1013409486f88f06af2932546a1b366704d3Jin Cao            listView.dismissChild(this);
15245254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        }
15255bcd7e9f994624eea184a60ff50a3d71b5710582Mindy Pereira    }
15265bcd7e9f994624eea184a60ff50a3d71b5710582Mindy Pereira
1527a4b9f78c174238045ec51a351553b39d876fb67emindyp    private boolean onTouchEventNoSwipe(MotionEvent event) {
1528479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("on touch event no swipe");
1529a4b9f78c174238045ec51a351553b39d876fb67emindyp        boolean handled = false;
1530a4b9f78c174238045ec51a351553b39d876fb67emindyp
1531a4b9f78c174238045ec51a351553b39d876fb67emindyp        int x = (int) event.getX();
1532a4b9f78c174238045ec51a351553b39d876fb67emindyp        int y = (int) event.getY();
1533a4b9f78c174238045ec51a351553b39d876fb67emindyp        switch (event.getAction()) {
1534a4b9f78c174238045ec51a351553b39d876fb67emindyp            case MotionEvent.ACTION_DOWN:
1535d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                if (isTouchInContactPhoto(x, y) || isTouchInInfoIcon(x, y) || isTouchInStar(x, y)) {
1536a4b9f78c174238045ec51a351553b39d876fb67emindyp                    mDownEvent = true;
1537a4b9f78c174238045ec51a351553b39d876fb67emindyp                    handled = true;
1538a4b9f78c174238045ec51a351553b39d876fb67emindyp                }
1539a4b9f78c174238045ec51a351553b39d876fb67emindyp                break;
1540a4b9f78c174238045ec51a351553b39d876fb67emindyp
1541a4b9f78c174238045ec51a351553b39d876fb67emindyp            case MotionEvent.ACTION_CANCEL:
1542a4b9f78c174238045ec51a351553b39d876fb67emindyp                mDownEvent = false;
1543a4b9f78c174238045ec51a351553b39d876fb67emindyp                break;
1544a4b9f78c174238045ec51a351553b39d876fb67emindyp
1545a4b9f78c174238045ec51a351553b39d876fb67emindyp            case MotionEvent.ACTION_UP:
1546a4b9f78c174238045ec51a351553b39d876fb67emindyp                if (mDownEvent) {
1547479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                    if (isTouchInContactPhoto(x, y)) {
1548a4b9f78c174238045ec51a351553b39d876fb67emindyp                        // Touch on the check mark
1549ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao                        toggleCheckedState();
1550d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                    } else if (isTouchInInfoIcon(x, y)) {
1551d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        if (mConversationItemAreaClickListener != null) {
1552d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                            mConversationItemAreaClickListener.onInfoIconClicked();
1553d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        }
1554a4b9f78c174238045ec51a351553b39d876fb67emindyp                    } else if (isTouchInStar(x, y)) {
15558afccad8b03701577bb4b734a0f4fe76f6cab487Scott Kennedy                        // Touch on the star
1556d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        if (mConversationItemAreaClickListener == null) {
1557d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                            toggleStar();
1558d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        } else {
1559d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                            mConversationItemAreaClickListener.onStarClicked();
1560d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        }
1561a4b9f78c174238045ec51a351553b39d876fb67emindyp                    }
1562a4b9f78c174238045ec51a351553b39d876fb67emindyp                    handled = true;
1563a4b9f78c174238045ec51a351553b39d876fb67emindyp                }
1564a4b9f78c174238045ec51a351553b39d876fb67emindyp                break;
1565a4b9f78c174238045ec51a351553b39d876fb67emindyp        }
1566a4b9f78c174238045ec51a351553b39d876fb67emindyp
1567a4b9f78c174238045ec51a351553b39d876fb67emindyp        if (!handled) {
1568a4b9f78c174238045ec51a351553b39d876fb67emindyp            handled = super.onTouchEvent(event);
1569a4b9f78c174238045ec51a351553b39d876fb67emindyp        }
1570a4b9f78c174238045ec51a351553b39d876fb67emindyp
1571479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceEndSection();
1572a4b9f78c174238045ec51a351553b39d876fb67emindyp        return handled;
1573a4b9f78c174238045ec51a351553b39d876fb67emindyp    }
1574a4b9f78c174238045ec51a351553b39d876fb67emindyp
1575b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    /**
1576866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * ConversationItemView is given the first chance to handle touch events.
1577866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
1578c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    @Override
1579c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    public boolean onTouchEvent(MotionEvent event) {
1580479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("on touch event");
15811e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira        int x = (int) event.getX();
15821e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira        int y = (int) event.getY();
1583f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        if (!mSwipeEnabled) {
1584479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            Utils.traceEndSection();
1585f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira            return onTouchEventNoSwipe(event);
1586f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        }
1587c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        switch (event.getAction()) {
1588c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira            case MotionEvent.ACTION_DOWN:
1589d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                if (isTouchInContactPhoto(x, y) || isTouchInInfoIcon(x, y) || isTouchInStar(x, y)) {
1590960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira                    mDownEvent = true;
1591479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                    Utils.traceEndSection();
1592960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira                    return true;
1593960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira                }
1594c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                break;
1595c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira            case MotionEvent.ACTION_UP:
1596c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                if (mDownEvent) {
1597479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                    if (isTouchInContactPhoto(x, y)) {
1598c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                        // Touch on the check mark
1599479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                        Utils.traceEndSection();
1600960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira                        mDownEvent = false;
1601ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao                        toggleCheckedState();
1602479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                        Utils.traceEndSection();
1603960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira                        return true;
1604d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                    } else if (isTouchInInfoIcon(x, y)) {
1605d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        // Touch on the info icon
1606d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        mDownEvent = false;
1607d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        if (mConversationItemAreaClickListener != null) {
1608d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                            mConversationItemAreaClickListener.onInfoIconClicked();
1609d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        }
1610d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        Utils.traceEndSection();
1611d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        return true;
1612866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    } else if (isTouchInStar(x, y)) {
16138afccad8b03701577bb4b734a0f4fe76f6cab487Scott Kennedy                        // Touch on the star
1614d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        mDownEvent = false;
1615d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        if (mConversationItemAreaClickListener == null) {
1616d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                            toggleStar();
1617d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        } else {
1618d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                            mConversationItemAreaClickListener.onStarClicked();
1619d35dcd8d74d2cc95ccaf28a5bc28344fda309fc3Scott Kennedy                        }
1620479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                        Utils.traceEndSection();
1621479505d71969e26b0785d8e0e1b81108731cf827Mark Wei                        return true;
1622c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                    }
1623c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                }
1624c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                break;
1625c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        }
1626ac9687c359d06ffd26a270906325dacef531ef53Vikram Aggarwal        // Let View try to handle it as well.
1627960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        boolean handled = super.onTouchEvent(event);
1628960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        if (event.getAction() == MotionEvent.ACTION_DOWN) {
1629479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            Utils.traceEndSection();
1630960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira            return true;
1631960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        }
1632479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceEndSection();
1633960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        return handled;
1634c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1635866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1636960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira    @Override
1637960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira    public boolean performClick() {
1638f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal        final boolean handled = super.performClick();
1639f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal        final SwipeableListView list = getListView();
1640103319aaed26bce257de55b2fe93d4f78d3c59b9Scott Kennedy        if (!handled && list != null && list.getAdapter() != null) {
1641f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal            final int pos = list.findConversation(this, mHeader.conversation);
1642960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira            list.performItemClick(this, pos, mHeader.conversation.id);
1643960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        }
1644960fea746ff82480cccf6a945bfaeab1689c7138Mindy Pereira        return handled;
16451e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira    }
16461e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira
1647e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy    private View unwrap() {
164879c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        final ViewParent vp = getParent();
1649e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy        if (vp == null || !(vp instanceof View)) {
165079c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang            return null;
165179c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        }
1652e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy        return (View) vp;
165379c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang    }
165479c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
1655a538984fcc19e7624f2650b119ede39bf1f35846mindyp    private SwipeableListView getListView() {
165679c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        SwipeableListView v = null;
1657e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy        final View wrapper = unwrap();
1658e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy        if (wrapper != null && wrapper instanceof SwipeableConversationItemView) {
1659e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy            v = (SwipeableListView) ((SwipeableConversationItemView) wrapper).getListView();
166079c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        }
16615254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        if (v == null) {
16625254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            v = mAdapter.getListView();
16635254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        }
16645254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        return v;
16651ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira    }
16661ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira
1667866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
16685c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira     * Reset any state associated with this conversation item view so that it
16695c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira     * can be reused.
16705c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira     */
16715c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira    public void reset() {
1672479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceBeginSection("reset");
1673370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        setAlpha(1f);
1674370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        setTranslationX(0f);
1675370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        mAnimatedHeightFraction = 1.0f;
1676479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        Utils.traceEndSection();
1677370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    }
1678370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
1679370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    @SuppressWarnings("deprecation")
1680370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    @Override
1681370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    public void setTranslationX(float translationX) {
1682370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        super.setTranslationX(translationX);
1683370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
168479c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        // When a list item is being swiped or animated, ensure that the hosting view has a
168579c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        // background color set. We only enable the background during the X-translation effect to
168679c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        // reduce overdraw during normal list scrolling.
1687e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy        final View parent = (View) getParent();
168879c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang        if (parent == null) {
1689e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy            LogUtils.w(LOG_TAG, "CIV.setTranslationX null ConversationItemView parent x=%s",
1690e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy                    translationX);
1691370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        }
1692370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
1693e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy        if (parent instanceof SwipeableConversationItemView) {
1694e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy            if (translationX != 0f) {
1695e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy                parent.setBackgroundResource(R.color.swiped_bg_color);
1696e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy            } else {
1697e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy                parent.setBackgroundDrawable(null);
1698e5707f86f340797d5ee1535bff86d331715cbce9Scott Kennedy            }
1699370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        }
17005c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira    }
17015c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira
17025c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira    /**
1703866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * Grow the height of the item and fade it in when bringing a conversation
1704866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * back from a destructive action.
1705866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
1706370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    public Animator createSwipeUndoAnimation() {
1707067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator undoAnimator = createTranslateXAnimation(true);
1708370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        return undoAnimator;
1709866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
1710866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1711bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    /**
1712bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     * Grow the height of the item and fade it in when bringing a conversation
1713bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     * back from a destructive action.
1714bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     */
1715370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    public Animator createUndoAnimation() {
1716067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator height = createHeightAnimation(true);
1717370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        Animator fade = ObjectAnimator.ofFloat(this, "alpha", 0, 1.0f);
1718067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        fade.setDuration(sShrinkAnimationDuration);
1719067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        fade.setInterpolator(new DecelerateInterpolator(2.0f));
1720067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        AnimatorSet transitionSet = new AnimatorSet();
1721067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.playTogether(height, fade);
1722370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        transitionSet.addListener(new HardwareLayerEnabler(this));
1723370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        return transitionSet;
1724067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1725067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1726067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    /**
1727067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * Grow the height of the item and fade it in when bringing a conversation
1728067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * back from a destructive action.
1729067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     */
1730370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    public Animator createDestroyWithSwipeAnimation() {
1731067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator slide = createTranslateXAnimation(false);
1732067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator height = createHeightAnimation(false);
1733bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        AnimatorSet transitionSet = new AnimatorSet();
1734067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.playSequentially(slide, height);
1735370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        return transitionSet;
1736bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
1737bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
1738067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private ObjectAnimator createTranslateXAnimation(boolean show) {
1739ffd39aa99f185385941595c1da7e09c2a4a4c146mindyp        SwipeableListView parent = getListView();
1740ffd39aa99f185385941595c1da7e09c2a4a4c146mindyp        // If we can't get the parent...we have bigger problems.
1741ffd39aa99f185385941595c1da7e09c2a4a4c146mindyp        int width = parent != null ? parent.getMeasuredWidth() : 0;
1742ffd39aa99f185385941595c1da7e09c2a4a4c146mindyp        final float start = show ? width : 0f;
1743ffd39aa99f185385941595c1da7e09c2a4a4c146mindyp        final float end = show ? 0f : width;
1744067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator slide = ObjectAnimator.ofFloat(this, "translationX", start, end);
1745067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        slide.setInterpolator(new DecelerateInterpolator(2.0f));
1746067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        slide.setDuration(sSlideAnimationDuration);
1747067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return slide;
1748067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1749067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1750370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    public Animator createDestroyAnimation() {
1751370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        return createHeightAnimation(false);
17525c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira    }
17535c16f82f9916b8d21fd36ac7c460811e59ba6614Mindy Pereira
1754067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private ObjectAnimator createHeightAnimation(boolean show) {
1755370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        final float start = show ? 0f : 1.0f;
1756370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        final float end = show ? 1.0f : 0f;
1757370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        ObjectAnimator height = ObjectAnimator.ofFloat(this, "animatedHeightFraction", start, end);
1758067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        height.setInterpolator(new DecelerateInterpolator(2.0f));
1759067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        height.setDuration(sShrinkAnimationDuration);
1760067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return height;
1761067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1762067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1763bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    // Used by animator
1764370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    public void setAnimatedHeightFraction(float height) {
1765370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        mAnimatedHeightFraction = height;
1766bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        requestLayout();
1767bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
1768bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
1769350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira    @Override
17702102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei    public SwipeableView getSwipeableView() {
17712102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei        return SwipeableView.from(this);
17726c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
17735390fcabb7baf683fc14bd68d8612913dac70a81mindyp
1774d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp    @Override
1775d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp    public float getMinAllowScrollDistance() {
1776d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp        return sScrollSlop;
1777d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp    }
17781fea6a3cffcc8c4afc3d877e5dc57d29f9665942Scott Kennedy
17793dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao    public String getAccountEmailAddress() {
17803dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao        return mAccount.getEmailAddress();
1781022aeeffe491ed8c3deeaf7c0fc7570d57af12bbScott Kennedy    }
1782bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook}
1783