2009-07-07 20:43:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package com.android.email.activity;
|
|
|
|
|
|
|
|
import com.android.email.R;
|
2011-03-31 20:29:23 +00:00
|
|
|
import com.android.emailcommon.utility.TextUtilities;
|
2009-07-07 20:43:24 +00:00
|
|
|
|
|
|
|
import android.content.Context;
|
2010-11-10 20:14:55 +00:00
|
|
|
import android.content.res.Resources;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.BitmapFactory;
|
|
|
|
import android.graphics.Canvas;
|
2010-11-22 21:47:11 +00:00
|
|
|
import android.graphics.Paint;
|
2010-11-10 20:14:55 +00:00
|
|
|
import android.graphics.Typeface;
|
2011-01-05 18:47:08 +00:00
|
|
|
import android.graphics.drawable.Drawable;
|
2010-11-10 20:14:55 +00:00
|
|
|
import android.text.Layout.Alignment;
|
2010-12-04 07:12:48 +00:00
|
|
|
import android.text.Spannable;
|
|
|
|
import android.text.SpannableString;
|
|
|
|
import android.text.SpannableStringBuilder;
|
2010-11-10 20:14:55 +00:00
|
|
|
import android.text.StaticLayout;
|
|
|
|
import android.text.TextPaint;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import android.text.TextUtils.TruncateAt;
|
|
|
|
import android.text.format.DateUtils;
|
2010-12-04 07:12:48 +00:00
|
|
|
import android.text.style.StyleSpan;
|
2009-07-07 20:43:24 +00:00
|
|
|
import android.util.AttributeSet;
|
|
|
|
import android.view.MotionEvent;
|
2010-11-10 20:14:55 +00:00
|
|
|
import android.view.View;
|
2011-06-23 21:51:19 +00:00
|
|
|
import android.view.accessibility.AccessibilityEvent;
|
2009-07-07 20:43:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* This custom View is the list item for the MessageList activity, and serves two purposes:
|
|
|
|
* 1. It's a container to store message metadata (e.g. the ids of the message, mailbox, & account)
|
|
|
|
* 2. It handles internal clicks such as the checkbox or the favorite star
|
|
|
|
*/
|
2010-11-10 20:14:55 +00:00
|
|
|
public class MessageListItem extends View {
|
2010-08-27 20:00:48 +00:00
|
|
|
// Note: messagesAdapter directly fiddles with these fields.
|
|
|
|
/* package */ long mMessageId;
|
|
|
|
/* package */ long mMailboxId;
|
|
|
|
/* package */ long mAccountId;
|
2009-07-07 20:43:24 +00:00
|
|
|
|
2010-06-09 21:43:43 +00:00
|
|
|
private MessagesAdapter mAdapter;
|
2011-04-15 18:09:37 +00:00
|
|
|
private MessageListItemCoordinates mCoordinates;
|
|
|
|
private Context mContext;
|
2009-07-07 20:43:24 +00:00
|
|
|
|
|
|
|
private boolean mDownEvent;
|
|
|
|
|
2010-10-14 02:04:46 +00:00
|
|
|
public static final String MESSAGE_LIST_ITEMS_CLIP_LABEL =
|
|
|
|
"com.android.email.MESSAGE_LIST_ITEMS";
|
|
|
|
|
2009-07-07 20:43:24 +00:00
|
|
|
public MessageListItem(Context context) {
|
|
|
|
super(context);
|
2010-11-10 20:14:55 +00:00
|
|
|
init(context);
|
2009-07-07 20:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public MessageListItem(Context context, AttributeSet attrs) {
|
|
|
|
super(context, attrs);
|
2010-11-10 20:14:55 +00:00
|
|
|
init(context);
|
2009-07-07 20:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public MessageListItem(Context context, AttributeSet attrs, int defStyle) {
|
|
|
|
super(context, attrs, defStyle);
|
2010-11-10 20:14:55 +00:00
|
|
|
init(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wide mode shows sender, snippet, time, and favorite spread out across the screen
|
2011-04-15 18:09:37 +00:00
|
|
|
private static final int MODE_WIDE = MessageListItemCoordinates.WIDE_MODE;
|
2010-11-10 20:14:55 +00:00
|
|
|
// Sentinel indicating that the view needs layout
|
|
|
|
public static final int NEEDS_LAYOUT = -1;
|
|
|
|
|
|
|
|
private static boolean sInit = false;
|
|
|
|
private static final TextPaint sDefaultPaint = new TextPaint();
|
|
|
|
private static final TextPaint sBoldPaint = new TextPaint();
|
|
|
|
private static final TextPaint sDatePaint = new TextPaint();
|
2011-03-31 20:29:23 +00:00
|
|
|
private static final TextPaint sHighlightPaint = new TextPaint();
|
2010-11-10 20:14:55 +00:00
|
|
|
private static Bitmap sAttachmentIcon;
|
|
|
|
private static Bitmap sInviteIcon;
|
|
|
|
private static Bitmap sFavoriteIconOff;
|
|
|
|
private static Bitmap sFavoriteIconOn;
|
|
|
|
private static Bitmap sSelectedIconOn;
|
|
|
|
private static Bitmap sSelectedIconOff;
|
2011-06-25 02:35:34 +00:00
|
|
|
private static Bitmap sStateReplied;
|
|
|
|
private static Bitmap sStateForwarded;
|
|
|
|
private static Bitmap sStateRepliedAndForwarded;
|
2010-12-04 07:12:48 +00:00
|
|
|
private static String sSubjectSnippetDivider;
|
2011-06-23 21:51:19 +00:00
|
|
|
private static String sSubjectDescription;
|
|
|
|
private static String sSubjectEmptyDescription;
|
2010-11-10 20:14:55 +00:00
|
|
|
|
|
|
|
public String mSender;
|
2010-12-04 07:12:48 +00:00
|
|
|
public CharSequence mText;
|
2011-03-31 20:29:23 +00:00
|
|
|
public CharSequence mSnippet;
|
2011-06-23 21:51:19 +00:00
|
|
|
private String mSubject;
|
|
|
|
private String mSubjectAndDescription;
|
2011-04-15 18:09:37 +00:00
|
|
|
private StaticLayout mSubjectLayout;
|
2010-11-10 20:14:55 +00:00
|
|
|
public boolean mRead;
|
|
|
|
public long mTimestamp;
|
|
|
|
public boolean mHasAttachment = false;
|
|
|
|
public boolean mHasInvite = true;
|
|
|
|
public boolean mIsFavorite = false;
|
2011-06-25 02:35:34 +00:00
|
|
|
public boolean mHasBeenRepliedTo = false;
|
|
|
|
public boolean mHasBeenForwarded = false;
|
2010-11-22 21:47:11 +00:00
|
|
|
/** {@link Paint} for account color chips. null if no chips should be drawn. */
|
|
|
|
public Paint mColorChipPaint;
|
2010-11-10 20:14:55 +00:00
|
|
|
|
|
|
|
private int mMode = -1;
|
|
|
|
|
|
|
|
private int mViewWidth = 0;
|
|
|
|
private int mViewHeight = 0;
|
2011-04-15 18:09:37 +00:00
|
|
|
|
2010-11-10 20:14:55 +00:00
|
|
|
private static int sTextSize;
|
|
|
|
private static int sItemHeightWide;
|
|
|
|
private static int sItemHeightNarrow;
|
2011-01-06 00:11:08 +00:00
|
|
|
|
|
|
|
// Note: these cannot be shared Drawables because they are selectors which have state.
|
|
|
|
private Drawable mReadSelector;
|
|
|
|
private Drawable mUnreadSelector;
|
|
|
|
private Drawable mWideReadSelector;
|
|
|
|
private Drawable mWideUnreadSelector;
|
2010-11-10 20:14:55 +00:00
|
|
|
|
|
|
|
public int mSnippetLineCount = NEEDS_LAYOUT;
|
|
|
|
private CharSequence mFormattedSender;
|
|
|
|
private CharSequence mFormattedDate;
|
|
|
|
|
|
|
|
private void init(Context context) {
|
2011-04-15 18:09:37 +00:00
|
|
|
mContext = context;
|
2010-11-10 20:14:55 +00:00
|
|
|
if (!sInit) {
|
|
|
|
Resources r = context.getResources();
|
2011-06-23 21:51:19 +00:00
|
|
|
sSubjectDescription = r.getString(R.string.message_subject_description).concat(", ");
|
|
|
|
sSubjectEmptyDescription = r.getString(R.string.message_is_empty_description);
|
2010-12-04 07:12:48 +00:00
|
|
|
sSubjectSnippetDivider = r.getString(R.string.message_list_subject_snippet_divider);
|
2010-11-10 20:14:55 +00:00
|
|
|
sTextSize =
|
|
|
|
r.getDimensionPixelSize(R.dimen.message_list_item_text_size);
|
|
|
|
sItemHeightWide =
|
|
|
|
r.getDimensionPixelSize(R.dimen.message_list_item_height_wide);
|
|
|
|
sItemHeightNarrow =
|
|
|
|
r.getDimensionPixelSize(R.dimen.message_list_item_height_narrow);
|
|
|
|
|
|
|
|
sDefaultPaint.setTypeface(Typeface.DEFAULT);
|
|
|
|
sDefaultPaint.setTextSize(sTextSize);
|
|
|
|
sDefaultPaint.setAntiAlias(true);
|
|
|
|
sDatePaint.setTypeface(Typeface.DEFAULT);
|
|
|
|
sDatePaint.setAntiAlias(true);
|
|
|
|
sBoldPaint.setTextSize(sTextSize);
|
2011-04-15 18:09:37 +00:00
|
|
|
sBoldPaint.setTypeface(Typeface.DEFAULT_BOLD);
|
2010-11-10 20:14:55 +00:00
|
|
|
sBoldPaint.setAntiAlias(true);
|
2011-03-31 20:29:23 +00:00
|
|
|
sHighlightPaint.setColor(TextUtilities.HIGHLIGHT_COLOR_INT);
|
2011-01-06 21:42:20 +00:00
|
|
|
sAttachmentIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_attachment);
|
|
|
|
sInviteIcon = BitmapFactory.decodeResource(r, R.drawable.ic_badge_invite);
|
2010-11-10 20:14:55 +00:00
|
|
|
sFavoriteIconOff =
|
2011-01-27 01:35:55 +00:00
|
|
|
BitmapFactory.decodeResource(r, R.drawable.btn_star_off_normal_email_holo_light);
|
2010-11-10 20:14:55 +00:00
|
|
|
sFavoriteIconOn =
|
2011-01-27 01:35:55 +00:00
|
|
|
BitmapFactory.decodeResource(r, R.drawable.btn_star_on_normal_email_holo_light);
|
2010-11-10 20:14:55 +00:00
|
|
|
sSelectedIconOff =
|
|
|
|
BitmapFactory.decodeResource(r, R.drawable.btn_check_off_normal_holo_light);
|
|
|
|
sSelectedIconOn =
|
|
|
|
BitmapFactory.decodeResource(r, R.drawable.btn_check_on_normal_holo_light);
|
|
|
|
|
2011-06-25 02:35:34 +00:00
|
|
|
//TODO: put the actual drawables when they exist. these are temps for visibile testing.
|
|
|
|
sStateReplied =
|
|
|
|
BitmapFactory.decodeResource(r, R.drawable.reply);
|
|
|
|
sStateForwarded =
|
|
|
|
BitmapFactory.decodeResource(r, R.drawable.forward);
|
|
|
|
sStateRepliedAndForwarded =
|
|
|
|
BitmapFactory.decodeResource(r, R.drawable.reply_all);
|
|
|
|
|
2010-11-10 20:14:55 +00:00
|
|
|
sInit = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-23 21:51:19 +00:00
|
|
|
/**
|
|
|
|
* Sets message subject safely, ensuring the cache is invalidated.
|
|
|
|
*/
|
|
|
|
public void setSubject(String subject) {
|
|
|
|
if (!subject.equals(mSubject)) {
|
|
|
|
mSubject = subject;
|
|
|
|
mSubjectAndDescription = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-10 20:14:55 +00:00
|
|
|
/**
|
|
|
|
* Determine the mode of this view (WIDE or NORMAL)
|
|
|
|
*
|
|
|
|
* @param width The width of the view
|
|
|
|
* @return The mode of the view
|
|
|
|
*/
|
|
|
|
private int getViewMode(int width) {
|
2011-04-15 18:09:37 +00:00
|
|
|
return MessageListItemCoordinates.getMode(mContext, width);
|
2010-11-10 20:14:55 +00:00
|
|
|
}
|
|
|
|
|
2011-01-06 00:11:08 +00:00
|
|
|
private Drawable mCurentBackground = null; // Only used by updateBackground()
|
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
private void updateBackground() {
|
2011-01-06 00:11:08 +00:00
|
|
|
final Drawable newBackground;
|
2011-01-05 18:47:08 +00:00
|
|
|
if (mRead) {
|
|
|
|
if (mMode == MODE_WIDE) {
|
2011-01-06 00:11:08 +00:00
|
|
|
if (mWideReadSelector == null) {
|
|
|
|
mWideReadSelector = getContext().getResources()
|
|
|
|
.getDrawable(R.drawable.message_list_wide_read_selector);
|
|
|
|
}
|
|
|
|
newBackground = mWideReadSelector;
|
2011-01-05 18:47:08 +00:00
|
|
|
} else {
|
2011-01-06 00:11:08 +00:00
|
|
|
if (mReadSelector == null) {
|
|
|
|
mReadSelector = getContext().getResources()
|
|
|
|
.getDrawable(R.drawable.message_list_read_selector);
|
|
|
|
}
|
|
|
|
newBackground = mReadSelector;
|
2011-01-05 18:47:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (mMode == MODE_WIDE) {
|
2011-01-06 00:11:08 +00:00
|
|
|
if (mWideUnreadSelector == null) {
|
|
|
|
mWideUnreadSelector = getContext().getResources()
|
|
|
|
.getDrawable(R.drawable.message_list_wide_unread_selector);
|
|
|
|
}
|
|
|
|
newBackground = mWideUnreadSelector;
|
2011-01-05 18:47:08 +00:00
|
|
|
} else {
|
2011-01-06 00:11:08 +00:00
|
|
|
if (mUnreadSelector == null) {
|
|
|
|
mUnreadSelector = getContext().getResources()
|
|
|
|
.getDrawable(R.drawable.message_list_unread_selector);
|
|
|
|
}
|
|
|
|
newBackground = mUnreadSelector;
|
2011-01-05 18:47:08 +00:00
|
|
|
}
|
|
|
|
}
|
2011-01-06 00:11:08 +00:00
|
|
|
if (newBackground != mCurentBackground) {
|
|
|
|
// setBackgroundDrawable is a heavy operation. Only call it when really needed.
|
|
|
|
setBackgroundDrawable(newBackground);
|
|
|
|
mCurentBackground = newBackground;
|
|
|
|
}
|
|
|
|
}
|
2011-01-05 18:47:08 +00:00
|
|
|
|
2011-01-06 00:11:08 +00:00
|
|
|
private void calculateDrawingData() {
|
2010-12-04 07:12:48 +00:00
|
|
|
SpannableStringBuilder ssb = new SpannableStringBuilder();
|
|
|
|
boolean hasSubject = false;
|
|
|
|
if (!TextUtils.isEmpty(mSubject)) {
|
|
|
|
SpannableString ss = new SpannableString(mSubject);
|
|
|
|
ss.setSpan(new StyleSpan(mRead ? Typeface.NORMAL : Typeface.BOLD), 0, ss.length(),
|
|
|
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
ssb.append(ss);
|
|
|
|
hasSubject = true;
|
|
|
|
}
|
|
|
|
if (!TextUtils.isEmpty(mSnippet)) {
|
|
|
|
if (hasSubject) {
|
|
|
|
ssb.append(sSubjectSnippetDivider);
|
|
|
|
}
|
|
|
|
ssb.append(mSnippet);
|
|
|
|
}
|
|
|
|
mText = ssb;
|
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
sDefaultPaint.setTextSize(mCoordinates.subjectFontSize);
|
|
|
|
mSubjectLayout = new StaticLayout(mText, sDefaultPaint,
|
|
|
|
mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
|
|
|
if (mCoordinates.subjectLineCount < mSubjectLayout.getLineCount()) {
|
|
|
|
// TODO: ellipsize.
|
|
|
|
int end = mSubjectLayout.getLineEnd(mCoordinates.subjectLineCount - 1);
|
|
|
|
mSubjectLayout = new StaticLayout(mText.subSequence(0, end),
|
|
|
|
sDefaultPaint, mCoordinates.subjectWidth, Alignment.ALIGN_NORMAL, 1, 0, true);
|
2010-11-10 20:14:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now, format the sender for its width
|
|
|
|
TextPaint senderPaint = mRead ? sDefaultPaint : sBoldPaint;
|
2011-04-15 18:09:37 +00:00
|
|
|
int senderWidth = mCoordinates.sendersWidth;
|
2010-11-10 20:14:55 +00:00
|
|
|
// And get the ellipsized string for the calculated width
|
2011-01-12 01:20:45 +00:00
|
|
|
if (TextUtils.isEmpty(mSender)) {
|
|
|
|
mFormattedSender = "";
|
|
|
|
} else {
|
|
|
|
mFormattedSender = TextUtils.ellipsize(mSender, senderPaint, senderWidth,
|
|
|
|
TruncateAt.END);
|
|
|
|
}
|
2010-11-10 20:14:55 +00:00
|
|
|
// Get a nicely formatted date string (relative to today)
|
2011-04-15 18:09:37 +00:00
|
|
|
mFormattedDate = DateUtils.getRelativeTimeSpanString(getContext(), mTimestamp).toString();
|
2010-11-10 20:14:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
2010-11-23 01:43:11 +00:00
|
|
|
if (widthMeasureSpec != 0 || mViewWidth == 0) {
|
|
|
|
mViewWidth = MeasureSpec.getSize(widthMeasureSpec);
|
|
|
|
int mode = getViewMode(mViewWidth);
|
|
|
|
if (mode != mMode) {
|
|
|
|
// If the mode has changed, set the snippet line count to indicate layout required
|
|
|
|
mMode = mode;
|
|
|
|
mSnippetLineCount = NEEDS_LAYOUT;
|
|
|
|
}
|
|
|
|
mViewHeight = measureHeight(heightMeasureSpec, mMode);
|
2010-11-10 20:14:55 +00:00
|
|
|
}
|
|
|
|
setMeasuredDimension(mViewWidth, mViewHeight);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine the height of this view
|
|
|
|
*
|
|
|
|
* @param measureSpec A measureSpec packed into an int
|
|
|
|
* @param mode The current mode of this view
|
|
|
|
* @return The height of the view, honoring constraints from measureSpec
|
|
|
|
*/
|
|
|
|
private int measureHeight(int measureSpec, int mode) {
|
|
|
|
int result = 0;
|
|
|
|
int specMode = MeasureSpec.getMode(measureSpec);
|
|
|
|
int specSize = MeasureSpec.getSize(measureSpec);
|
|
|
|
|
|
|
|
if (specMode == MeasureSpec.EXACTLY) {
|
|
|
|
// We were told how big to be
|
|
|
|
result = specSize;
|
|
|
|
} else {
|
|
|
|
// Measure the text
|
|
|
|
if (mMode == MODE_WIDE) {
|
|
|
|
result = sItemHeightWide;
|
|
|
|
} else {
|
|
|
|
result = sItemHeightNarrow;
|
|
|
|
}
|
|
|
|
if (specMode == MeasureSpec.AT_MOST) {
|
|
|
|
// Respect AT_MOST value if that was what is called for by
|
|
|
|
// measureSpec
|
|
|
|
result = Math.min(result, specSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-01-06 00:11:08 +00:00
|
|
|
@Override
|
|
|
|
public void draw(Canvas canvas) {
|
|
|
|
// Update the background, before View.draw() draws it.
|
2011-03-08 00:13:54 +00:00
|
|
|
setSelected(mAdapter.isSelected(this));
|
2011-01-06 00:11:08 +00:00
|
|
|
updateBackground();
|
|
|
|
super.draw(canvas);
|
|
|
|
}
|
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
@Override
|
|
|
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
|
|
|
super.onLayout(changed, left, top, right, bottom);
|
|
|
|
|
|
|
|
mCoordinates = MessageListItemCoordinates.forWidth(mContext, mViewWidth);
|
|
|
|
}
|
|
|
|
|
2010-11-10 20:14:55 +00:00
|
|
|
@Override
|
|
|
|
protected void onDraw(Canvas canvas) {
|
|
|
|
if (mSnippetLineCount == NEEDS_LAYOUT) {
|
|
|
|
calculateDrawingData();
|
|
|
|
}
|
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
// Draw the color chip indicating the mailbox this belongs to
|
2010-11-22 21:47:11 +00:00
|
|
|
if (mColorChipPaint != null) {
|
2011-04-15 18:09:37 +00:00
|
|
|
canvas.drawRect(
|
|
|
|
mCoordinates.chipX, mCoordinates.chipY,
|
|
|
|
mCoordinates.chipX + mCoordinates.chipWidth,
|
|
|
|
mCoordinates.chipY + mCoordinates.chipHeight,
|
|
|
|
mColorChipPaint);
|
2010-11-22 21:47:11 +00:00
|
|
|
}
|
|
|
|
|
2010-11-10 20:14:55 +00:00
|
|
|
// Draw the checkbox
|
|
|
|
canvas.drawBitmap(mAdapter.isSelected(this) ? sSelectedIconOn : sSelectedIconOff,
|
2011-04-15 18:09:37 +00:00
|
|
|
mCoordinates.checkmarkX, mCoordinates.checkmarkY, sDefaultPaint);
|
2010-11-10 20:14:55 +00:00
|
|
|
|
|
|
|
// Draw the sender name
|
2011-04-15 18:09:37 +00:00
|
|
|
canvas.drawText(mFormattedSender, 0, mFormattedSender.length(),
|
|
|
|
mCoordinates.sendersX, mCoordinates.sendersY - mCoordinates.sendersAscent,
|
2010-11-10 20:14:55 +00:00
|
|
|
mRead ? sDefaultPaint : sBoldPaint);
|
|
|
|
|
2011-06-25 02:35:34 +00:00
|
|
|
// Draw the reply state. Draw nothing if neither replied nor forwarded.
|
|
|
|
if (mHasBeenRepliedTo && mHasBeenForwarded) {
|
2011-07-06 20:48:51 +00:00
|
|
|
canvas.drawBitmap(sStateRepliedAndForwarded,
|
2011-06-25 02:35:34 +00:00
|
|
|
mCoordinates.stateX, mCoordinates.stateY, sDefaultPaint);
|
|
|
|
} else if (mHasBeenRepliedTo) {
|
2011-07-06 20:48:51 +00:00
|
|
|
canvas.drawBitmap(sStateReplied,
|
2011-06-25 02:35:34 +00:00
|
|
|
mCoordinates.stateX, mCoordinates.stateY, sDefaultPaint);
|
|
|
|
} else if (mHasBeenForwarded) {
|
2011-07-06 20:48:51 +00:00
|
|
|
canvas.drawBitmap(sStateForwarded,
|
2011-06-25 02:35:34 +00:00
|
|
|
mCoordinates.stateX, mCoordinates.stateY, sDefaultPaint);
|
|
|
|
}
|
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
// Subject and snippet.
|
|
|
|
sDefaultPaint.setTextSize(mCoordinates.subjectFontSize);
|
|
|
|
sDefaultPaint.setTypeface(Typeface.DEFAULT);
|
|
|
|
canvas.save();
|
|
|
|
canvas.translate(
|
|
|
|
mCoordinates.subjectX,
|
|
|
|
mCoordinates.subjectY);
|
|
|
|
mSubjectLayout.draw(canvas);
|
|
|
|
canvas.restore();
|
2010-11-10 20:14:55 +00:00
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
// Draw the date
|
|
|
|
sDatePaint.setTextSize(mCoordinates.dateFontSize);
|
|
|
|
int dateX = mCoordinates.dateXEnd
|
|
|
|
- (int) sDatePaint.measureText(mFormattedDate, 0, mFormattedDate.length());
|
|
|
|
|
|
|
|
canvas.drawText(mFormattedDate, 0, mFormattedDate.length(),
|
|
|
|
dateX, mCoordinates.dateY - mCoordinates.dateAscent, sDatePaint);
|
2010-12-04 07:12:48 +00:00
|
|
|
|
2011-04-15 18:09:37 +00:00
|
|
|
// Draw the favorite icon
|
|
|
|
canvas.drawBitmap(mIsFavorite ? sFavoriteIconOn : sFavoriteIconOff,
|
|
|
|
mCoordinates.starX, mCoordinates.starY, sDefaultPaint);
|
|
|
|
|
|
|
|
// TODO: deal with the icon layouts better from the coordinate class so that this logic
|
|
|
|
// doesn't have to exist.
|
|
|
|
// Draw the attachment and invite icons, if necessary.
|
|
|
|
int iconsLeft = dateX;
|
2010-11-10 20:14:55 +00:00
|
|
|
if (mHasAttachment) {
|
2011-04-15 18:09:37 +00:00
|
|
|
iconsLeft = iconsLeft - sAttachmentIcon.getWidth();
|
|
|
|
canvas.drawBitmap(sAttachmentIcon, iconsLeft, mCoordinates.paperclipY, sDefaultPaint);
|
2010-11-10 20:14:55 +00:00
|
|
|
}
|
|
|
|
if (mHasInvite) {
|
2011-04-15 18:09:37 +00:00
|
|
|
iconsLeft -= sInviteIcon.getWidth();
|
|
|
|
canvas.drawBitmap(sInviteIcon, iconsLeft, mCoordinates.paperclipY, sDefaultPaint);
|
2010-11-10 20:14:55 +00:00
|
|
|
}
|
|
|
|
|
2009-07-07 20:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called by the adapter at bindView() time
|
2010-06-02 00:55:31 +00:00
|
|
|
*
|
2009-07-07 20:43:24 +00:00
|
|
|
* @param adapter the adapter that creates this view
|
|
|
|
*/
|
2010-06-23 00:19:58 +00:00
|
|
|
public void bindViewInit(MessagesAdapter adapter) {
|
2009-07-07 20:43:24 +00:00
|
|
|
mAdapter = adapter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Overriding this method allows us to "catch" clicks in the checkbox or star
|
|
|
|
* and process them accordingly.
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
|
|
boolean handled = false;
|
|
|
|
int touchX = (int) event.getX();
|
2011-04-15 18:09:37 +00:00
|
|
|
int checkRight = mCoordinates.checkmarkWidthIncludingMargins;
|
|
|
|
int starLeft = mViewWidth - mCoordinates.starWidthIncludingMargins;
|
2009-07-07 20:43:24 +00:00
|
|
|
|
|
|
|
switch (event.getAction()) {
|
|
|
|
case MotionEvent.ACTION_DOWN:
|
2010-11-10 20:14:55 +00:00
|
|
|
if (touchX < checkRight || touchX > starLeft) {
|
2010-10-14 02:04:46 +00:00
|
|
|
mDownEvent = true;
|
2010-11-10 20:14:55 +00:00
|
|
|
if ((touchX < checkRight) || (touchX > starLeft)) {
|
2010-10-14 02:04:46 +00:00
|
|
|
handled = true;
|
|
|
|
}
|
2009-07-07 20:43:24 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MotionEvent.ACTION_CANCEL:
|
|
|
|
mDownEvent = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MotionEvent.ACTION_UP:
|
|
|
|
if (mDownEvent) {
|
2010-11-10 20:14:55 +00:00
|
|
|
if (touchX < checkRight) {
|
2010-08-27 20:00:48 +00:00
|
|
|
mAdapter.toggleSelected(this);
|
|
|
|
handled = true;
|
2010-11-10 20:14:55 +00:00
|
|
|
} else if (touchX > starLeft) {
|
|
|
|
mIsFavorite = !mIsFavorite;
|
|
|
|
mAdapter.updateFavorite(this, mIsFavorite);
|
2009-07-07 20:43:24 +00:00
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handled) {
|
2010-11-10 20:14:55 +00:00
|
|
|
invalidate();
|
2009-07-07 20:43:24 +00:00
|
|
|
} else {
|
|
|
|
handled = super.onTouchEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
2011-06-23 21:51:19 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
|
|
|
CharSequence contentDescription = getContentDescription(mContext);
|
|
|
|
if (!TextUtils.isEmpty(contentDescription)) {
|
|
|
|
event.setClassName(getClass().getName());
|
|
|
|
event.setPackageName(getContext().getPackageName());
|
|
|
|
event.setEnabled(true);
|
|
|
|
event.setContentDescription(contentDescription);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get message information to use for accessibility.
|
|
|
|
*/
|
|
|
|
private CharSequence getContentDescription(Context context) {
|
|
|
|
if (mSubjectAndDescription == null) {
|
|
|
|
if (!TextUtils.isEmpty(mSubject)) {
|
|
|
|
mSubjectAndDescription = sSubjectDescription + mSubject;
|
|
|
|
} else {
|
|
|
|
mSubjectAndDescription = sSubjectEmptyDescription;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return mSubjectAndDescription;
|
|
|
|
}
|
2009-07-07 20:43:24 +00:00
|
|
|
}
|