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