1432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler/* 2432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * Copyright (C) 2009 The Android Open Source Project 3432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * 4432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * Licensed under the Apache License, Version 2.0 (the "License"); 5432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * you may not use this file except in compliance with the License. 6432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * You may obtain a copy of the License at 7432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * 8432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * http://www.apache.org/licenses/LICENSE-2.0 9432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * 10432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * Unless required by applicable law or agreed to in writing, software 11432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * distributed under the License is distributed on an "AS IS" BASIS, 12432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * See the License for the specific language governing permissions and 14432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * limitations under the License. 15432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler */ 16432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 17432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadlerpackage com.android.email.activity; 18432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 19432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadlerimport android.content.Context; 2018811dfb457eff8ba8b5436bd2641a4215480cdfBen Komaloimport android.content.res.Configuration; 21937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.content.res.Resources; 22937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.graphics.Bitmap; 23937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.graphics.BitmapFactory; 24937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.graphics.Canvas; 255b81690de1ea15035ab0539df683acd8e28b0ebdMakoto Onukiimport android.graphics.Paint; 26937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.graphics.Typeface; 27bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blankimport android.graphics.drawable.Drawable; 28937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.text.Layout.Alignment; 2906a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blankimport android.text.Spannable; 3006a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blankimport android.text.SpannableString; 3106a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blankimport android.text.SpannableStringBuilder; 32937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.text.StaticLayout; 33937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.text.TextPaint; 34937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.text.TextUtils; 35937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.text.TextUtils.TruncateAt; 36937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.text.format.DateUtils; 374beab88c92226628bf743070f88affb701968ce0Mindy Pereiraimport android.text.style.ForegroundColorSpan; 3806a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blankimport android.text.style.StyleSpan; 39432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadlerimport android.util.AttributeSet; 40432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadlerimport android.view.MotionEvent; 41937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankimport android.view.View; 428e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugoimport android.view.accessibility.AccessibilityEvent; 43432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 447f876c0375fd65d8796a96f137481a4c28593617Ben Komaloimport com.android.email.R; 457f876c0375fd65d8796a96f137481a4c28593617Ben Komaloimport com.android.emailcommon.utility.TextUtilities; 467f876c0375fd65d8796a96f137481a4c28593617Ben Komaloimport com.google.common.base.Objects; 477f876c0375fd65d8796a96f137481a4c28593617Ben Komalo 48432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler/** 49432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * This custom View is the list item for the MessageList activity, and serves two purposes: 50432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * 1. It's a container to store message metadata (e.g. the ids of the message, mailbox, & account) 51432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * 2. It handles internal clicks such as the checkbox or the favorite star 52432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler */ 53937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blankpublic class MessageListItem extends View { 54bdf84d57e623499d9c250fcc6fa1ba1f947cd2b5Makoto Onuki // Note: messagesAdapter directly fiddles with these fields. 55bdf84d57e623499d9c250fcc6fa1ba1f947cd2b5Makoto Onuki /* package */ long mMessageId; 56bdf84d57e623499d9c250fcc6fa1ba1f947cd2b5Makoto Onuki /* package */ long mMailboxId; 57bdf84d57e623499d9c250fcc6fa1ba1f947cd2b5Makoto Onuki /* package */ long mAccountId; 58432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 59e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira private ThreePaneLayout mLayout; 60851f3219e2bbcfb9c02c439d84d0885d890ded8dMakoto Onuki private MessagesAdapter mAdapter; 618b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo private MessageListItemCoordinates mCoordinates; 628b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo private Context mContext; 63432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 64432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler private boolean mDownEvent; 65432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 66c81bef672089654e6da3babbeb0172bd636564b2Marc Blank public static final String MESSAGE_LIST_ITEMS_CLIP_LABEL = 67c81bef672089654e6da3babbeb0172bd636564b2Marc Blank "com.android.email.MESSAGE_LIST_ITEMS"; 68c81bef672089654e6da3babbeb0172bd636564b2Marc Blank 69432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler public MessageListItem(Context context) { 70432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler super(context); 71937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank init(context); 72432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 73432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 74432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler public MessageListItem(Context context, AttributeSet attrs) { 75432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler super(context, attrs); 76937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank init(context); 77432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 78432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 79432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler public MessageListItem(Context context, AttributeSet attrs, int defStyle) { 80432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler super(context, attrs, defStyle); 81937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank init(context); 82937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 83937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 84937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Wide mode shows sender, snippet, time, and favorite spread out across the screen 858b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo private static final int MODE_WIDE = MessageListItemCoordinates.WIDE_MODE; 86937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Sentinel indicating that the view needs layout 87937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank public static final int NEEDS_LAYOUT = -1; 88937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 89937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static boolean sInit = false; 90937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static final TextPaint sDefaultPaint = new TextPaint(); 91937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static final TextPaint sBoldPaint = new TextPaint(); 92937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static final TextPaint sDatePaint = new TextPaint(); 93937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static Bitmap sAttachmentIcon; 94937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static Bitmap sInviteIcon; 95891da84a254d55c68df21998fbce9c1772eb6172Ben Komalo private static int sBadgeMargin; 96937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static Bitmap sFavoriteIconOff; 97937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static Bitmap sFavoriteIconOn; 98937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static Bitmap sSelectedIconOn; 99937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static Bitmap sSelectedIconOff; 100e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo private static Bitmap sStateReplied; 101e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo private static Bitmap sStateForwarded; 102e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo private static Bitmap sStateRepliedAndForwarded; 10306a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blank private static String sSubjectSnippetDivider; 1048e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo private static String sSubjectDescription; 1058e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo private static String sSubjectEmptyDescription; 1064beab88c92226628bf743070f88affb701968ce0Mindy Pereira 1074beab88c92226628bf743070f88affb701968ce0Mindy Pereira // Static colors. 1084beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int DEFAULT_TEXT_COLOR; 1094beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int ACTIVATED_TEXT_COLOR; 1104beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int LIGHT_TEXT_COLOR; 1114beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int DRAFT_TEXT_COLOR; 1124beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int SUBJECT_TEXT_COLOR_READ; 1134beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int SUBJECT_TEXT_COLOR_UNREAD; 1144beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int SNIPPET_TEXT_COLOR_READ; 1154beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int SNIPPET_TEXT_COLOR_UNREAD; 1164beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int SENDERS_TEXT_COLOR_READ; 1174beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int SENDERS_TEXT_COLOR_UNREAD; 1184beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int DATE_TEXT_COLOR_READ; 1194beab88c92226628bf743070f88affb701968ce0Mindy Pereira private static int DATE_TEXT_COLOR_UNREAD; 120937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 121937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank public String mSender; 1224beab88c92226628bf743070f88affb701968ce0Mindy Pereira public SpannableStringBuilder mText; 12378684ccc795c0d5211dfc04a834cb452dccb1058Marc Blank public CharSequence mSnippet; 1248e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo private String mSubject; 1258b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo private StaticLayout mSubjectLayout; 126937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank public boolean mRead; 127937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank public boolean mHasAttachment = false; 128937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank public boolean mHasInvite = true; 129937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank public boolean mIsFavorite = false; 130e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo public boolean mHasBeenRepliedTo = false; 131e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo public boolean mHasBeenForwarded = false; 1325b81690de1ea15035ab0539df683acd8e28b0ebdMakoto Onuki /** {@link Paint} for account color chips. null if no chips should be drawn. */ 1335b81690de1ea15035ab0539df683acd8e28b0ebdMakoto Onuki public Paint mColorChipPaint; 134937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 135937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private int mMode = -1; 136937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 137937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private int mViewWidth = 0; 138937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private int mViewHeight = 0; 1398b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo 140937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private static int sItemHeightWide; 141383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo private static int sItemHeightNormal; 142eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki 143eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki // Note: these cannot be shared Drawables because they are selectors which have state. 144eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki private Drawable mReadSelector; 145eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki private Drawable mUnreadSelector; 146eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki private Drawable mWideReadSelector; 147eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki private Drawable mWideUnreadSelector; 148937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 149937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private CharSequence mFormattedSender; 150bcf5d5825fe69bf8bd7edfd077027a52abd2c8ebMarc Blank // We must initialize this to something, in case the timestamp of the message is zero (which 151bcf5d5825fe69bf8bd7edfd077027a52abd2c8ebMarc Blank // should be very rare); this is otherwise set in setTimestamp 152bcf5d5825fe69bf8bd7edfd077027a52abd2c8ebMarc Blank private CharSequence mFormattedDate = ""; 153937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 154937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private void init(Context context) { 1558b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mContext = context; 156937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (!sInit) { 157937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank Resources r = context.getResources(); 1588e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo sSubjectDescription = r.getString(R.string.message_subject_description).concat(", "); 1598e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo sSubjectEmptyDescription = r.getString(R.string.message_is_empty_description); 16006a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blank sSubjectSnippetDivider = r.getString(R.string.message_list_subject_snippet_divider); 161937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sItemHeightWide = 162937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank r.getDimensionPixelSize(R.dimen.message_list_item_height_wide); 163383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo sItemHeightNormal = 164383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo r.getDimensionPixelSize(R.dimen.message_list_item_height_normal); 165937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 166937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sDefaultPaint.setTypeface(Typeface.DEFAULT); 167937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sDefaultPaint.setAntiAlias(true); 168937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sDatePaint.setTypeface(Typeface.DEFAULT); 169937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sDatePaint.setAntiAlias(true); 1708b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo sBoldPaint.setTypeface(Typeface.DEFAULT_BOLD); 171937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sBoldPaint.setAntiAlias(true); 1724beab88c92226628bf743070f88affb701968ce0Mindy Pereira 17364ac7a6cc81ef6dc84354153b978bd5db944e8b0Todd Kennedy sAttachmentIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_attachment); 1748466f79a06433bf3d05a770578c72b2b60e1bd7cBen Komalo sInviteIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_invite_holo_light); 175891da84a254d55c68df21998fbce9c1772eb6172Ben Komalo sBadgeMargin = r.getDimensionPixelSize(R.dimen.message_list_badge_margin); 176937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sFavoriteIconOff = 177891da84a254d55c68df21998fbce9c1772eb6172Ben Komalo BitmapFactory.decodeResource(r, R.drawable.btn_star_off_normal_email_holo_light); 178937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sFavoriteIconOn = 179891da84a254d55c68df21998fbce9c1772eb6172Ben Komalo BitmapFactory.decodeResource(r, R.drawable.btn_star_on_normal_email_holo_light); 180937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sSelectedIconOff = 181937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank BitmapFactory.decodeResource(r, R.drawable.btn_check_off_normal_holo_light); 182937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sSelectedIconOn = 183937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank BitmapFactory.decodeResource(r, R.drawable.btn_check_on_normal_holo_light); 184937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 185e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo sStateReplied = 1868466f79a06433bf3d05a770578c72b2b60e1bd7cBen Komalo BitmapFactory.decodeResource(r, R.drawable.ic_badge_reply_holo_light); 187e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo sStateForwarded = 1888466f79a06433bf3d05a770578c72b2b60e1bd7cBen Komalo BitmapFactory.decodeResource(r, R.drawable.ic_badge_forward_holo_light); 189e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo sStateRepliedAndForwarded = 1908466f79a06433bf3d05a770578c72b2b60e1bd7cBen Komalo BitmapFactory.decodeResource(r, R.drawable.ic_badge_reply_forward_holo_light); 191e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo 1924beab88c92226628bf743070f88affb701968ce0Mindy Pereira DEFAULT_TEXT_COLOR = r.getColor(R.color.default_text_color); 1934beab88c92226628bf743070f88affb701968ce0Mindy Pereira ACTIVATED_TEXT_COLOR = r.getColor(android.R.color.white); 1944beab88c92226628bf743070f88affb701968ce0Mindy Pereira SUBJECT_TEXT_COLOR_READ = r.getColor(R.color.subject_text_color_read); 1954beab88c92226628bf743070f88affb701968ce0Mindy Pereira SUBJECT_TEXT_COLOR_UNREAD = r.getColor(R.color.subject_text_color_unread); 1964beab88c92226628bf743070f88affb701968ce0Mindy Pereira SNIPPET_TEXT_COLOR_READ = r.getColor(R.color.snippet_text_color_read); 1974beab88c92226628bf743070f88affb701968ce0Mindy Pereira SNIPPET_TEXT_COLOR_UNREAD = r.getColor(R.color.snippet_text_color_unread); 1984beab88c92226628bf743070f88affb701968ce0Mindy Pereira SENDERS_TEXT_COLOR_READ = r.getColor(R.color.senders_text_color_read); 1994beab88c92226628bf743070f88affb701968ce0Mindy Pereira SENDERS_TEXT_COLOR_UNREAD = r.getColor(R.color.senders_text_color_unread); 2004beab88c92226628bf743070f88affb701968ce0Mindy Pereira DATE_TEXT_COLOR_READ = r.getColor(R.color.date_text_color_read); 2014beab88c92226628bf743070f88affb701968ce0Mindy Pereira DATE_TEXT_COLOR_UNREAD = r.getColor(R.color.date_text_color_unread); 202ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo 203937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank sInit = true; 204937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 205937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 206937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 207937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank /** 20828e496daef8be15def1de3787845a22bed0c8b79Ben Komalo * Invalidate all drawing caches associated with drawing message list items. 20928e496daef8be15def1de3787845a22bed0c8b79Ben Komalo * This is an expensive operation, and should be done rarely, such as when system font size 21028e496daef8be15def1de3787845a22bed0c8b79Ben Komalo * changes occurs. 21128e496daef8be15def1de3787845a22bed0c8b79Ben Komalo */ 21228e496daef8be15def1de3787845a22bed0c8b79Ben Komalo public static void resetDrawingCaches() { 21328e496daef8be15def1de3787845a22bed0c8b79Ben Komalo MessageListItemCoordinates.resetCaches(); 21428e496daef8be15def1de3787845a22bed0c8b79Ben Komalo sInit = false; 21528e496daef8be15def1de3787845a22bed0c8b79Ben Komalo } 21628e496daef8be15def1de3787845a22bed0c8b79Ben Komalo 21728e496daef8be15def1de3787845a22bed0c8b79Ben Komalo /** 2182313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo * Sets message subject and snippet safely, ensuring the cache is invalidated. 2198e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo */ 220217dc144bd967f21850cefc6e1a84e9d35a67f85Ben Komalo public void setText(String subject, String snippet, boolean forceUpdate) { 2212313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo boolean changed = false; 2227f876c0375fd65d8796a96f137481a4c28593617Ben Komalo if (!Objects.equal(mSubject, subject)) { 2238e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo mSubject = subject; 2242313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo changed = true; 22556593af65ad25a69f81fb471d346c7519b58fbc4Jorge Lugo populateContentDescription(); 2268e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo } 2272313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo 2282313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo if (!Objects.equal(mSnippet, snippet)) { 2292313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo mSnippet = snippet; 2302313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo changed = true; 2312313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo } 2322313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo 233217dc144bd967f21850cefc6e1a84e9d35a67f85Ben Komalo if (forceUpdate || changed || (mSubject == null && mSnippet == null) /* first time */) { 2342313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo SpannableStringBuilder ssb = new SpannableStringBuilder(); 2352313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo boolean hasSubject = false; 2362313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo if (!TextUtils.isEmpty(mSubject)) { 2372313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo SpannableString ss = new SpannableString(mSubject); 2382313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo ss.setSpan(new StyleSpan(mRead ? Typeface.NORMAL : Typeface.BOLD), 0, ss.length(), 2392313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 2402313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo ssb.append(ss); 2412313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo hasSubject = true; 2422313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo } 2432313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo if (!TextUtils.isEmpty(mSnippet)) { 2442313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo if (hasSubject) { 2452313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo ssb.append(sSubjectSnippetDivider); 2462313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo } 2472313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo ssb.append(mSnippet); 2482313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo } 2492313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo mText = ssb; 250ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo requestLayout(); 2512313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo } 2522313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo } 2532313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo 254ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo long mTimeFormatted = 0; 2552313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo public void setTimestamp(long timestamp) { 256ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo if (mTimeFormatted != timestamp) { 257ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo mFormattedDate = DateUtils.getRelativeTimeSpanString(mContext, timestamp).toString(); 258ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo mTimeFormatted = timestamp; 259ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo } 2608e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo } 2618e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo 2628e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo /** 263937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * Determine the mode of this view (WIDE or NORMAL) 264937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * 265937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * @param width The width of the view 266937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * @return The mode of the view 267937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank */ 268937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private int getViewMode(int width) { 2698b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo return MessageListItemCoordinates.getMode(mContext, width); 270937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 271937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 272eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki private Drawable mCurentBackground = null; // Only used by updateBackground() 273eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki 2748b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo private void updateBackground() { 275eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki final Drawable newBackground; 276e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira boolean isMultiPane = MessageListItemCoordinates.isMultiPane(mContext); 277bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank if (mRead) { 278e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira if (isMultiPane && mLayout.isLeftPaneVisible()) { 279eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki if (mWideReadSelector == null) { 280eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki mWideReadSelector = getContext().getResources() 28121e4fe49b68738523ebdc8c340469a46d79ed691Mindy Pereira .getDrawable(R.drawable.conversation_wide_read_selector); 282eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 283eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki newBackground = mWideReadSelector; 284bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank } else { 285eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki if (mReadSelector == null) { 286eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki mReadSelector = getContext().getResources() 28721e4fe49b68738523ebdc8c340469a46d79ed691Mindy Pereira .getDrawable(R.drawable.conversation_read_selector); 288eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 289eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki newBackground = mReadSelector; 290bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank } 291bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank } else { 292e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira if (isMultiPane && mLayout.isLeftPaneVisible()) { 293eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki if (mWideUnreadSelector == null) { 2944beab88c92226628bf743070f88affb701968ce0Mindy Pereira mWideUnreadSelector = getContext().getResources().getDrawable( 2954beab88c92226628bf743070f88affb701968ce0Mindy Pereira R.drawable.conversation_wide_unread_selector); 296eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 297eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki newBackground = mWideUnreadSelector; 298bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank } else { 299eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki if (mUnreadSelector == null) { 300eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki mUnreadSelector = getContext().getResources() 30121e4fe49b68738523ebdc8c340469a46d79ed691Mindy Pereira .getDrawable(R.drawable.conversation_unread_selector); 302eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 303eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki newBackground = mUnreadSelector; 304bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank } 305bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank } 306eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki if (newBackground != mCurentBackground) { 307eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki // setBackgroundDrawable is a heavy operation. Only call it when really needed. 308eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki setBackgroundDrawable(newBackground); 309eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki mCurentBackground = newBackground; 310eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 311eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 312bd9b2ff2b31b8db24471f74d35b4f6c220a1d2e3Marc Blank 3134beab88c92226628bf743070f88affb701968ce0Mindy Pereira private void calculateSubjectText() { 3144beab88c92226628bf743070f88affb701968ce0Mindy Pereira if (mText == null || mText.length() == 0) { 3154beab88c92226628bf743070f88affb701968ce0Mindy Pereira return; 3164beab88c92226628bf743070f88affb701968ce0Mindy Pereira } 3174beab88c92226628bf743070f88affb701968ce0Mindy Pereira boolean hasSubject = false; 318c1d9be5dc36f64b104fcaf041dd38c28ed4d05a0Makoto Onuki int snippetStart = 0; 3194beab88c92226628bf743070f88affb701968ce0Mindy Pereira if (!TextUtils.isEmpty(mSubject)) { 3204beab88c92226628bf743070f88affb701968ce0Mindy Pereira int subjectColor = getFontColor(mRead ? SUBJECT_TEXT_COLOR_READ 3214beab88c92226628bf743070f88affb701968ce0Mindy Pereira : SUBJECT_TEXT_COLOR_UNREAD); 3224beab88c92226628bf743070f88affb701968ce0Mindy Pereira mText.setSpan(new ForegroundColorSpan(subjectColor), 0, mSubject.length(), 3234beab88c92226628bf743070f88affb701968ce0Mindy Pereira Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 324c1d9be5dc36f64b104fcaf041dd38c28ed4d05a0Makoto Onuki snippetStart = mSubject.length() + 1; 3254beab88c92226628bf743070f88affb701968ce0Mindy Pereira } 3264beab88c92226628bf743070f88affb701968ce0Mindy Pereira if (!TextUtils.isEmpty(mSnippet)) { 3274beab88c92226628bf743070f88affb701968ce0Mindy Pereira int snippetColor = getFontColor(mRead ? SNIPPET_TEXT_COLOR_READ 3284beab88c92226628bf743070f88affb701968ce0Mindy Pereira : SNIPPET_TEXT_COLOR_UNREAD); 329c1d9be5dc36f64b104fcaf041dd38c28ed4d05a0Makoto Onuki mText.setSpan(new ForegroundColorSpan(snippetColor), snippetStart, mText.length(), 330c1d9be5dc36f64b104fcaf041dd38c28ed4d05a0Makoto Onuki Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 3314beab88c92226628bf743070f88affb701968ce0Mindy Pereira } 3324beab88c92226628bf743070f88affb701968ce0Mindy Pereira } 3334beab88c92226628bf743070f88affb701968ce0Mindy Pereira 334eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki private void calculateDrawingData() { 3358b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo sDefaultPaint.setTextSize(mCoordinates.subjectFontSize); 3364beab88c92226628bf743070f88affb701968ce0Mindy Pereira calculateSubjectText(); 3378b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mSubjectLayout = new StaticLayout(mText, sDefaultPaint, 338383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, false /* includePad */); 3398b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo if (mCoordinates.subjectLineCount < mSubjectLayout.getLineCount()) { 3408b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // TODO: ellipsize. 3418b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo int end = mSubjectLayout.getLineEnd(mCoordinates.subjectLineCount - 1); 3428b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mSubjectLayout = new StaticLayout(mText.subSequence(0, end), 3438b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo sDefaultPaint, mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true); 344937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 345937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 346937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Now, format the sender for its width 347937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank TextPaint senderPaint = mRead ? sDefaultPaint : sBoldPaint; 348937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // And get the ellipsized string for the calculated width 3490a73e8cd459f4839f7c54fd74c9085271a1fb806Makoto Onuki if (TextUtils.isEmpty(mSender)) { 3500a73e8cd459f4839f7c54fd74c9085271a1fb806Makoto Onuki mFormattedSender = ""; 3510a73e8cd459f4839f7c54fd74c9085271a1fb806Makoto Onuki } else { 352383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo int senderWidth = mCoordinates.sendersWidth; 353383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo senderPaint.setTextSize(mCoordinates.sendersFontSize); 3544beab88c92226628bf743070f88affb701968ce0Mindy Pereira senderPaint.setColor(getFontColor(mRead ? SENDERS_TEXT_COLOR_READ 3554beab88c92226628bf743070f88affb701968ce0Mindy Pereira : SENDERS_TEXT_COLOR_UNREAD)); 3560a73e8cd459f4839f7c54fd74c9085271a1fb806Makoto Onuki mFormattedSender = TextUtils.ellipsize(mSender, senderPaint, senderWidth, 3570a73e8cd459f4839f7c54fd74c9085271a1fb806Makoto Onuki TruncateAt.END); 3580a73e8cd459f4839f7c54fd74c9085271a1fb806Makoto Onuki } 359937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 360937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank @Override 361937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 362452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank if (widthMeasureSpec != 0 || mViewWidth == 0) { 363452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank mViewWidth = MeasureSpec.getSize(widthMeasureSpec); 364452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank int mode = getViewMode(mViewWidth); 365452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank if (mode != mMode) { 366452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank mMode = mode; 367452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank } 368452b34772942f767e2ba1a14fa03bdd58b29d180Marc Blank mViewHeight = measureHeight(heightMeasureSpec, mMode); 369937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 370937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank setMeasuredDimension(mViewWidth, mViewHeight); 371937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 372937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 373937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank /** 374937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * Determine the height of this view 375937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * 376937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * @param measureSpec A measureSpec packed into an int 377937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * @param mode The current mode of this view 378937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank * @return The height of the view, honoring constraints from measureSpec 379937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank */ 380937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank private int measureHeight(int measureSpec, int mode) { 381937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank int result = 0; 382937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank int specMode = MeasureSpec.getMode(measureSpec); 383937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank int specSize = MeasureSpec.getSize(measureSpec); 384937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 385937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (specMode == MeasureSpec.EXACTLY) { 386937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // We were told how big to be 387937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank result = specSize; 388937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } else { 389937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Measure the text 390937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (mMode == MODE_WIDE) { 391937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank result = sItemHeightWide; 392937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } else { 393383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo result = sItemHeightNormal; 394937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 395937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (specMode == MeasureSpec.AT_MOST) { 396937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Respect AT_MOST value if that was what is called for by 397937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // measureSpec 398937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank result = Math.min(result, specSize); 399937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 400937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 401937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank return result; 402937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 403937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 404937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank @Override 405eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki public void draw(Canvas canvas) { 406eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki // Update the background, before View.draw() draws it. 407f42d5c6234bfb26f63a711fd59076964283fb7f0Todd Kennedy setSelected(mAdapter.isSelected(this)); 408eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki updateBackground(); 409eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki super.draw(canvas); 410eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki } 411eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki 412eaf748e6eecb4cb3644dcd950d56d1edb2d50a63Makoto Onuki @Override 4138b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 4148b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo super.onLayout(changed, left, top, right, bottom); 4158b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo 4168b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates = MessageListItemCoordinates.forWidth(mContext, mViewWidth); 417ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo calculateDrawingData(); 4188b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo } 4198b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo 4204beab88c92226628bf743070f88affb701968ce0Mindy Pereira private int getFontColor(int defaultColor) { 4214beab88c92226628bf743070f88affb701968ce0Mindy Pereira return isActivated() ? ACTIVATED_TEXT_COLOR : defaultColor; 4224beab88c92226628bf743070f88affb701968ce0Mindy Pereira } 4234beab88c92226628bf743070f88affb701968ce0Mindy Pereira 4248b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo @Override 425937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank protected void onDraw(Canvas canvas) { 4268b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // Draw the color chip indicating the mailbox this belongs to 4275b81690de1ea15035ab0539df683acd8e28b0ebdMakoto Onuki if (mColorChipPaint != null) { 4288b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.drawRect( 4298b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates.chipX, mCoordinates.chipY, 4308b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates.chipX + mCoordinates.chipWidth, 4318b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates.chipY + mCoordinates.chipHeight, 4328b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mColorChipPaint); 4335b81690de1ea15035ab0539df683acd8e28b0ebdMakoto Onuki } 4345b81690de1ea15035ab0539df683acd8e28b0ebdMakoto Onuki 435937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Draw the checkbox 436937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank canvas.drawBitmap(mAdapter.isSelected(this) ? sSelectedIconOn : sSelectedIconOff, 437383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo mCoordinates.checkmarkX, mCoordinates.checkmarkY, null); 438937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 439937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank // Draw the sender name 4402313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo Paint senderPaint = mRead ? sDefaultPaint : sBoldPaint; 4414beab88c92226628bf743070f88affb701968ce0Mindy Pereira senderPaint.setColor(getFontColor(mRead ? SENDERS_TEXT_COLOR_READ 4424beab88c92226628bf743070f88affb701968ce0Mindy Pereira : SENDERS_TEXT_COLOR_UNREAD)); 443ba0008b669146f808f5e250bf0c140fc3a638049Ben Komalo senderPaint.setTextSize(mCoordinates.sendersFontSize); 4448b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.drawText(mFormattedSender, 0, mFormattedSender.length(), 4458b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates.sendersX, mCoordinates.sendersY - mCoordinates.sendersAscent, 4462313f48bdc34409a1d17bd841d440d8215eb9528Ben Komalo senderPaint); 447937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 448e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo // Draw the reply state. Draw nothing if neither replied nor forwarded. 449e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo if (mHasBeenRepliedTo && mHasBeenForwarded) { 4507891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo canvas.drawBitmap(sStateRepliedAndForwarded, 451383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo mCoordinates.stateX, mCoordinates.stateY, null); 452e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo } else if (mHasBeenRepliedTo) { 4537891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo canvas.drawBitmap(sStateReplied, 454383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo mCoordinates.stateX, mCoordinates.stateY, null); 455e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo } else if (mHasBeenForwarded) { 4567891106a7d6b4c406792a8a9144e5148e6bf5ddbBen Komalo canvas.drawBitmap(sStateForwarded, 457383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo mCoordinates.stateX, mCoordinates.stateY, null); 458e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo } 459e2f6f18396f27d2fee1149d6a3896721297bf7f3Jorge Lugo 4608b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // Subject and snippet. 4618b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo sDefaultPaint.setTextSize(mCoordinates.subjectFontSize); 4628b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.save(); 4638b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.translate( 4648b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates.subjectX, 4658b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mCoordinates.subjectY); 4668b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo mSubjectLayout.draw(canvas); 4678b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.restore(); 468937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 4698b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // Draw the date 4708b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo sDatePaint.setTextSize(mCoordinates.dateFontSize); 4714beab88c92226628bf743070f88affb701968ce0Mindy Pereira sDatePaint.setColor(mRead ? DATE_TEXT_COLOR_READ : DATE_TEXT_COLOR_UNREAD); 4728b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo int dateX = mCoordinates.dateXEnd 4738b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo - (int) sDatePaint.measureText(mFormattedDate, 0, mFormattedDate.length()); 4748b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo 4758b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.drawText(mFormattedDate, 0, mFormattedDate.length(), 4768b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo dateX, mCoordinates.dateY - mCoordinates.dateAscent, sDatePaint); 47706a2f4a3b1322fb6fecb908bd04e777199529ce7Marc Blank 4788b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // Draw the favorite icon 4798b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo canvas.drawBitmap(mIsFavorite ? sFavoriteIconOn : sFavoriteIconOff, 480383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo mCoordinates.starX, mCoordinates.starY, null); 4818b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo 4828b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // TODO: deal with the icon layouts better from the coordinate class so that this logic 4838b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // doesn't have to exist. 4848b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo // Draw the attachment and invite icons, if necessary. 485891da84a254d55c68df21998fbce9c1772eb6172Ben Komalo int iconsLeft = dateX - sBadgeMargin; 486937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (mHasAttachment) { 4878b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo iconsLeft = iconsLeft - sAttachmentIcon.getWidth(); 488383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo canvas.drawBitmap(sAttachmentIcon, iconsLeft, mCoordinates.paperclipY, null); 489937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 490937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (mHasInvite) { 4918b2109f047d8b50edbb677a822f6ee34df8d17b8Ben Komalo iconsLeft -= sInviteIcon.getWidth(); 492383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo canvas.drawBitmap(sInviteIcon, iconsLeft, mCoordinates.paperclipY, null); 493937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } 494937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank 495432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 496432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 497432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler /** 498432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * Called by the adapter at bindView() time 4990a892ae04f0557367a751e1b130e260feccc3c52Makoto Onuki * 500432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * @param adapter the adapter that creates this view 501e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira * @param layout If this is a three pane implementation, the 502e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira * ThreePaneLayout. Otherwise, null. 503432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler */ 504e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira public void bindViewInit(MessagesAdapter adapter, ThreePaneLayout layout) { 505e4202e782c91075c09cd5c348517a90620622a7fMindy Pereira mLayout = layout; 506432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler mAdapter = adapter; 5074beab88c92226628bf743070f88affb701968ce0Mindy Pereira requestLayout(); 508432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 509432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 5102076fa7a3b088ed220d9fa0607a457d2829afb8cBen Komalo private static final int TOUCH_SLOP = 24; 51118811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo private static int sScaledTouchSlop = -1; 51218811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo 51318811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo private void initializeSlop(Context context) { 51418811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo if (sScaledTouchSlop == -1) { 51518811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo final Resources res = context.getResources(); 51618811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo final Configuration config = res.getConfiguration(); 51718811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo final float density = res.getDisplayMetrics().density; 51818811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo final float sizeAndDensity; 51918811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo if (config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE)) { 52018811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo sizeAndDensity = density * 1.5f; 52118811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo } else { 52218811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo sizeAndDensity = density; 52318811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo } 52418811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo sScaledTouchSlop = (int) (sizeAndDensity * TOUCH_SLOP + 0.5f); 52518811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo } 52618811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo } 52718811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo 528432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler /** 529432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * Overriding this method allows us to "catch" clicks in the checkbox or star 530432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler * and process them accordingly. 531432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler */ 532432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler @Override 533432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler public boolean onTouchEvent(MotionEvent event) { 53418811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo initializeSlop(getContext()); 53518811dfb457eff8ba8b5436bd2641a4215480cdfBen Komalo 536432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler boolean handled = false; 537432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler int touchX = (int) event.getX(); 538383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo int checkRight = mCoordinates.checkmarkX 539383279a1c5e0cba982645a5ed06e06534d12159eBen Komalo + mCoordinates.checkmarkWidthIncludingMargins + sScaledTouchSlop; 5402076fa7a3b088ed220d9fa0607a457d2829afb8cBen Komalo int starLeft = mCoordinates.starX - sScaledTouchSlop; 541432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 542432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler switch (event.getAction()) { 543432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler case MotionEvent.ACTION_DOWN: 544937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (touchX < checkRight || touchX > starLeft) { 545c81bef672089654e6da3babbeb0172bd636564b2Marc Blank mDownEvent = true; 546937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if ((touchX < checkRight) || (touchX > starLeft)) { 547c81bef672089654e6da3babbeb0172bd636564b2Marc Blank handled = true; 548c81bef672089654e6da3babbeb0172bd636564b2Marc Blank } 549432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 550432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler break; 551432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 552432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler case MotionEvent.ACTION_CANCEL: 553432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler mDownEvent = false; 554432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler break; 555432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 556432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler case MotionEvent.ACTION_UP: 557432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler if (mDownEvent) { 558937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank if (touchX < checkRight) { 559bdf84d57e623499d9c250fcc6fa1ba1f947cd2b5Makoto Onuki mAdapter.toggleSelected(this); 560bdf84d57e623499d9c250fcc6fa1ba1f947cd2b5Makoto Onuki handled = true; 561937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank } else if (touchX > starLeft) { 562937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank mIsFavorite = !mIsFavorite; 563937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank mAdapter.updateFavorite(this, mIsFavorite); 564432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler handled = true; 565432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 566432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 567432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler break; 568432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 569432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 570432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler if (handled) { 571937ea4fc87eabd8fe785abeb2af1a38450e3fca9Marc Blank invalidate(); 572432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } else { 573432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler handled = super.onTouchEvent(event); 574432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 575432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler 576432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler return handled; 577432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler } 5788e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo 5798e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo @Override 5808e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 58170a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo event.setClassName(getClass().getName()); 58270a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo event.setPackageName(getContext().getPackageName()); 58370a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo event.setEnabled(true); 58470a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo event.setContentDescription(getContentDescription()); 58570a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo return true; 5868e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo } 5878e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo 5888e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo /** 58970a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo * Sets the content description for this item, used for accessibility. 5908e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo */ 59170a3f210418d060c4e1616f2692c728564cae9e4Jorge Lugo private void populateContentDescription() { 59256593af65ad25a69f81fb471d346c7519b58fbc4Jorge Lugo if (!TextUtils.isEmpty(mSubject)) { 59356593af65ad25a69f81fb471d346c7519b58fbc4Jorge Lugo setContentDescription(sSubjectDescription + mSubject); 59456593af65ad25a69f81fb471d346c7519b58fbc4Jorge Lugo } else { 59556593af65ad25a69f81fb471d346c7519b58fbc4Jorge Lugo setContentDescription(sSubjectEmptyDescription); 5968e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo } 5978e779e627a2185320ab168fdce09477a73bf5f22Jorge Lugo } 598432d1ec3ed54cd2f627fd79b5fe7b64341fa273aAndrew Stadler} 599