ConversationItemView.java revision bf9508d3877d05742b2f5d23e1780366d3e1aa2e
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;
21304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blankimport android.animation.Animator.AnimatorListener;
22bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereiraimport android.animation.AnimatorSet;
23866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport android.animation.ObjectAnimator;
24acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereiraimport android.content.ClipData;
25acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereiraimport android.content.ClipData.Item;
26304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blankimport android.content.Context;
276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.content.res.Resources;
28f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereiraimport android.database.Cursor;
296f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Bitmap;
306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.BitmapFactory;
316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Canvas;
326f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Color;
33b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport android.graphics.LinearGradient;
34b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport android.graphics.Paint;
35acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereiraimport android.graphics.Point;
366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Rect;
37b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport android.graphics.Shader;
386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.Typeface;
396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.graphics.drawable.Drawable;
406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.Layout.Alignment;
416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.Spannable;
42b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereiraimport android.text.SpannableString;
436f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.SpannableStringBuilder;
446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.StaticLayout;
456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.TextPaint;
466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.TextUtils;
476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.TextUtils.TruncateAt;
486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.format.DateUtils;
496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.CharacterStyle;
506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.ForegroundColorSpan;
516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.text.style.StyleSpan;
526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.util.SparseArray;
53b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereiraimport android.view.HapticFeedbackConstants;
546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.view.MotionEvent;
556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereiraimport android.view.View;
56b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereiraimport android.view.ViewConfiguration;
57866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport android.view.animation.DecelerateInterpolator;
58f892f0a57d5c24b09fdc805f0fe2007ecd0d0e91Marc Blankimport android.widget.ListView;
596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
60732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.R;
61732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.browse.ConversationItemViewModel.SenderFragment;
62732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.perf.Timer;
63732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.providers.Conversation;
64b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport com.android.mail.providers.Folder;
653cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereiraimport com.android.mail.providers.UIProvider;
66c8a994227b9c686d88ee05840544162711a85712Marc Blankimport com.android.mail.providers.UIProvider.ConversationColumns;
67bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.ui.AnimatedAdapter;
68e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereiraimport com.android.mail.ui.ControllableActivity;
691ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport com.android.mail.ui.ConversationSelectionSet;
70b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereiraimport com.android.mail.ui.FolderDisplayer;
716c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereiraimport com.android.mail.ui.SwipeableItemView;
721ddcf0f2bf44d3c9db89112ef52510d9b2433ac4Vikram Aggarwalimport com.android.mail.ui.ViewMode;
732f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwalimport com.android.mail.utils.LogTag;
742f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwalimport com.android.mail.utils.LogUtils;
75732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huangimport com.android.mail.utils.Utils;
76304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blankimport com.google.common.annotations.VisibleForTesting;
77732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang
786c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereirapublic class ConversationItemView extends View implements SwipeableItemView {
796f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Timer.
806f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static int sLayoutCount = 0;
81bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook    private static Timer sTimer; // Create the sTimer here if you need to do
82bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                                 // perf analysis.
836f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final int PERF_LAYOUT_ITERATIONS = 50;
846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_LAYOUT = "CCHV.layout";
856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_CALCULATE_TEXTS_BITMAPS = "CCHV.txtsbmps";
866f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_CALCULATE_SENDER_SUBJECT = "CCHV.sendersubj";
8730fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira    private static final String PERF_TAG_CALCULATE_FOLDERS = "CCHV.folders";
886f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static final String PERF_TAG_CALCULATE_COORDINATES = "CCHV.coordinates";
892f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal    private static final String LOG_TAG = LogTag.getLogTag();
906f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
916f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Static bitmaps.
926f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap CHECKMARK_OFF;
936f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap CHECKMARK_ON;
946f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap STAR_OFF;
956f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap STAR_ON;
966f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap ATTACHMENT;
976f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap ONLY_TO_ME;
986f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap TO_ME_AND_OTHERS;
996f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap IMPORTANT_ONLY_TO_ME;
1006f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap IMPORTANT_TO_ME_AND_OTHERS;
1016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap IMPORTANT_TO_OTHERS;
1026f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static Bitmap DATE_BACKGROUND;
10354467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira    private static Bitmap STATE_REPLIED;
10454467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira    private static Bitmap STATE_FORWARDED;
10554467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira    private static Bitmap STATE_REPLIED_AND_FORWARDED;
1068d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira    private static Bitmap STATE_CALENDAR_INVITE;
1076f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
108ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static String sSendersSplitToken;
109ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static String sElidedPaddingToken;
11084cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira    private static String sEllipsis;
11124538e893ef2db41a4c1b341f676b64422920304Mindy Pereira
1126f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Static colors.
113ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sDefaultTextColor;
114ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sActivatedTextColor;
115ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sSubjectTextColorRead;
116ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sSubjectTextColorUnead;
117ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sSnippetTextColorRead;
118ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sSnippetTextColorUnread;
119ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sSendersTextColorRead;
120ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sSendersTextColorUnread;
121ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sDateTextColor;
122ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sDateBackgroundPaddingLeft;
123ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private static int sTouchSlop;
1246f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static int sDateBackgroundHeight;
1256f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static int sStandardScaledDimen;
126067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private static int sShrinkAnimationDuration;
127067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private static int sSlideAnimationDuration;
1286f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1296f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Static paints.
1306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static TextPaint sPaint = new TextPaint();
13130fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira    private static TextPaint sFoldersPaint = new TextPaint();
1326f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1336f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Backgrounds for different states.
1346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private final SparseArray<Drawable> mBackgrounds = new SparseArray<Drawable>();
1356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    // Dimensions and coordinates.
1376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mViewWidth = -1;
1386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mMode = -1;
1396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mDateX;
1406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mPaperclipX;
14130fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira    private int mFoldersXEnd;
1426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int mSendersWidth;
1436f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    /** Whether we're running under test mode. */
1456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private boolean mTesting = false;
146fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal    /** Whether we are on a tablet device or not */
147fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal    private final boolean mTabletDevice;
1486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @VisibleForTesting
1500944e5e69312666b89fda025430b7cf03bca4305Mindy Pereira    ConversationItemViewCoordinates mCoordinates;
1516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private final Context mContext;
1536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
154866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public ConversationItemViewModel mHeader;
155c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    private boolean mDownEvent;
156d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal    private boolean mChecked = false;
1576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static int sFadedActivatedColor = -1;
15811b0bbdf024ec1413f90b2baac2c18a8f1c01d71Mindy Pereira    private ConversationSelectionSet mSelectedConversationSet;
1594584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    private Folder mDisplayedFolder;
1603cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira    private boolean mPriorityMarkersEnabled;
161b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    private boolean mCheckboxesEnabled;
162464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira    private HandleLongPress mPendingCheckForLongPress;
163f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira    private boolean mSwipeEnabled;
164acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    private int mLastTouchX;
165acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    private int mLastTouchY;
166bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook    private AnimatedAdapter mAdapter;
167bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    private int mAnimatedHeight = -1;
168c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira    private String mAccount;
169464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira    private Runnable mListItemClick;
170e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira    private ControllableActivity mActivity;
171fb7bace9a83abf0e8726def19e76cb03afdf5740Mindy Pereira    private static Bitmap sDateBackgroundAttachment;
172fb7bace9a83abf0e8726def19e76cb03afdf5740Mindy Pereira    private static Bitmap sDateBackgroundNoAttachment;
173350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira    private static int sUndoAnimationOffset;
174b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira    private static Bitmap MORE_FOLDERS;
1756f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1766f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    static {
1776f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setAntiAlias(true);
17830fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira        sFoldersPaint.setAntiAlias(true);
1796f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
1806f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
181b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira    /**
182b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira     * Handles displaying folders in a conversation header view.
183b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira     */
184b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira    static class ConversationItemFolderDisplayer extends FolderDisplayer {
185b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        // Maximum number of folders to be displayed.
186b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        private static final int MAX_DISPLAYED_FOLDERS_COUNT = 4;
187b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
188b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        private int mFoldersCount;
189b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        private boolean mHasMoreFolders;
190b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
191c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang        public ConversationItemFolderDisplayer(Context context) {
192c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            super(context);
193c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang        }
194c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang
195b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        @Override
19685c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira        public void loadConversationFolders(Conversation conv, Folder ignoreFolder) {
19785c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira            super.loadConversationFolders(conv, ignoreFolder);
198b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
199c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            mFoldersCount = mFoldersSortedSet.size();
200b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            mHasMoreFolders = mFoldersCount > MAX_DISPLAYED_FOLDERS_COUNT;
201b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            mFoldersCount = Math.min(mFoldersCount, MAX_DISPLAYED_FOLDERS_COUNT);
202b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
203b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
204b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        public boolean hasVisibleFolders() {
205b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            return mFoldersCount > 0;
206b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
207b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
208b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        private int measureFolders(int mode) {
209b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int availableSpace = ConversationItemViewCoordinates.getFoldersWidth(mContext, mode);
210b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int cellSize = ConversationItemViewCoordinates.getFolderCellWidth(mContext, mode,
211b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    mFoldersCount);
212b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
213b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int totalWidth = 0;
214c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            for (Folder f : mFoldersSortedSet) {
215c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                final String folderString = f.name;
216c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                int width = (int) sFoldersPaint.measureText(folderString) + cellSize;
217b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (width % cellSize != 0) {
218b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    width += cellSize - (width % cellSize);
219b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
220b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                totalWidth += width;
221b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (totalWidth > availableSpace) {
222b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    break;
223b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
224b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            }
225b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
226b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            return totalWidth;
227b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
228b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
229b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        public void drawFolders(Canvas canvas, ConversationItemViewCoordinates coordinates,
230b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                int foldersXEnd, int mode) {
231b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            if (mFoldersCount == 0) {
232b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                return;
233b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            }
234b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
235b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int xEnd = foldersXEnd;
236b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int y = coordinates.foldersY - coordinates.foldersAscent;
237b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int height = coordinates.foldersHeight;
238b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int topPadding = coordinates.foldersTopPadding;
239b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int ascent = coordinates.foldersAscent;
240b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            sFoldersPaint.setTextSize(coordinates.foldersFontSize);
241b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
242b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            // Initialize space and cell size based on the current mode.
243b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int availableSpace = ConversationItemViewCoordinates.getFoldersWidth(mContext, mode);
244b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int averageWidth = availableSpace / mFoldersCount;
245b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int cellSize = ConversationItemViewCoordinates.getFolderCellWidth(mContext, mode,
246b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    mFoldersCount);
247b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
248b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            // First pass to calculate the starting point.
249b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int totalWidth = measureFolders(mode);
250b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            int xStart = xEnd - Math.min(availableSpace, totalWidth);
251b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
252b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            // Second pass to draw folders.
253c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            for (Folder f : mFoldersSortedSet) {
254c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                final String folderString = f.name;
255c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                final int fgColor = f.getForegroundColor(mDefaultFgColor);
256c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                final int bgColor = f.getBackgroundColor(mDefaultBgColor);
257b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                int width = cellSize;
258b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                boolean labelTooLong = false;
259c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                width = (int) sFoldersPaint.measureText(folderString) + cellSize;
260b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (width % cellSize != 0) {
261b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    width += cellSize - (width % cellSize);
262b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
263b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (totalWidth > availableSpace && width > averageWidth) {
264b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    width = averageWidth;
265a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    labelTooLong = true;
266b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
267b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
268b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                // TODO (mindyp): how to we get this?
269b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                final boolean isMuted = false;
270bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                // labelValues.folderId ==
271bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook                // sGmail.getFolderMap(mAccount).getFolderIdIgnored();
272b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
273b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                // Draw the box.
274c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                sFoldersPaint.setColor(bgColor);
275b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                sFoldersPaint.setStyle(isMuted ? Paint.Style.STROKE : Paint.Style.FILL_AND_STROKE);
276b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                canvas.drawRect(xStart, y + ascent, xStart + width, y + ascent + height,
277b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                        sFoldersPaint);
278b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
279b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                // Draw the text.
280c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang                int padding = getPadding(width, (int) sFoldersPaint.measureText(folderString));
281b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (labelTooLong) {
282a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    TextPaint shortPaint = new TextPaint();
283a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    shortPaint.setColor(fgColor);
284a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    shortPaint.setTextSize(coordinates.foldersFontSize);
285b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    padding = cellSize / 2;
286b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    int rightBorder = xStart + width - padding;
287b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    Shader shader = new LinearGradient(rightBorder - padding, y, rightBorder, y,
288a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                            fgColor, Utils.getTransparentColor(fgColor), Shader.TileMode.CLAMP);
289a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    shortPaint.setShader(shader);
290a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    canvas.drawText(folderString, xStart + padding, y + topPadding, shortPaint);
291a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                } else {
292a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    sFoldersPaint.setColor(fgColor);
293a293987a6bc4d0b1089db95555abc9ac32939882Mindy Pereira                    canvas.drawText(folderString, xStart + padding, y + topPadding, sFoldersPaint);
294b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
295b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
296b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                availableSpace -= width;
297b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                xStart += width;
298b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (availableSpace <= 0 && mHasMoreFolders) {
299b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    canvas.drawBitmap(MORE_FOLDERS, xEnd, y + ascent, sFoldersPaint);
300b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    return;
301b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
302b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            }
303b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
304acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
305b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
306acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    /**
307acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira     * Helpers function to align an element in the center of a space.
308acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira     */
309acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    private static int getPadding(int space, int length) {
310acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        return (space - length) / 2;
311b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira    }
312b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
3130944e5e69312666b89fda025430b7cf03bca4305Mindy Pereira    public ConversationItemView(Context context, String account) {
3146f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        super(context);
3156f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mContext = context.getApplicationContext();
316fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal        mTabletDevice = Utils.useTabletUI(mContext);
317c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira        mAccount = account;
318464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        final View item = this;
319464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        mListItemClick = new Runnable() {
320464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira            @Override
321464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira            public void run() {
322464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                ListView list = getListView();
323464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                if (list != null) {
324464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                    int pos = list.getPositionForView(item);
325464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                    list.performItemClick(item, pos, mHeader.conversation.id);
326464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                }
327464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira            }
328464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        };
3296f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        Resources res = mContext.getResources();
3306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
3316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (CHECKMARK_OFF == null) {
3326f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Initialize static bitmaps.
3336f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            CHECKMARK_OFF = BitmapFactory.decodeResource(res,
3346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.btn_check_off_normal_holo_light);
3356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            CHECKMARK_ON = BitmapFactory.decodeResource(res,
3366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.btn_check_on_normal_holo_light);
3376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            STAR_OFF = BitmapFactory.decodeResource(res,
3386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.btn_star_off_normal_email_holo_light);
3396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            STAR_ON = BitmapFactory.decodeResource(res,
3406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.btn_star_on_normal_email_holo_light);
3416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            ONLY_TO_ME = BitmapFactory.decodeResource(res, R.drawable.ic_email_caret_double);
3426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            TO_ME_AND_OTHERS = BitmapFactory.decodeResource(res, R.drawable.ic_email_caret_single);
3436f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            IMPORTANT_ONLY_TO_ME = BitmapFactory.decodeResource(res,
3446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.ic_email_caret_double_important_unread);
3456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            IMPORTANT_TO_ME_AND_OTHERS = BitmapFactory.decodeResource(res,
3466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.ic_email_caret_single_important_unread);
3476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            IMPORTANT_TO_OTHERS = BitmapFactory.decodeResource(res,
3486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    R.drawable.ic_email_caret_none_important_unread);
3496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            ATTACHMENT = BitmapFactory.decodeResource(res, R.drawable.ic_attachment_holo_light);
350b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            MORE_FOLDERS = BitmapFactory.decodeResource(res, R.drawable.ic_folders_more);
351e9a81035bcef5a372fa13a992f8553eb60e6aaf0Vikram Aggarwal            DATE_BACKGROUND = BitmapFactory.decodeResource(res, R.drawable.folder_bg_holo_light);
35254467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            STATE_REPLIED =
35354467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_reply_holo_light);
35454467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            STATE_FORWARDED =
35554467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_forward_holo_light);
35654467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            STATE_REPLIED_AND_FORWARDED =
35754467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_reply_forward_holo_light);
3588d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira            STATE_CALENDAR_INVITE =
3598d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira                    BitmapFactory.decodeResource(res, R.drawable.ic_badge_invite_holo_light);
3606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
3616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Initialize colors.
362ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sDefaultTextColor = res.getColor(R.color.default_text_color);
363ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sActivatedTextColor = res.getColor(android.R.color.white);
364ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSubjectTextColorRead = res.getColor(R.color.subject_text_color_read);
365ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSubjectTextColorUnead = res.getColor(R.color.subject_text_color_unread);
366ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSnippetTextColorRead = res.getColor(R.color.snippet_text_color_read);
367ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSnippetTextColorUnread = res.getColor(R.color.snippet_text_color_unread);
368ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSendersTextColorRead = res.getColor(R.color.senders_text_color_read);
369ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSendersTextColorUnread = res.getColor(R.color.senders_text_color_unread);
370ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sDateTextColor = res.getColor(R.color.date_text_color);
371ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sDateBackgroundPaddingLeft = res
3726f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    .getDimensionPixelSize(R.dimen.date_background_padding_left);
373ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sTouchSlop = res.getDimensionPixelSize(R.dimen.touch_slop);
3746f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sDateBackgroundHeight = res.getDimensionPixelSize(R.dimen.date_background_height);
3756f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sStandardScaledDimen = res.getDimensionPixelSize(R.dimen.standard_scaled_dimen);
376067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            sShrinkAnimationDuration = res.getInteger(R.integer.shrink_animation_duration);
377067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            sSlideAnimationDuration = res.getInteger(R.integer.slide_animation_duration);
378350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            sUndoAnimationOffset = res.getDimensionPixelOffset(R.dimen.undo_animation_offset);
3796f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Initialize static color.
380ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sSendersSplitToken = res.getString(R.string.senders_split_token);
381ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sElidedPaddingToken = res.getString(R.string.elided_padding_token);
38284cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira            sEllipsis = res.getString(R.string.ellipsis);
3836f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
3846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
3856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
386e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira    public void bind(Cursor cursor, ControllableActivity activity, ConversationSelectionSet set,
387e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira            Folder folder, boolean checkboxesDisabled, boolean swipeEnabled,
388e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira            boolean priorityArrowEnabled, AnimatedAdapter adapter) {
389e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        bind(ConversationItemViewModel.forCursor(mAccount, cursor), activity, set, folder,
39033519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal                checkboxesDisabled, swipeEnabled, priorityArrowEnabled, adapter);
391b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    }
392b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira
393e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira    public void bind(Conversation conversation, ControllableActivity activity,
394e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira            ConversationSelectionSet set, Folder folder, boolean checkboxesDisabled,
395e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira            boolean swipeEnabled, boolean priorityArrowEnabled, AnimatedAdapter adapter) {
396e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        bind(ConversationItemViewModel.forConversation(mAccount, conversation), activity, set,
39733519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal                folder, checkboxesDisabled, swipeEnabled, priorityArrowEnabled, adapter);
398acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
399acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
400e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira    private void bind(ConversationItemViewModel header, ControllableActivity activity,
401acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            ConversationSelectionSet set, Folder folder, boolean checkboxesDisabled,
40233519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal            boolean swipeEnabled, boolean priorityArrowEnabled, AnimatedAdapter adapter) {
403acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        mHeader = header;
404e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        mActivity = activity;
405b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        mSelectedConversationSet = set;
406b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        mDisplayedFolder = folder;
40790fc0ffa0ad4fcde94fa9648df7f8041bfb6a943Mindy Pereira        mCheckboxesEnabled = !checkboxesDisabled;
408f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        mSwipeEnabled = swipeEnabled;
40933519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal        mPriorityMarkersEnabled = priorityArrowEnabled;
410bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook        mAdapter = adapter;
411f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira        setContentDescription(mHeader.getContentDescription(mContext));
412f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira        requestLayout();
413f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira    }
414f9573c5f07bcc05409b5d4c15772884c5313c407Mindy Pereira
415866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
416866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * Get the Conversation object associated with this view.
417866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
418732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang    public Conversation getConversation() {
419732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang        return mHeader.conversation;
420732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang    }
421732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang
4226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    /**
4236f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * Sets the mode. Only used for testing.
4246f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     */
4256f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @VisibleForTesting
4266f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    void setMode(int mode) {
4276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mMode = mode;
4286f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mTesting = true;
4296f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
4306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static void startTimer(String tag) {
4326f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (sTimer != null) {
4336f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer.start(tag);
4346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
4366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private static void pauseTimer(String tag) {
4386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (sTimer != null) {
4396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer.pause(tag);
4406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
4426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4436f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @Override
4446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
4456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_LAYOUT);
4466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        super.onLayout(changed, left, top, right, bottom);
4486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        int width = right - left;
4506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (width != mViewWidth) {
4516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mViewWidth = width;
4526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (!mTesting) {
453e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira                mMode = ConversationItemViewCoordinates.getMode(mContext, mActivity.getViewMode());
4546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
4556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.viewWidth = mViewWidth;
4576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        Resources res = getResources();
4586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.standardScaledDimen = res.getDimensionPixelOffset(R.dimen.standard_scaled_dimen);
4596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.standardScaledDimen != sStandardScaledDimen) {
4606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Large Text has been toggle on/off. Update the static dimens.
4616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sStandardScaledDimen = mHeader.standardScaledDimen;
4620944e5e69312666b89fda025430b7cf03bca4305Mindy Pereira            ConversationItemViewCoordinates.refreshConversationHeights(mContext);
4636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sDateBackgroundHeight = res.getDimensionPixelSize(R.dimen.date_background_height);
4646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4650944e5e69312666b89fda025430b7cf03bca4305Mindy Pereira        mCoordinates = ConversationItemViewCoordinates.forWidth(mContext, mViewWidth, mMode,
4666f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                mHeader.standardScaledDimen);
4676f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        calculateTextsAndBitmaps();
4686f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        calculateCoordinates();
4696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.validate(mContext);
4706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4716f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        pauseTimer(PERF_TAG_LAYOUT);
4726f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (sTimer != null && ++sLayoutCount >= PERF_LAYOUT_ITERATIONS) {
4736f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer.dumpResults();
4746f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sTimer = new Timer();
4756f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            sLayoutCount = 0;
4766f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4776f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
4786f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4796f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @Override
4806f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    public void setBackgroundResource(int resourceId) {
4816f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        Drawable drawable = mBackgrounds.get(resourceId);
4826f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (drawable == null) {
4836f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            drawable = getResources().getDrawable(resourceId);
4846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mBackgrounds.put(resourceId, drawable);
4856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4866f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (getBackground() != drawable) {
4876f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            super.setBackgroundDrawable(drawable);
4886f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
4896f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
4906f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
4916f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void calculateTextsAndBitmaps() {
4926f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
493d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal        if (mSelectedConversationSet != null) {
494d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal            mChecked = mSelectedConversationSet.contains(mHeader.conversation);
495d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal        }
4966f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Update font color.
497ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        int fontColor = getFontColor(sDefaultTextColor);
4986f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        boolean fontChanged = false;
4996f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.fontColor != fontColor) {
5006f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            fontChanged = true;
5016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mHeader.fontColor = fontColor;
5026f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
5036f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5048d69d4e10a9a36ff790babb2f3a098a12d0dc732Marc Blank        boolean isUnread = mHeader.unread;
5056f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
506b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        final boolean checkboxEnabled = mCheckboxesEnabled;
5076f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.checkboxVisible != checkboxEnabled) {
5086f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mHeader.checkboxVisible = checkboxEnabled;
5096f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
5106f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5116f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Update background.
5126f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        updateBackground(isUnread);
5136f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5146f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.isLayoutValid(mContext)) {
5156f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // Relayout subject if font color has changed.
5166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (fontChanged) {
5170b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                layoutSubjectSpans(isUnread);
5186f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                layoutSubject();
5196f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
5206f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            pauseTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
5216f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            return;
5226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
5236f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
52430fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira        startTimer(PERF_TAG_CALCULATE_FOLDERS);
525b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
526b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        // Initialize folder displayer.
527b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        if (mCoordinates.showFolders) {
528c03208720e5650f0acb748f82ed10ac770d6ceb4Andy Huang            mHeader.folderDisplayer = new ConversationItemFolderDisplayer(mContext);
52985c4a77abd849f5f3f0236d51554bb1bb99fe8f6Mindy Pereira            mHeader.folderDisplayer.loadConversationFolders(mHeader.conversation, mDisplayedFolder);
530b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
531b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
53230fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira        pauseTimer(PERF_TAG_CALCULATE_FOLDERS);
5336f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
534732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang        mHeader.dateText = DateUtils.getRelativeTimeSpanString(mContext,
535732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang                mHeader.conversation.dateMs).toString();
5366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Paper clip icon.
5386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.paperclip = null;
539732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang        if (mHeader.conversation.hasAttachments) {
5406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mHeader.paperclip = ATTACHMENT;
5416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
5426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Personal level.
5436f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mHeader.personalLevelBitmap = null;
5443cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira        if (mCoordinates.showPersonalLevel) {
54533519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal            final int personalLevel = mHeader.personalLevel;
5463cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira            final boolean isImportant =
5473cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira                    mHeader.priority == UIProvider.ConversationPriority.IMPORTANT;
54833519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal            final boolean useImportantMarkers = isImportant && mPriorityMarkersEnabled;
5493cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira
5503cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira            if (personalLevel == UIProvider.ConversationPersonalLevel.ONLY_TO_ME) {
5513cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira                mHeader.personalLevelBitmap = useImportantMarkers ? IMPORTANT_ONLY_TO_ME
5523cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira                        : ONLY_TO_ME;
5533cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira            } else if (personalLevel == UIProvider.ConversationPersonalLevel.TO_ME_AND_OTHERS) {
5543cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira                mHeader.personalLevelBitmap = useImportantMarkers ? IMPORTANT_TO_ME_AND_OTHERS
5553cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira                        : TO_ME_AND_OTHERS;
5563cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira            } else if (useImportantMarkers) {
5573cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira                mHeader.personalLevelBitmap = IMPORTANT_TO_OTHERS;
5583cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira            }
5593cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira        }
5606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_CALCULATE_SENDER_SUBJECT);
5626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Subject.
5640b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        layoutSubjectSpans(isUnread);
5656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
566d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang        mHeader.sendersDisplayText = new SpannableStringBuilder();
5676c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira        mHeader.styledSendersString = new SpannableStringBuilder();
568d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang
5696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Parse senders fragments.
570c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira        if (mHeader.conversation.conversationInfo != null) {
571b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            Context context = getContext();
572b821e306583115e5fce8a8f0383019ae6268b1ccMindy Pereira            mHeader.messageInfoString = SendersView
573b821e306583115e5fce8a8f0383019ae6268b1ccMindy Pereira                    .createMessageInfo(context, mHeader.conversation);
574b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            int maxChars = ConversationItemViewCoordinates.getSubjectLength(context,
575e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira                    ConversationItemViewCoordinates.getMode(context, mActivity.getViewMode()),
576b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                    mHeader.folderDisplayer != null && mHeader.folderDisplayer.mFoldersCount > 0,
577b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                    mHeader.conversation.hasAttachments);
578b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            mHeader.styledSenders = SendersView.format(context,
579b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                    mHeader.conversation.conversationInfo, mHeader.messageInfoString.toString(),
580b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                    maxChars);
581c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira        } else {
58277d7f3c3c8c82048b51025428a825f6ac71e8560Mindy Pereira            SendersView.formatSenders(mHeader, getContext());
583c3efca18f09904f4ce39395169559c5d82bd3d06Mindy Pereira        }
5846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        pauseTimer(PERF_TAG_CALCULATE_SENDER_SUBJECT);
5866f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        pauseTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
5876f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
5886f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
5890b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    private void layoutSubjectSpans(boolean isUnread) {
5900b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        if (showActivatedText()) {
5910b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            mHeader.subjectTextActivated = createSubject(isUnread, true);
5920b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        }
5930b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        mHeader.subjectText = createSubject(isUnread, false);
5940b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    }
5950b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira
5960b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    private SpannableStringBuilder createSubject(boolean isUnread, boolean activated) {
597732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang        final String subject = filterTag(mHeader.conversation.subject);
598aa1f945612847bc4cf5c8909b8acfab4b5ecf54eMindy Pereira        final String snippet = mHeader.conversation.getSnippet();
599ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        int subjectColor = activated ? sActivatedTextColor : isUnread ? sSubjectTextColorUnead
600ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                : sSubjectTextColorRead;
601ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        int snippetColor = activated ? sActivatedTextColor : isUnread ? sSnippetTextColorUnread
602ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                : sSnippetTextColorRead;
603bf9508d3877d05742b2f5d23e1780366d3e1aa2eMindy Pereira        SpannableStringBuilder subjectText = Conversation.getSubjectAndSnippetForDisplay(mContext,
604bf9508d3877d05742b2f5d23e1780366d3e1aa2eMindy Pereira                subject, snippet);
6056f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (isUnread) {
6060b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            subjectText.setSpan(new StyleSpan(Typeface.BOLD), 0, subject.length(),
6076f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
6086f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
6090b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        subjectText.setSpan(new ForegroundColorSpan(subjectColor), 0, subject.length(),
6100b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
611304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blank        if (snippet != null) {
6120b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            subjectText.setSpan(new ForegroundColorSpan(snippetColor), subject.length() + 1,
6130b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                    subjectText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
614304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blank        }
6150b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        return subjectText;
6166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
6176f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6186f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private int getFontColor(int defaultColor) {
619ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        return isActivated() && mTabletDevice ? sActivatedTextColor
6206f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                : defaultColor;
6216f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
6226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6230b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    private boolean showActivatedText() {
6240b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        return mTabletDevice;
6250b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    }
6260b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira
6276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void layoutSubject() {
6280b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        if (showActivatedText()) {
6290b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            mHeader.subjectLayoutActivated =
6300b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                    createSubjectLayout(true, mHeader.subjectTextActivated);
6310b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        }
6320b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        mHeader.subjectLayout = createSubjectLayout(false, mHeader.subjectText);
6330b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    }
6340b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira
6350b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira    private StaticLayout createSubjectLayout(boolean activated,
6360b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            SpannableStringBuilder subjectText) {
6376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTextSize(mCoordinates.subjectFontSize);
638ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        sPaint.setColor(activated ? sActivatedTextColor
639ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                : mHeader.unread ? sSubjectTextColorUnead : sSubjectTextColorRead);
6400b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        StaticLayout subjectLayout = new StaticLayout(subjectText, sPaint,
6416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
6420b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        int lineCount = subjectLayout.getLineCount();
6430b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        if (mCoordinates.subjectLineCount < lineCount) {
6440b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            int end = subjectLayout.getLineEnd(mCoordinates.subjectLineCount - 1);
6450b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            subjectLayout = new StaticLayout(subjectText.subSequence(0, end), sPaint,
6460b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                    mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
6476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
6480b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        return subjectLayout;
6496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
6506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private boolean canFitFragment(int width, int line, int fixedWidth) {
6526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (line == mCoordinates.sendersLineCount) {
6536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            return width + fixedWidth <= mSendersWidth;
6546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        } else {
6556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            return width <= mSendersWidth;
6566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
6576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
6586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void calculateCoordinates() {
6606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        startTimer(PERF_TAG_CALCULATE_COORDINATES);
6616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTextSize(mCoordinates.dateFontSize);
6636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTypeface(Typeface.DEFAULT);
6646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mDateX = mCoordinates.dateXEnd - (int) sPaint.measureText(mHeader.dateText);
6656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6666f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        mPaperclipX = mDateX - ATTACHMENT.getWidth();
6676f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
66830fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira        int cellWidth = mContext.getResources().getDimensionPixelSize(R.dimen.folder_cell_width);
6696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
6703fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira        if (ConversationItemViewCoordinates.isWideMode(mMode)) {
6713fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            // Folders are displayed above the date.
6723fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            mFoldersXEnd = mCoordinates.dateXEnd;
6733fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            // In wide mode, the end of the senders should align with
6743fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            // the start of the subject and is based on a max width.
6753fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            mSendersWidth = mCoordinates.sendersWidth;
6763fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira        } else {
6773fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            // In normal mode, the width is based on where the folders or date
6783fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            // (or attachment icon) start.
6793fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira            if (mCoordinates.showFolders) {
680b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (mHeader.paperclip != null) {
681b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    mFoldersXEnd = mPaperclipX;
682b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                } else {
683b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    mFoldersXEnd = mDateX - cellWidth / 2;
684b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
685b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                mSendersWidth = mFoldersXEnd - mCoordinates.sendersX - 2 * cellWidth;
686b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                if (mHeader.folderDisplayer.hasVisibleFolders()) {
687b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                    mSendersWidth -= ConversationItemViewCoordinates.getFoldersWidth(mContext,
688b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                            mMode);
689b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira                }
6906f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            } else {
6913fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                int dateAttachmentStart = 0;
6923fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                // Have this end near the paperclip or date, not the folders.
6933fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                if (mHeader.paperclip != null) {
6943fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                    dateAttachmentStart = mPaperclipX;
6953fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                } else {
6963fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                    dateAttachmentStart = mDateX;
6973fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                }
6983fd1f2c4cba9095ccd024ac26187cba6fdfc367bMindy Pereira                mSendersWidth = dateAttachmentStart - mCoordinates.sendersX - cellWidth;
6996f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
7006f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
7016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
7026f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.isLayoutValid(mContext)) {
7036f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            pauseTimer(PERF_TAG_CALCULATE_COORDINATES);
7046f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            return;
7056f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
7066f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
7076f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Layout subject.
7086f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        layoutSubject();
7096f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
7106f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Second pass to layout each fragment.
7116f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        int sendersY = mCoordinates.sendersY - mCoordinates.sendersAscent;
712ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira
713b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        if (mHeader.styledSenders != null) {
714ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            ellipsizeStyledSenders();
715b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            mHeader.sendersDisplayLayout = new StaticLayout(mHeader.styledSendersString, sPaint,
716b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                    mSendersWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
717b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        } else {
718ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            // First pass to calculate width of each fragment.
719ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            int totalWidth = 0;
720ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            int fixedWidth = 0;
721ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sPaint.setTextSize(mCoordinates.sendersFontSize);
722ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sPaint.setTypeface(Typeface.DEFAULT);
723ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            for (SenderFragment senderFragment : mHeader.senderFragments) {
724ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                CharacterStyle style = senderFragment.style;
725ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                int start = senderFragment.start;
726ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                int end = senderFragment.end;
727ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                style.updateDrawState(sPaint);
728ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                senderFragment.width = (int) sPaint.measureText(mHeader.sendersText, start, end);
729ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                boolean isFixed = senderFragment.isFixed;
730ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                if (isFixed) {
731ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                    fixedWidth += senderFragment.width;
732ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                }
733ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                totalWidth += senderFragment.width;
734ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            }
735ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira
736ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            if (!ConversationItemViewCoordinates.displaySendersInline(mMode)) {
737ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                sendersY += totalWidth <= mSendersWidth ? mCoordinates.sendersLineHeight / 2 : 0;
738ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            }
73958ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            totalWidth = ellipsize(fixedWidth, sendersY);
740b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            mHeader.sendersDisplayLayout = new StaticLayout(mHeader.sendersDisplayText, sPaint,
741b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                    mSendersWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
742b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        }
743b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
744b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        sPaint.setTextSize(mCoordinates.sendersFontSize);
745b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        sPaint.setTypeface(Typeface.DEFAULT);
746b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        if (mSendersWidth < 0) {
747b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            mSendersWidth = 0;
748b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        }
749b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
750b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        pauseTimer(PERF_TAG_CALCULATE_COORDINATES);
751b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira    }
752b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
75358ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // The rules for displaying ellipsized senders are as follows:
75458ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // 1) If there is message info (either a COUNT or DRAFT info to display), it MUST be shown
75558ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // 2) If senders do not fit, ellipsize the last one that does fit, and stop
75658ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    // appending new senders
757ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira    private int ellipsizeStyledSenders() {
758b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        SpannableStringBuilder builder = new SpannableStringBuilder();
75984cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira        float totalWidth = 0;
760b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        boolean ellipsize = false;
7616c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira        SpannableString ellipsizedText;
76284cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira        float width;
763b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira        SpannableStringBuilder messageInfoString = mHeader.messageInfoString;
7640c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira        if (messageInfoString.length() > 0) {
7650c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            CharacterStyle[] spans = messageInfoString.getSpans(0, messageInfoString.length(),
7660c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira                    CharacterStyle.class);
7670c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            // There is only 1 character style span; make sure we apply all the
7680c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            // styles to the paint object before measuring.
7690c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            if (spans.length > 0) {
7700c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira                spans[0].updateDrawState(sPaint);
7710c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            }
7720c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            // Paint the message info string to see if we lose space.
7730c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            float messageInfoWidth = sPaint.measureText(messageInfoString.toString());
7740c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira            totalWidth += messageInfoWidth;
7750c2e567e792d557de1d80ef25f82aaf3c41c22b6Mindy Pereira        }
776b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira        SpannableString prevSender = null;
777b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        for (SpannableString sender : mHeader.styledSenders) {
778feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira            // There may be null sender strings if there were dupes we had to remove.
779feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira            if (sender == null) {
780feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira                continue;
781feffa26a40e933ad0ff4700e2bf9e0555f0f8470Mindy Pereira            }
78258ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            // No more width available, we'll only show fixed fragments.
78358ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            if (ellipsize) {
78458ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira                break;
78558ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            }
7866c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            CharacterStyle[] spans = sender.getSpans(0, sender.length(), CharacterStyle.class);
7876c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            // There is only 1 character style span.
7886c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            if (spans.length > 0) {
7896c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira                spans[0].updateDrawState(sPaint);
7906c2663dc9cade8aff34c462d244e3d72c475c664Mindy Pereira            }
7911152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            // If there are already senders present in this string, we need to
7921152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            // make sure we prepend the dividing token
793b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            if (SendersView.sElidedString.equals(sender.toString())) {
794b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                prevSender = sender;
795ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                sender = copyStyles(spans, sElidedPaddingToken + sender + sElidedPaddingToken);
796b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            } else if (builder.length() > 0
797b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                    && (prevSender == null || !SendersView.sElidedString.equals(prevSender
798b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                            .toString()))) {
799b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                prevSender = sender;
800ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                sender = copyStyles(spans, sSendersSplitToken + sender);
801b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira            } else {
802b1cbb89f72631bb7e34822b98e8d0842ebd01b83Mindy Pereira                prevSender = sender;
8031152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            }
8041152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            // Measure the width of the current sender and make sure we have space
805b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            width = (int) sPaint.measureText(sender.toString());
806ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            if (width + totalWidth > mSendersWidth) {
807b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                // The text is too long, new line won't help. We have to
808b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                // ellipsize text.
8091152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                ellipsize = true;
81084cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira                width = mSendersWidth - totalWidth - getEllipsisWidth(); // ellipsis width?
8111152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                ellipsizedText = copyStyles(spans,
8121152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                        TextUtils.ellipsize(sender, sPaint, width, TruncateAt.END));
8131152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                width = (int) sPaint.measureText(ellipsizedText.toString());
8141152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira            } else {
8151152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                ellipsizedText = null;
816b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            }
817b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            totalWidth += width;
818b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
819b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            final CharSequence fragmentDisplayText;
820b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            if (ellipsizedText != null) {
821b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira                fragmentDisplayText = ellipsizedText;
822b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            } else {
8231152c02a415f5b93bdecc5733a7372dca7d9ecd3Mindy Pereira                fragmentDisplayText = sender;
824b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            }
825b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira            builder.append(fragmentDisplayText);
826b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        }
82758ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira        if (messageInfoString.length() > 0) {
82858ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira            builder.append(messageInfoString);
82958ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira        }
830b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        mHeader.styledSendersString = builder;
83184cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira        return (int)totalWidth;
83284cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira    }
83384cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira
83484cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira    private float getEllipsisWidth() {
83584cef5e3457338d22dc3e96dc6feeaf9e50e4d57Mindy Pereira        return sPaint.measureText(sEllipsis);
836b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira    }
837b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira
838d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira    private SpannableString copyStyles(CharacterStyle[] spans, CharSequence newText) {
839d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        SpannableString s = new SpannableString(newText);
840d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        if (spans != null && spans.length > 0) {
841d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira            s.setSpan(spans[0], 0, s.length(), 0);
842d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        }
843d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira        return s;
844d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira    }
845d8e5ff44a8a7405bb8891fb46570782138babbd1Mindy Pereira
84658ef69ad99623fd8795a95227aa718d3d6177c5aMindy Pereira    private int ellipsize(int fixedWidth, int sendersY) {
847b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        int totalWidth = 0;
8486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        int currentLine = 1;
8496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        boolean ellipsize = false;
8506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        for (SenderFragment senderFragment : mHeader.senderFragments) {
8516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            CharacterStyle style = senderFragment.style;
8526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int start = senderFragment.start;
8536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int end = senderFragment.end;
8546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int width = senderFragment.width;
8556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            boolean isFixed = senderFragment.isFixed;
8566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            style.updateDrawState(sPaint);
8576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
8586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // No more width available, we'll only show fixed fragments.
8596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (ellipsize && !isFixed) {
8606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                senderFragment.shouldDisplay = false;
8616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                continue;
8626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
8636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
8646f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            // New line and ellipsize text if needed.
8656f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            senderFragment.ellipsizedText = null;
8666f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (isFixed) {
8676f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                fixedWidth -= width;
8686f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
8696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (!canFitFragment(totalWidth + width, currentLine, fixedWidth)) {
8706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                // The text is too long, new line won't help. We have to
8716f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                // ellipsize text.
8726f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                if (totalWidth == 0) {
8736f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    ellipsize = true;
8746f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                } else {
8756f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    // New line.
8766f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    if (currentLine < mCoordinates.sendersLineCount) {
8776f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        currentLine++;
8786f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        sendersY += mCoordinates.sendersLineHeight;
8796f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        totalWidth = 0;
8806f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        // The text is still too long, we have to ellipsize
8816f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        // text.
8826f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        if (totalWidth + width > mSendersWidth) {
8836f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                            ellipsize = true;
8846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        }
8856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    } else {
8866f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        ellipsize = true;
8876f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    }
8886f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                }
8896f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
8906f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                if (ellipsize) {
8916f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    width = mSendersWidth - totalWidth;
8926f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    // No more new line, we have to reserve width for fixed
8936f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    // fragments.
8946f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    if (currentLine == mCoordinates.sendersLineCount) {
8956f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        width -= fixedWidth;
8966f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    }
8976f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    senderFragment.ellipsizedText = TextUtils.ellipsize(
8986f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                            mHeader.sendersText.substring(start, end), sPaint, width,
8996f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                            TruncateAt.END).toString();
9006f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    width = (int) sPaint.measureText(senderFragment.ellipsizedText);
9016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                }
9026f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
9036f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            senderFragment.shouldDisplay = true;
9046f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            totalWidth += width;
905d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang
906d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            final CharSequence fragmentDisplayText;
907d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            if (senderFragment.ellipsizedText != null) {
908d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang                fragmentDisplayText = senderFragment.ellipsizedText;
909d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            } else {
910d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang                fragmentDisplayText = mHeader.sendersText.substring(start, end);
911d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            }
912d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            final int spanStart = mHeader.sendersDisplayText.length();
913d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            mHeader.sendersDisplayText.append(fragmentDisplayText);
914d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang            mHeader.sendersDisplayText.setSpan(senderFragment.style, spanStart,
915d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang                    mHeader.sendersDisplayText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
9166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
917b1207e3ec8fe3ce988996722e13b80a4dfdf1c72Mindy Pereira        return totalWidth;
9186f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
9196f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
9206f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    /**
9216f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * If the subject contains the tag of a mailing-list (text surrounded with
9226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * []), return the subject with that tag ellipsized, e.g.
9236f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     * "[android-gmail-team] Hello" -> "[andr...] Hello"
9246f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira     */
9256f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private String filterTag(String subject) {
9266f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        String result = subject;
9276f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        String formatString = getContext().getResources().getString(R.string.filtered_tag);
9286f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (!TextUtils.isEmpty(subject) && subject.charAt(0) == '[') {
9296f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int end = subject.indexOf(']');
9306f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (end > 0) {
9316f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                String tag = subject.substring(1, end);
9326f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                result = String.format(formatString, Utils.ellipsize(tag, 7),
9336f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        subject.substring(end + 1));
9346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
9356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
9366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        return result;
9376f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
9386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
9396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    @Override
9406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    protected void onDraw(Canvas canvas) {
9416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Check mark.
9426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.checkboxVisible) {
943c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira            Bitmap checkmark = mChecked ? CHECKMARK_ON : CHECKMARK_OFF;
9446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.drawBitmap(checkmark, mCoordinates.checkmarkX, mCoordinates.checkmarkY, sPaint);
9456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
9466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
9476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Personal Level.
9483cb938f638cc3cec08c9c42d20192e65b1e7d343Mindy Pereira        if (mCoordinates.showPersonalLevel && mHeader.personalLevelBitmap != null) {
9496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.drawBitmap(mHeader.personalLevelBitmap, mCoordinates.personalLevelX,
9506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    mCoordinates.personalLevelY, sPaint);
9516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
9526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
9536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Senders.
9548d69d4e10a9a36ff790babb2f3a098a12d0dc732Marc Blank        boolean isUnread = mHeader.unread;
955ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        // Old style senders; apply text colors/ sizes/ styling.
956c1e1fbb0be9fc60a141b8a5a067f4eed035989c1Mindy Pereira        if (mHeader.senderFragments.size() > 0) {
957ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sPaint.setTextSize(mCoordinates.sendersFontSize);
95877d7f3c3c8c82048b51025428a825f6ac71e8560Mindy Pereira            sPaint.setTypeface(SendersView.getTypeface(isUnread));
959ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            int sendersColor = getFontColor(isUnread ? sSendersTextColorUnread
960ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                    : sSendersTextColorRead);
961ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira            sPaint.setColor(sendersColor);
962ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        }
963d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang        canvas.save();
964d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang        canvas.translate(mCoordinates.sendersX,
965d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang                mCoordinates.sendersY + mHeader.sendersDisplayLayout.getTopPadding());
966d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang        mHeader.sendersDisplayLayout.draw(canvas);
967d7a4ad903cd77a2cd3ad44c7c456b48c7d47e599Andy Huang        canvas.restore();
9686f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
9696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Subject.
9706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTextSize(mCoordinates.subjectFontSize);
9716f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTypeface(Typeface.DEFAULT);
9726f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        canvas.save();
9730b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        if (isActivated() && showActivatedText()) {
9740b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            if (mHeader.subjectLayoutActivated != null) {
9750b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                canvas.translate(mCoordinates.subjectX, mCoordinates.subjectY
9760b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                        + mHeader.subjectLayoutActivated.getTopPadding());
9770b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira                mHeader.subjectLayoutActivated.draw(canvas);
9780b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira            }
9790b686764015284889d98b8e9f1abea8b27ce26bdMindy Pereira        } else if (mHeader.subjectLayout != null) {
9804f4334983e01c5f72ef0b14d72356a5736c82decMindy Pereira            canvas.translate(mCoordinates.subjectX,
9814f4334983e01c5f72ef0b14d72356a5736c82decMindy Pereira                    mCoordinates.subjectY + mHeader.subjectLayout.getTopPadding());
9824f4334983e01c5f72ef0b14d72356a5736c82decMindy Pereira            mHeader.subjectLayout.draw(canvas);
9834f4334983e01c5f72ef0b14d72356a5736c82decMindy Pereira        }
9846f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        canvas.restore();
9856f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
986b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        // Folders.
987b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        if (mCoordinates.showFolders) {
988b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira            mHeader.folderDisplayer.drawFolders(canvas, mCoordinates, mFoldersXEnd, mMode);
989b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira        }
990b5080d5335d2aa445a660ad426ab008750be24cbMindy Pereira
99192939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank        // If this folder has a color (combined view/Email), show it here
99292939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank        if (mHeader.conversation.color != 0) {
99392939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            sFoldersPaint.setColor(mHeader.conversation.color);
99492939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            sFoldersPaint.setStyle(Paint.Style.FILL);
99592939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            int width = ConversationItemViewCoordinates.getColorBlockWidth(mContext);
99692939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            int height = ConversationItemViewCoordinates.getColorBlockHeight(mContext);
99792939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank            canvas.drawRect(mCoordinates.dateXEnd - width, 0, mCoordinates.dateXEnd,
99892939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank                    height, sFoldersPaint);
99992939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank        }
100092939fc7b40a56e17fb0d2fde987133ca1614e29Marc Blank
10016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Date background: shown when there is an attachment or a visible
100230fd47bf1947da5ad813cb957b6cbe569dce563aMindy Pereira        // folder.
10036f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (!isActivated()
1004280dbf201cbc555ee59edc4dfe459aebe4ffceadMindy Pereira                && (mHeader.conversation.hasAttachments ||
1005280dbf201cbc555ee59edc4dfe459aebe4ffceadMindy Pereira                        (mHeader.folderDisplayer != null
1006280dbf201cbc555ee59edc4dfe459aebe4ffceadMindy Pereira                            && mHeader.folderDisplayer.hasVisibleFolders()))
10070944e5e69312666b89fda025430b7cf03bca4305Mindy Pereira                && ConversationItemViewCoordinates.showAttachmentBackground(mMode)) {
1008732600e38891db139bae02dc91dd0c5b0987e8e9Andy Huang            int leftOffset = (mHeader.conversation.hasAttachments ? mPaperclipX : mDateX)
1009ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira                    - sDateBackgroundPaddingLeft;
101047ccb45dff1329d5ddac33fb71674048f8c7f51aMindy Pereira            int top = mCoordinates.showFolders ? mCoordinates.foldersY : mCoordinates.dateY;
1011bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            mHeader.dateBackground = getDateBackground(mHeader.conversation.hasAttachments);
1012bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            canvas.drawBitmap(mHeader.dateBackground, leftOffset, top, sPaint);
10136f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        } else {
10146f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            mHeader.dateBackground = null;
10156f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
10166f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
101754467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira        // Draw the reply state. Draw nothing if neither replied nor forwarded.
101854467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira        if (mCoordinates.showReplyState) {
101954467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            if (mHeader.hasBeenRepliedTo && mHeader.hasBeenForwarded) {
102054467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                canvas.drawBitmap(STATE_REPLIED_AND_FORWARDED, mCoordinates.replyStateX,
102154467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                        mCoordinates.replyStateY, null);
102254467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            } else if (mHeader.hasBeenRepliedTo) {
102354467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                canvas.drawBitmap(STATE_REPLIED, mCoordinates.replyStateX,
102454467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                        mCoordinates.replyStateY, null);
102554467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            } else if (mHeader.hasBeenForwarded) {
102654467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                canvas.drawBitmap(STATE_FORWARDED, mCoordinates.replyStateX,
102754467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira                        mCoordinates.replyStateY, null);
10288d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira            } else if (mHeader.isInvite) {
1029d5ac9c16e8955abe8366fd1185b86d8bd7c5ac60Mindy Pereira                canvas.drawBitmap(STATE_CALENDAR_INVITE, mCoordinates.replyStateX,
10308d83c8a0c9c01ce5ed9381f2765b3ba59948710fMindy Pereira                        mCoordinates.replyStateY, null);
103154467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira            }
103254467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira        }
103354467a21dce72130bb04eb5aa1c9813d88308a80Mindy Pereira
10346f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Date.
10356f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTextSize(mCoordinates.dateFontSize);
10366f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        sPaint.setTypeface(Typeface.DEFAULT);
1037ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        sPaint.setColor(sDateTextColor);
10386f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        drawText(canvas, mHeader.dateText, mDateX, mCoordinates.dateY - mCoordinates.dateAscent,
10396f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                sPaint);
10406f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
10416f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Paper clip icon.
10426f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.paperclip != null) {
10436f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.drawBitmap(mHeader.paperclip, mPaperclipX, mCoordinates.paperclipY, sPaint);
10446f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
10456f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
10466f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (mHeader.faded) {
10476f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int fadedColor = -1;
10486f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            if (sFadedActivatedColor == -1) {
10496f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                sFadedActivatedColor = mContext.getResources().getColor(
10506f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                        R.color.faded_activated_conversation_header);
10516f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
10526f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            fadedColor = sFadedActivatedColor;
10536f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            int restoreState = canvas.save();
10546f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            Rect bounds = canvas.getClipBounds();
10556f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.clipRect(bounds.left, bounds.top, bounds.right
10566f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    - mContext.getResources().getDimensionPixelSize(R.dimen.triangle_width),
10576f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    bounds.bottom);
10586f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.drawARGB(Color.alpha(fadedColor), Color.red(fadedColor),
10596f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira                    Color.green(fadedColor), Color.blue(fadedColor));
10606f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            canvas.restoreToCount(restoreState);
10616f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
10626f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
10636f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        // Star.
10644f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira        canvas.drawBitmap(getStarBitmap(), mCoordinates.starX, mCoordinates.starY, sPaint);
10654f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira    }
10664f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira
10674f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira    private Bitmap getStarBitmap() {
10684f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira        return mHeader.conversation.starred ? STAR_ON : STAR_OFF;
10696f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
10706f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
1071bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira    private Bitmap getDateBackground(boolean hasAttachments) {
1072ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        int leftOffset = (hasAttachments ? mPaperclipX : mDateX) - sDateBackgroundPaddingLeft;
1073bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira        if (hasAttachments) {
1074bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            if (sDateBackgroundAttachment == null) {
1075bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira                sDateBackgroundAttachment = Bitmap.createScaledBitmap(DATE_BACKGROUND, mViewWidth
1076bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira                        - leftOffset, sDateBackgroundHeight, false);
1077bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            }
1078bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            return sDateBackgroundAttachment;
1079bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira        } else {
1080bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            if (sDateBackgroundNoAttachment == null) {
1081bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira                sDateBackgroundNoAttachment = Bitmap.createScaledBitmap(DATE_BACKGROUND, mViewWidth
1082bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira                        - leftOffset, sDateBackgroundHeight, false);
1083bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            }
1084bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira            return sDateBackgroundNoAttachment;
1085bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira        }
1086bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira    }
1087bf19cb00a3cc0f65b6b6e5ce8553f53c03a3b717Mindy Pereira
10886f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void drawText(Canvas canvas, CharSequence s, int x, int y, TextPaint paint) {
10896f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        canvas.drawText(s, 0, s.length(), x, y, paint);
10906f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
10916f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira
10926f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    private void updateBackground(boolean isUnread) {
1093e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        ViewMode viewMode = mActivity.getViewMode();
10946f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        if (isUnread) {
1095e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira            if (mTabletDevice && viewMode.isListMode()) {
10969d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                if (mChecked) {
10979d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setBackgroundResource(R.drawable.list_conversation_wide_unread_selected_holo);
10989d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                } else {
10999d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setBackgroundResource(R.drawable.conversation_wide_unread_selector);
11009d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                }
11016f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            } else {
11029d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                if (mChecked) {
11039d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setCheckedActivatedBackground();
11049d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                } else {
11059d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setBackgroundResource(R.drawable.conversation_unread_selector);
11069d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                }
11076f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
11086f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        } else {
1109e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira            if (mTabletDevice && viewMode.isListMode()) {
11109d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                if (mChecked) {
11119d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setBackgroundResource(R.drawable.list_conversation_wide_read_selected_holo);
11129d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                } else {
11139d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setBackgroundResource(R.drawable.conversation_wide_read_selector);
11149d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                }
11156f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            } else {
11169d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                if (mChecked) {
11179d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setCheckedActivatedBackground();
11189d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                } else {
11199d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                    setBackgroundResource(R.drawable.conversation_read_selector);
11209d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira                }
11216f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira            }
11226f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira        }
11236f92de64bbdf1ea6c4cd9774fc96921a10c266d7Mindy Pereira    }
1124c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
11259d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira    private void setCheckedActivatedBackground() {
1126fa131a2ff399fd1d544f759b063268fb4e8a3e70Vikram Aggarwal        if (isActivated() && mTabletDevice) {
11279d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira            setBackgroundResource(R.drawable.list_arrow_selected_holo);
11289d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira        } else {
11299d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira            setBackgroundResource(R.drawable.list_selected_holo);
11309d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira        }
11319d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira    }
11329d59a9a272abc78564428dd204d3616317c96b4bMindy Pereira
1133c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    /**
1134c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira     * Toggle the check mark on this view and update the conversation
1135c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira     */
1136c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    public void toggleCheckMark() {
1137b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        if (mHeader != null && mHeader.conversation != null) {
1138b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            mChecked = !mChecked;
1139b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            Conversation conv = mHeader.conversation;
1140b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            // Set the list position of this item in the conversation
11411ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            ListView listView = getListView();
1142b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            conv.position = mChecked && listView != null ? listView.getPositionForView(this)
1143b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira                    : Conversation.NO_POSITION;
1144b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            if (mSelectedConversationSet != null) {
1145b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira                mSelectedConversationSet.toggle(this, conv);
1146b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            }
1147bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook            // We update the background after the checked state has changed now
1148bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook            // that
1149bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook            // we have a selected background asset. Setting the background
1150bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook            // usually
1151b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            // waits for a layout pass, but we don't need a full layout, just an
1152b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            // update to the background.
1153b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            requestLayout();
1154d247dc966bca1ed303039c2893c54979d448a336Vikram Aggarwal        }
1155c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1156c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1157c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    /**
1158866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * Return if the checkbox for this item is checked.
1159866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
1160866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public boolean isChecked() {
1161866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return mChecked;
1162866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
1163866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1164866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
1165c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira     * Toggle the star on this view and update the conversation.
1166c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira     */
1167866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public void toggleStar() {
11684f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira        mHeader.conversation.starred = !mHeader.conversation.starred;
11694f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira        Bitmap starBitmap = getStarBitmap();
1170c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        postInvalidate(mCoordinates.starX, mCoordinates.starY, mCoordinates.starX
11714f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira                + starBitmap.getWidth(),
11724f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira                mCoordinates.starY + starBitmap.getHeight());
1173bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook        ConversationCursor cursor = (ConversationCursor)mAdapter.getCursor();
1174bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook        cursor.updateBoolean(mContext, mHeader.conversation, ConversationColumns.STARRED,
11754f2224c70d4d07df85b325fa3faf78218f92aae6Mindy Pereira                mHeader.conversation.starred);
1176c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1177c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1178866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private boolean isTouchInCheckmark(float x, float y) {
1179c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        // Everything before senders and include a touch slop.
1180ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        return mHeader.checkboxVisible && x < mCoordinates.sendersX + sTouchSlop;
1181c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1182c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1183866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private boolean isTouchInStar(float x, float y) {
1184c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        // Everything after the star and include a touch slop.
1185ee0c85d6d0ad72cfdf3edce935a598e2655ae65bMindy Pereira        return x > mCoordinates.starX - sTouchSlop;
1186c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1187c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1188866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
1189b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira     * Cancel any potential tap handling on this view.
1190b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira     */
1191304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blank    @Override
1192b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    public void cancelTap() {
1193464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        setPressed(false);
1194b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        removeCallbacks(mPendingCheckForLongPress);
1195b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    }
1196b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira
1197b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    /**
1198866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * ConversationItemView is given the first chance to handle touch events.
1199866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
1200c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    @Override
1201c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    public boolean onTouchEvent(MotionEvent event) {
1202464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        int x = mLastTouchX = (int) event.getX();
1203464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        int y = mLastTouchY = (int) event.getY();
1204f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        if (!mSwipeEnabled) {
1205f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira            return onTouchEventNoSwipe(event);
1206f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        }
1207866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        boolean handled = true;
1208c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1209c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        switch (event.getAction()) {
1210c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira            case MotionEvent.ACTION_DOWN:
1211c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                mDownEvent = true;
1212464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                // This checks for long press. The actual tap is handled on "up".
1213464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                checkForLongPress();
1214866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                // In order to allow the down event and subsequent move events
1215866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                // to bubble to the swipe handler, we need to return that all
1216866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                // down events are handled.
1217866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                handled = true;
1218c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                break;
1219c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira            case MotionEvent.ACTION_CANCEL:
1220c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                mDownEvent = false;
1221c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                break;
1222c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira            case MotionEvent.ACTION_UP:
1223c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                if (mDownEvent) {
1224866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // ConversationItemView gets the first chance to handle up
1225866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // events if there was a down event and there was no move
1226866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // event in between. In this case, ConversationItemView
1227866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // received the down event, and then an up event in the
1228866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // same location (+/- slop). Treat this as a click on the
1229866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // view or on a specific part of the view.
1230464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                    cancelTap();
1231866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    if (isTouchInCheckmark(x, y)) {
1232c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                        // Touch on the check mark
1233c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                        toggleCheckMark();
1234b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira                        handled = true;
1235866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    } else if (isTouchInStar(x, y)) {
1236c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                        // Touch on the star
1237c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                        toggleStar();
1238b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira                        handled = true;
1239866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    } else {
1240e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira                        setActivated(true);
1241464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                        // Put the list item click in the queue so we can show
1242464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                        // the user tap feedback first.
1243464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                        postDelayed(mListItemClick, 0);
1244c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                    }
1245bdcd35cc553bd6bede8277983384f5bcf83b58b2Mindy Pereira                    handled = true;
1246866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                } else {
1247866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // There was no down event that this view was made aware of,
1248866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    // therefore it cannot handle it.
1249866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                    handled = false;
1250c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                }
1251c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira                break;
1252c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira        }
1253c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira
1254ac9687c359d06ffd26a270906325dacef531ef53Vikram Aggarwal        // Let View try to handle it as well.
1255ac9687c359d06ffd26a270906325dacef531ef53Vikram Aggarwal        return handled || super.onTouchEvent(event);
1256c1b239dae7848b8783cb61964f870f8e18e8cc4fMindy Pereira    }
1257866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
12581ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira    private ListView getListView() {
12591ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        return ((SwipeableConversationItemView) getParent()).getListView();
12601ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira    }
12611ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira
1262f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira    private boolean onTouchEventNoSwipe(MotionEvent event) {
1263f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        boolean handled = true;
1264f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira
1265f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        int x = (int) event.getX();
1266f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        int y = (int) event.getY();
1267f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        switch (event.getAction()) {
1268f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira            case MotionEvent.ACTION_DOWN:
1269f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                mDownEvent = true;
1270f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                // In order to allow the down event and subsequent move events
1271f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                // to bubble to the swipe handler, we need to return that all
1272f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                // down events are handled.
1273f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                handled = isTouchInCheckmark(x, y) || isTouchInStar(x, y);
1274f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                break;
1275f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira            case MotionEvent.ACTION_CANCEL:
1276f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                mDownEvent = false;
1277f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                break;
1278f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira            case MotionEvent.ACTION_UP:
1279f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                if (mDownEvent) {
1280f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // ConversationItemView gets the first chance to handle up
1281f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // events if there was a down event and there was no move
1282f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // event in between. In this case, ConversationItemView
1283f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // received the down event, and then an up event in the
1284f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // same location (+/- slop). Treat this as a click on the
1285f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // view or on a specific part of the view.
1286f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    if (isTouchInCheckmark(x, y)) {
1287f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                        // Touch on the check mark
1288f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                        toggleCheckMark();
1289f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    } else if (isTouchInStar(x, y)) {
1290f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                        // Touch on the star
1291f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                        toggleStar();
1292f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    }
1293f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    handled = true;
1294f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                } else {
1295f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // There was no down event that this view was made aware of,
1296f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    // therefore it cannot handle it.
1297f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                    handled = false;
1298f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                }
1299f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira                break;
1300f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira        }
1301f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira
1302ac9687c359d06ffd26a270906325dacef531ef53Vikram Aggarwal        // Let View try to handle it as well.
1303ac9687c359d06ffd26a270906325dacef531ef53Vikram Aggarwal        return handled || super.onTouchEvent(event);
1304f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira    }
1305f07269fdfbc0ca2607dad50bfc15c2c041c1faddMindy Pereira
1306866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
1307b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira     * Return if this item should respond to long clicks.
1308b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira     */
1309b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    @Override
1310b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    public boolean isLongClickable() {
1311b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        return true;
1312b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    }
1313b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira
1314464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira    public void checkForLongPress() {
1315464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        // refreshDrawableState();
1316464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        final int longPressTimeout = ViewConfiguration.getLongPressTimeout();
1317464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        final boolean longClickable = isLongClickable();
1318b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira
1319464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira        if (longClickable) {
1320464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira            if (mPendingCheckForLongPress == null) {
1321464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira                mPendingCheckForLongPress = new HandleLongPress();
1322b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            }
1323464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira            postDelayed(mPendingCheckForLongPress, longPressTimeout);
1324b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        }
1325b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    }
1326b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira
1327464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira    private class HandleLongPress implements Runnable {
1328304a91eab01d67c8b5ef134b3bfe922fb6ab102fMarc Blank        @Override
1329b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        public void run() {
1330464275f83c1fa264e097ad222ab47b469d04464bMindy Pereira            setPressed(false);
13319730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal            handleLongClick();
1332b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira            performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
1333b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira        }
1334b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    }
1335b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira
1336b6b174fb3a8f58a2c81e035917ebad8ab45b88aeMindy Pereira    /**
1337866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * Grow the height of the item and fade it in when bringing a conversation
1338866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * back from a destructive action.
1339866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * @param listener
1340866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
1341bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    public void startSwipeUndoAnimation(ViewMode viewMode, final AnimatorListener listener) {
1342067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator undoAnimator = createTranslateXAnimation(true);
13436c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        undoAnimator.addListener(listener);
1344350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        undoAnimator.start();
1345866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
1346866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1347bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    /**
1348bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     * Grow the height of the item and fade it in when bringing a conversation
1349bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     * back from a destructive action.
1350bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     * @param listener
1351bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira     */
1352bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    public void startUndoAnimation(ViewMode viewMode, final AnimatorListener listener) {
1353bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        int minHeight = ConversationItemViewCoordinates.getMinHeight(mContext, viewMode);
1354bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        setMinimumHeight(minHeight);
1355067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        mAnimatedHeight = 0;
1356067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator height = createHeightAnimation(true);
1357067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        Animator fade = ObjectAnimator.ofFloat(this, "itemAlpha", 0, 1.0f);
1358067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        fade.setDuration(sShrinkAnimationDuration);
1359067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        fade.setInterpolator(new DecelerateInterpolator(2.0f));
1360067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        AnimatorSet transitionSet = new AnimatorSet();
1361067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.playTogether(height, fade);
1362067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.addListener(listener);
1363067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.start();
1364067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1365067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1366067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    /**
1367067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * Grow the height of the item and fade it in when bringing a conversation
1368067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * back from a destructive action.
1369067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * @param listener
1370067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     */
1371067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    public void startDestroyWithSwipeAnimation(final AnimatorListener listener) {
1372067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator slide = createTranslateXAnimation(false);
1373067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator height = createHeightAnimation(false);
1374bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        AnimatorSet transitionSet = new AnimatorSet();
1375067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.playSequentially(slide, height);
1376067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        transitionSet.addListener(listener);
1377bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        transitionSet.start();
1378bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
1379bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
1380067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private ObjectAnimator createTranslateXAnimation(boolean show) {
1381067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        final float start = show ? sUndoAnimationOffset : 0f;
1382067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        final float end = show ? 0f : sUndoAnimationOffset;
1383067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator slide = ObjectAnimator.ofFloat(this, "translationX", start, end);
1384067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        slide.setInterpolator(new DecelerateInterpolator(2.0f));
1385067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        slide.setDuration(sSlideAnimationDuration);
1386067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return slide;
1387067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1388067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1389067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private ObjectAnimator createHeightAnimation(boolean show) {
1390067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        int minHeight = ConversationItemViewCoordinates.getMinHeight(getContext(),
1391067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                mActivity.getViewMode());
1392067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        final int start = show ? 0 : minHeight;
1393067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        final int end = show ? minHeight : 0;
1394067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator height = ObjectAnimator.ofInt(this, "animatedHeight", start, end);
1395067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        height.setInterpolator(new DecelerateInterpolator(2.0f));
1396067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        height.setDuration(sShrinkAnimationDuration);
1397067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return height;
1398067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1399067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1400067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    public void startDestroyAnimation(final AnimatorListener listener) {
1401067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        ObjectAnimator height = createHeightAnimation(false);
1402067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        int minHeight = ConversationItemViewCoordinates.getMinHeight(mContext,
1403067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                mActivity.getViewMode());
1404067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        setMinimumHeight(0);
1405067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        mAnimatedHeight = minHeight;
1406067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        height.addListener(listener);
1407067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        height.start();
1408067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
1409067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
1410bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    // Used by animator
1411bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    @SuppressWarnings("unused")
1412bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    public void setItemAlpha(float alpha) {
1413bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        setAlpha(alpha);
1414bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        invalidate();
1415bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
1416bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
1417bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    // Used by animator
1418bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    @SuppressWarnings("unused")
1419bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    public void setAnimatedHeight(int height) {
1420bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        mAnimatedHeight = height;
1421bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        requestLayout();
1422bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
1423bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
1424350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira    @Override
1425350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1426bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        if (mAnimatedHeight == -1) {
1427bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            int height = measureHeight(heightMeasureSpec,
1428e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira                    ConversationItemViewCoordinates.getMode(mContext, mActivity.getViewMode()));
1429bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            setMeasuredDimension(widthMeasureSpec, height);
1430bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        } else {
1431bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mAnimatedHeight);
1432bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        }
1433866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
1434866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1435350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira    /**
1436350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira     * Determine the height of this view.
1437350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira     * @param measureSpec A measureSpec packed into an int
1438350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira     * @param mode The current mode of this view
1439350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira     * @return The height of the view, honoring constraints from measureSpec
1440350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira     */
1441350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira    private int measureHeight(int measureSpec, int mode) {
1442350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        int result = 0;
1443350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        int specMode = MeasureSpec.getMode(measureSpec);
1444350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        int specSize = MeasureSpec.getSize(measureSpec);
1445350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira
1446350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        if (specMode == MeasureSpec.EXACTLY) {
1447350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            // We were told how big to be
1448350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            result = specSize;
1449350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        } else {
1450350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            // Measure the text
1451350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            result = ConversationItemViewCoordinates.getHeight(mContext, mode);
1452350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            if (specMode == MeasureSpec.AT_MOST) {
1453350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira                // Respect AT_MOST value if that was what is called for by
1454350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira                // measureSpec
1455350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira                result = Math.min(result, specSize);
1456350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira            }
1457350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        }
1458350acdc75af67425aa3f8b6e4f889d4828ce8705Mindy Pereira        return result;
1459866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
1460866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1461866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    /**
1462866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     * Get the current position of this conversation item in the list.
1463866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira     */
1464866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public int getPosition() {
1465866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return mHeader != null && mHeader.conversation != null ?
1466866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                mHeader.conversation.position : -1;
1467866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
1468acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1469acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    /**
1470acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira     * Select the current conversation.
1471acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira     */
1472acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    private void selectConversation() {
1473acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        if (!mSelectedConversationSet.containsKey(mHeader.conversation.id)) {
1474acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            toggleCheckMark();
1475acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        }
1476acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
1477acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
14786c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    @Override
14796c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public View getView() {
14806c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        return this;
14816c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
14826c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
1483acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    /**
1484bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook     * With two pane mode and mailboxes in one pane (tablet), add the
1485bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook     * conversation to the selected set and start drag mode. In two pane mode
1486bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook     * when viewing conversations (tablet), toggle selection. In one pane mode
1487bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook     * (phone, and portrait mode on tablet), toggle selection.
1488acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira     */
14899730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal    private void handleLongClick() {
1490ac9687c359d06ffd26a270906325dacef531ef53Vikram Aggarwal        mDownEvent = false;
14919730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal        // If we are in one pane mode, or we are looking at conversations, drag and drop is
14929730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal        // meaningless. Allow the list's long click handler to do the right thing.
1493e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        if (!Utils.useTabletUI(mContext) || !mActivity.getViewMode().isListMode()) {
14949730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal            performLongClick();
14959730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal        } else {
14969730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal            beginDragMode();
1497acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        }
14989730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal    }
1499acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
15009730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal    /**
15019730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal     * Begin drag mode. Keep the conversation selected (NOT toggle selection) and start drag.
15029730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal     */
15039730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal    private void beginDragMode() {
1504acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        selectConversation();
1505acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1506acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        // Clip data has form: [conversations_uri, conversationId1,
1507acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        // maxMessageId1, label1, conversationId2, maxMessageId2, label2, ...]
15089730ea0550dacabcd38f0997c02d668058520042Vikram Aggarwal        final int count = mSelectedConversationSet.size();
1509acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        String description = Utils.formatPlural(mContext, R.plurals.move_conversation, count);
1510acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
15112f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        final ClipData data = ClipData.newUri(mContext.getContentResolver(), description,
1512acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira                Conversation.MOVE_CONVERSATIONS_URI);
1513acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        for (Conversation conversation : mSelectedConversationSet.values()) {
1514acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            data.addItem(new Item(String.valueOf(conversation.position)));
1515acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        }
15162f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        // Protect against non-existent views: only happens for monkeys
15172f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        final int width = this.getWidth();
15182f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        final int height = this.getHeight();
15192f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        final boolean isDimensionNegative = (width < 0) || (height < 0);
15202f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        if (isDimensionNegative) {
15212f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal            LogUtils.e(LOG_TAG, "ConversationItemView: dimension is negative: "
15222f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal                        + "width=%d, height=%d", width, height);
15232f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal            return;
15242f1f62ace49a6596e9f1eee78acfd607bbb4de87Vikram Aggarwal        }
1525acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        // Start drag mode
1526acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        startDrag(data, new ShadowBuilder(this, count, mLastTouchX, mLastTouchY), null, 0);
1527acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
1528acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1529acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    private class ShadowBuilder extends DragShadowBuilder {
1530acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private final Drawable mBackground;
1531acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1532acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private final View mView;
1533acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private final String mDragDesc;
1534acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private final int mTouchX;
1535acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private final int mTouchY;
1536acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private int mDragDescX;
1537acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        private int mDragDescY;
1538acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1539acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        public ShadowBuilder(View view, int count, int touchX, int touchY) {
1540acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            super(view);
1541acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mView = view;
1542acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mBackground = mView.getResources().getDrawable(R.drawable.list_pressed_holo);
1543acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mDragDesc = Utils.formatPlural(mView.getContext(), R.plurals.move_conversation, count);
1544acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mTouchX = touchX;
1545acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mTouchY = touchY;
1546acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        }
1547acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1548acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        @Override
1549acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) {
1550acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            int width = mView.getWidth();
1551acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            int height = mView.getHeight();
1552acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mDragDescX = mCoordinates.sendersX;
1553acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mDragDescY = getPadding(height, mCoordinates.subjectFontSize)
1554acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira                    - mCoordinates.subjectAscent;
1555acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            shadowSize.set(width, height);
1556acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            shadowTouchPoint.set(mTouchX, mTouchY);
1557acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        }
1558acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira
1559acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        @Override
1560acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        public void onDrawShadow(Canvas canvas) {
1561acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mBackground.setBounds(0, 0, mView.getWidth(), mView.getHeight());
1562acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            mBackground.draw(canvas);
1563acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            sPaint.setTextSize(mCoordinates.subjectFontSize);
1564acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira            canvas.drawText(mDragDesc, mDragDescX, mDragDescY, sPaint);
1565acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira        }
1566acf6039a23382f18c35f6b487d90d53cb67b5858Mindy Pereira    }
1567bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrook}
1568