Ad teaser redesign.
b/12243411.
Change-Id: I993b326bc36de8edf1f2f40202d8f32551de4d94
diff --git a/res/layout/conversation_item_view_normal.xml b/res/layout/conversation_item_view_normal.xml
index b34a019..f1f24ae 100644
--- a/res/layout/conversation_item_view_normal.xml
+++ b/res/layout/conversation_item_view_normal.xml
@@ -29,10 +29,11 @@
android:orientation="vertical">
<LinearLayout
+ android:id="@+id/conversation_item_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
+ android:layout_marginLeft="@dimen/conv_list_padding"
+ android:layout_marginRight="@dimen/conv_list_padding"
android:orientation="horizontal">
<View
diff --git a/res/layout/conversation_item_view_normal_spacious.xml b/res/layout/conversation_item_view_normal_spacious.xml
index be76c11..c93d41d 100644
--- a/res/layout/conversation_item_view_normal_spacious.xml
+++ b/res/layout/conversation_item_view_normal_spacious.xml
@@ -29,10 +29,11 @@
android:orientation="vertical">
<LinearLayout
+ android:id="@+id/conversation_item_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- style="@style/ConversationListSpaciousLinearLayoutStyle" >
+ style="@style/ConversationListSpaciousStyle" >
<View
android:id="@+id/contact_image"
diff --git a/res/layout/conversation_item_view_wide.xml b/res/layout/conversation_item_view_wide.xml
index 3e36b52..adc6f4c 100644
--- a/res/layout/conversation_item_view_wide.xml
+++ b/res/layout/conversation_item_view_wide.xml
@@ -29,9 +29,10 @@
android:orientation="vertical">
<FrameLayout
+ android:id="@+id/conversation_item_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- style="@style/ConversationListFrameStyle" >
+ style="@style/ConversationListWideStyle" >
<!-- minHeight here is to ensure more consistent item heights across gadget choices -->
<!-- and between 'normal' vs. 'wide' layouts (which is important during 2-pane -->
@@ -70,15 +71,27 @@
android:src="@drawable/ic_badge_reply_holo_light"
style="@style/ConversationListReplyStateStyle" />
- <TextView
- android:id="@+id/senders"
+ <LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:textSize="18sp"
- android:lines="1"
- android:includeFontPadding="false"
- android:text="@string/long_string" />
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/senders"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textSize="18sp"
+ android:lines="1"
+ android:includeFontPadding="false"
+ android:text="@string/long_string" />
+ <TextView
+ android:id="@+id/badge"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:lines="1"
+ android:includeFontPadding="false"
+ android:text="@string/long_string" />
+ </LinearLayout>
<FrameLayout
android:layout_width="54dp"
diff --git a/res/values-ldrtl/styles-ldrtl.xml b/res/values-ldrtl/styles-ldrtl.xml
index 0f350b5..c931b7f 100644
--- a/res/values-ldrtl/styles-ldrtl.xml
+++ b/res/values-ldrtl/styles-ldrtl.xml
@@ -324,9 +324,9 @@
<item name="android:layout_marginEnd">@dimen/ap_margin_side</item>
</style>
- <style name="ConversationListFrameStyle">
- <item name="android:layout_marginStart">@dimen/conv_list_frame_padding_start</item>
- <item name="android:layout_marginEnd">@dimen/conv_list_frame_padding_end</item>
+ <style name="ConversationListWideStyle">
+ <item name="android:layout_marginStart">@dimen/conv_list_wide_padding_start</item>
+ <item name="android:layout_marginEnd">@dimen/conv_list_wide_padding_end</item>
</style>
<style name="ConversationListWideContactImageStyle">
@@ -361,11 +361,9 @@
<item name="android:layout_gravity">top|end</item>
</style>
- <style name="ConversationListSpaciousLinearLayoutStyle">
- <item name="android:layout_marginStart">
- @dimen/conv_list_spacious_linearlayout_padding_start</item>
- <item name="android:layout_marginEnd">
- @dimen/conv_list_spacious_linearlayout_padding_end</item>
+ <style name="ConversationListSpaciousStyle">
+ <item name="android:layout_marginStart">@dimen/conv_list_spacious_padding_start</item>
+ <item name="android:layout_marginEnd">@dimen/conv_list_spacious_padding_end</item>
</style>
<style name="ConversationListSpaciousContactImageStyle">
diff --git a/res/values/colors.xml b/res/values/colors.xml
index c095b6c..c44fd3a 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -130,4 +130,6 @@
<color name="swipe_refresh_color2">#ffdb4437</color>
<color name="swipe_refresh_color3">#ff4285f4</color>
<color name="swipe_refresh_color4">#fff4b400</color>
+
+ <color name="badge_background_color">#edb802</color>
</resources>
diff --git a/res/values/dimen.xml b/res/values/dimen.xml
index 801d003..d121151 100644
--- a/res/values/dimen.xml
+++ b/res/values/dimen.xml
@@ -160,6 +160,9 @@
<dimen name="search_results_padding">8dip</dimen>
<!-- conversation list dimensions -->
+ <dimen name="conv_list_padding">16dip</dimen>
+ <dimen name="conv_list_card_border_padding">8dip</dimen>
+ <dimen name="conv_list_no_border_padding">0dip</dimen>
<dimen name="conv_list_contact_image_padding_end">12dip</dimen>
<dimen name="conv_list_reply_state_padding_end">8dip</dimen>
<dimen name="conv_list_personal_indicator_padding_start">-2dip</dimen>
@@ -169,16 +172,19 @@
<dimen name="conv_list_paperclip_padding_start">6dip</dimen>
<dimen name="conv_list_star_padding_end">-9dip</dimen>
- <dimen name="conv_list_frame_padding_start">20dip</dimen>
- <dimen name="conv_list_frame_padding_end">32dip</dimen>
+ <dimen name="conv_list_wide_padding_start">20dip</dimen>
+ <dimen name="conv_list_wide_padding_end">32dip</dimen>
<dimen name="conv_list_wide_contact_image_padding_end">20dip</dimen>
<dimen name="conv_list_wide_personal_indicator_padding_end">8dip</dimen>
<dimen name="conv_list_wide_star_padding_start">32dip</dimen>
<dimen name="conv_list_wide_color_block_padding_end">64dip</dimen>
- <dimen name="conv_list_spacious_linearlayout_padding_start">22dip</dimen>
- <dimen name="conv_list_spacious_linearlayout_padding_end">16dip</dimen>
+ <dimen name="conv_list_spacious_padding_start">22dip</dimen>
+ <dimen name="conv_list_spacious_padding_end">16dip</dimen>
<dimen name="conv_list_spacious_contact_image_padding_end">16dip</dimen>
<dimen name="conv_list_spacious_star_padding_end">-8dip</dimen>
+ <dimen name="badge_padding_extra_width">6dip</dimen>
+ <dimen name="badge_rounded_corner_radius">2dip</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c1b7f39..f7fc403 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -299,9 +299,10 @@
<!-- Formatting string. If the subject contains the tag of a mailing-list (text surrounded with
return the subject with that tag ellipsized, e.g. "[android-gmail-team] Hello" -> "[andr...] Hello" [CHAR LIMIT=100] -->
<string name="filtered_tag"> [<xliff:g id="tag">%1$s</xliff:g>]<xliff:g id="subject">%2$s</xliff:g></string>
- <!-- Displayed in Conversation Header View and Widget in the form of "subject - snippet"
- [CHAR LIMIT=5] -->
+ <!-- Displayed in conversation list item in the form of "subject - snippet" [CHAR LIMIT=5] -->
<string name="subject_and_snippet"><xliff:g>%s</xliff:g> \u2014 <xliff:g>%s</xliff:g></string>
+ <!-- Displayed in conversation list item in the form of "badge subject - snippet" [CHAR LIMIT=7] -->
+ <string name="badge_subject_and_snippet"><xliff:g>%1$s</xliff:g> <xliff:g>%2$s</xliff:g> \u2014 <xliff:g>%3$s</xliff:g></string>
<!-- Displayed in browse list item when the list item is a draft message instead of showing the subject [CHAR LIMIT=100] -->
<plurals name="draft">
<!-- Title of the screen when there is exactly one draft -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 89c3060..b537b92 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -861,9 +861,9 @@
<item name="android:layout_marginRight">@dimen/ap_margin_side</item>
</style>
- <style name="ConversationListFrameStyle">
- <item name="android:layout_marginLeft">@dimen/conv_list_frame_padding_start</item>
- <item name="android:layout_marginRight">@dimen/conv_list_frame_padding_end</item>
+ <style name="ConversationListWideStyle">
+ <item name="android:layout_marginLeft">@dimen/conv_list_wide_padding_start</item>
+ <item name="android:layout_marginRight">@dimen/conv_list_wide_padding_end</item>
</style>
<style name="ConversationListWideContactImageStyle">
@@ -898,11 +898,9 @@
<item name="android:layout_gravity">top|right</item>
</style>
- <style name="ConversationListSpaciousLinearLayoutStyle">
- <item name="android:layout_marginLeft">
- @dimen/conv_list_spacious_linearlayout_padding_start</item>
- <item name="android:layout_marginRight">
- @dimen/conv_list_spacious_linearlayout_padding_end</item>
+ <style name="ConversationListSpaciousStyle">
+ <item name="android:layout_marginLeft">@dimen/conv_list_spacious_padding_start</item>
+ <item name="android:layout_marginRight">@dimen/conv_list_spacious_padding_end</item>
</style>
<style name="ConversationListSpaciousContactImageStyle">
@@ -915,4 +913,10 @@
</style>
<!-- END Conversation list styles -->
+ <style name="BadgeTextStyle">
+ <item name="android:textColor">@android:color/white</item>
+ <item name="android:textSize">12sp</item>
+ <item name="android:textStyle">bold</item>
+ </style>
+
</resources>
diff --git a/src/com/android/mail/browse/BadgeSpan.java b/src/com/android/mail/browse/BadgeSpan.java
new file mode 100644
index 0000000..e849f7d
--- /dev/null
+++ b/src/com/android/mail/browse/BadgeSpan.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 Google Inc.
+ * Licensed to 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.mail.browse;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.graphics.RectF;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.style.CharacterStyle;
+import android.text.style.ReplacementSpan;
+
+/**
+ * A replacement span to use when displaying a badge in a conversation list item.
+ * A badge will be some piece of text with a colored background and rounded
+ * corners.
+ */
+public class BadgeSpan extends ReplacementSpan {
+
+ public interface BadgeSpanDimensions {
+ /**
+ * Returns the padding value that corresponds to one side of the
+ * horizontal padding surrounding the text inside the background color.
+ */
+ int getHorizontalPadding();
+
+ /**
+ * Returns the radius to use for the rounded corners on the background rect.
+ */
+ float getRoundedCornerRadius();
+ }
+
+ private TextPaint mWorkPaint = new TextPaint();
+ /**
+ * A reference to the enclosing Spanned object to collect other CharacterStyle spans and take
+ * them into account when drawing.
+ */
+ private final Spanned mSpanned;
+ private final BadgeSpanDimensions mDims;
+
+ public BadgeSpan(Spanned spanned, BadgeSpanDimensions dims) {
+ mSpanned = spanned;
+ mDims = dims;
+ }
+
+ @Override
+ public int getSize(Paint paint, CharSequence text, int start, int end, FontMetricsInt fm) {
+ if (fm != null) {
+ paint.getFontMetricsInt(fm);
+ // The magic set of measurements to vertically center text within a colored region!
+ fm.top = fm.ascent;
+ }
+ return measureWidth(paint, text, start, end);
+ }
+
+ private int measureWidth(Paint paint, CharSequence text, int start, int end) {
+ return (int) paint.measureText(text, start, end) + 2 * mDims.getHorizontalPadding();
+ }
+
+ @Override
+ public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top,
+ int y, int bottom, Paint paint) {
+
+ mWorkPaint.set(paint);
+
+ // take into account the foreground/background color spans when painting
+ final CharacterStyle[] otherSpans = mSpanned.getSpans(start, end, CharacterStyle.class);
+ for (CharacterStyle otherSpan : otherSpans) {
+ otherSpan.updateDrawState(mWorkPaint);
+ }
+
+ // paint a background if present
+ if (mWorkPaint.bgColor != 0) {
+ final int prevColor = mWorkPaint.getColor();
+ final Paint.Style prevStyle = mWorkPaint.getStyle();
+
+ mWorkPaint.setColor(mWorkPaint.bgColor);
+ mWorkPaint.setStyle(Paint.Style.FILL);
+
+ final int bgWidth = measureWidth(mWorkPaint, text, start, end);
+ final RectF rect = new RectF(x, top, x + bgWidth, bottom);
+ final float radius = mDims.getRoundedCornerRadius();
+ canvas.drawRoundRect(rect, radius, radius, mWorkPaint);
+
+ mWorkPaint.setColor(prevColor);
+ mWorkPaint.setStyle(prevStyle);
+ }
+
+ canvas.drawText(text, start, end, x + mDims.getHorizontalPadding(), y, mWorkPaint);
+ }
+}
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 2de6b15..ac991a0 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -35,6 +35,7 @@
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.support.v4.view.ViewCompat;
import android.text.Layout.Alignment;
import android.text.Spannable;
@@ -45,6 +46,7 @@
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.format.DateUtils;
+import android.text.style.BackgroundColorSpan;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.TextAppearanceSpan;
@@ -61,8 +63,6 @@
import android.widget.TextView;
import com.android.mail.R;
-import com.android.mail.R.drawable;
-import com.android.mail.R.integer;
import com.android.mail.analytics.Analytics;
import com.android.mail.bitmap.AttachmentDrawable;
import com.android.mail.bitmap.AttachmentGridDrawable;
@@ -100,7 +100,7 @@
public class ConversationItemView extends View
implements SwipeableItemView, ToggleableItem, InvalidateCallback, OnScrollListener,
- ConversationSetObserver {
+ ConversationSetObserver, BadgeSpan.BadgeSpanDimensions {
// Timer.
private static int sLayoutCount = 0;
@@ -143,8 +143,9 @@
private static int sSenderImageTouchSlop;
private static int sShrinkAnimationDuration;
private static int sSlideAnimationDuration;
- private static int sOverflowCountMax;
private static int sCabAnimationDuration;
+ private static int sBadgePaddingExtraWidth;
+ private static int sBadgeRoundedCornerRadius;
// Static paints.
private static final TextPaint sPaint = new TextPaint();
@@ -195,6 +196,7 @@
private ControllableActivity mActivity;
private final TextView mSubjectTextView;
private final TextView mSendersTextView;
+ private final TextView mBadgeTextView;
private int mGadgetMode;
private boolean mAttachmentPreviewsEnabled;
private boolean mParallaxSpeedAlternative;
@@ -203,6 +205,8 @@
private static int sFoldersStartPadding;
private static TextAppearanceSpan sSubjectTextUnreadSpan;
private static TextAppearanceSpan sSubjectTextReadSpan;
+ private static TextAppearanceSpan sBadgeTextSpan;
+ private static BackgroundColorSpan sBadgeBackgroundSpan;
private static ForegroundColorSpan sSnippetTextUnreadSpan;
private static ForegroundColorSpan sSnippetTextReadSpan;
private static int sScrollSlop;
@@ -354,8 +358,9 @@
if (labelTooLong) {
// todo - take RTL into account for fade
final int rightBorder = xLeft + width - sFoldersStartPadding - padding;
- final Shader shader = new LinearGradient(rightBorder - padding, y, rightBorder, y,
- fgColor, Utils.getTransparentColor(fgColor), Shader.TileMode.CLAMP);
+ final Shader shader = new LinearGradient(rightBorder - padding, y,
+ rightBorder, y, fgColor, Utils.getTransparentColor(fgColor),
+ Shader.TileMode.CLAMP);
sFoldersPaint.setShader(shader);
}
canvas.drawText(folderString, xLeft + padding, y + height - textBottomPadding,
@@ -407,8 +412,8 @@
BitmapFactory.decodeResource(res, R.drawable.ic_badge_invite_holo_light);
VISIBLE_CONVERSATION_CARET = BitmapFactory.decodeResource(res, R.drawable.caret_grey);
RIGHT_EDGE_TABLET = res.getDrawable(R.drawable.list_edge_tablet);
- PLACEHOLDER = res.getDrawable(drawable.ic_attachment_load);
- PROGRESS_BAR = res.getDrawable(drawable.progress_holo);
+ PLACEHOLDER = res.getDrawable(R.drawable.ic_attachment_load);
+ PROGRESS_BAR = res.getDrawable(R.drawable.progress_holo);
// Initialize colors.
sActivatedTextSpan = CharacterStyle.wrap(new ForegroundColorSpan(
@@ -417,8 +422,11 @@
sSendersTextColorUnread = res.getColor(R.color.senders_text_color_unread);
sSubjectTextUnreadSpan = new TextAppearanceSpan(mContext,
R.style.SubjectAppearanceUnreadStyle);
- sSubjectTextReadSpan = new TextAppearanceSpan(mContext,
- R.style.SubjectAppearanceReadStyle);
+ sBadgeTextSpan = new TextAppearanceSpan(mContext, R.style.BadgeTextStyle);
+ sBadgeBackgroundSpan = new BackgroundColorSpan(
+ res.getColor(R.color.badge_background_color));
+ sSubjectTextReadSpan = new TextAppearanceSpan(
+ mContext, R.style.SubjectAppearanceReadStyle);
sSnippetTextUnreadSpan =
new ForegroundColorSpan(res.getColor(R.color.snippet_text_color_unread));
sSnippetTextReadSpan =
@@ -433,8 +441,10 @@
sElidedPaddingToken = res.getString(R.string.elided_padding_token);
sScrollSlop = res.getInteger(R.integer.swipeScrollSlop);
sFoldersStartPadding = res.getDimensionPixelOffset(R.dimen.folders_start_padding);
- sOverflowCountMax = res.getInteger(integer.ap_overflow_max_count);
sCabAnimationDuration = res.getInteger(R.integer.conv_item_view_cab_anim_duration);
+ sBadgePaddingExtraWidth = res.getDimensionPixelSize(R.dimen.badge_padding_extra_width);
+ sBadgeRoundedCornerRadius =
+ res.getDimensionPixelSize(R.dimen.badge_rounded_corner_radius);
}
mSendersTextView = new TextView(mContext);
@@ -444,6 +454,9 @@
mSubjectTextView.setEllipsize(TextUtils.TruncateAt.END);
mSubjectTextView.setIncludeFontPadding(false);
+ mBadgeTextView = new TextView(mContext);
+ mBadgeTextView.setIncludeFontPadding(false);
+
mAttachmentsView = new AttachmentGridDrawable(res, PLACEHOLDER, PROGRESS_BAR);
mAttachmentsView.setCallback(this);
@@ -464,7 +477,8 @@
null /* conversationItemAreaClickListener */,
set, folder, checkboxOrSenderImage, showAttachmentPreviews,
parallaxSpeedAlternative, parallaxDirectionAlternative, swipeEnabled,
- priorityArrowEnabled, adapter, -1 /* backgroundOverrideResId */, null /* photoBitmap */);
+ priorityArrowEnabled, adapter, -1 /* backgroundOverrideResId */,
+ null /* photoBitmap */, false /* useFullMargins */);
Utils.traceEndSection();
}
@@ -478,7 +492,7 @@
folder, checkboxOrSenderImage, false /* attachment previews */,
false /* parallax */, false /* parallax */, true /* swipeEnabled */,
false /* priorityArrowEnabled */,
- adapter, backgroundOverrideResId, photoBitmap);
+ adapter, backgroundOverrideResId, photoBitmap, true /* useFullMargins */);
Utils.traceEndSection();
}
@@ -488,7 +502,8 @@
final int checkboxOrSenderImage, final boolean showAttachmentPreviews,
final boolean parallaxSpeedAlternative, final boolean parallaxDirectionAlternative,
boolean swipeEnabled, final boolean priorityArrowEnabled, final AnimatedAdapter adapter,
- final int backgroundOverrideResId, final Bitmap photoBitmap) {
+ final int backgroundOverrideResId, final Bitmap photoBitmap,
+ final boolean useFullMargins) {
mBackgroundOverrideResId = backgroundOverrideResId;
mPhotoBitmap = photoBitmap;
mConversationItemAreaClickListener = conversationItemAreaClickListener;
@@ -580,19 +595,20 @@
mDisplayedFolder.folderUri, ignoreFolderType);
Utils.traceEndSection();
- if (mHeader.dateOverrideText == null) {
+ if (mHeader.showDateText) {
Utils.traceBeginSection("relative time");
mHeader.dateText = DateUtils.getRelativeTimeSpanString(mContext,
mHeader.conversation.dateMs);
Utils.traceEndSection();
} else {
- mHeader.dateText = mHeader.dateOverrideText;
+ mHeader.dateText = "";
}
Utils.traceBeginSection("config setup");
mConfig = new ConversationItemViewCoordinates.Config()
.withGadget(mGadgetMode)
- .withAttachmentPreviews(getAttachmentPreviewsMode());
+ .withAttachmentPreviews(getAttachmentPreviewsMode())
+ .setUseFullMargins(useFullMargins);
if (header.folderDisplayer.hasVisibleFolders()) {
mConfig.showFolders();
}
@@ -736,6 +752,8 @@
Utils.traceBeginSection("subject");
createSubject(mHeader.unread);
+ createBadge();
+
if (!mHeader.isLayoutValid()) {
setContentDescription();
}
@@ -764,6 +782,10 @@
Drawable drawable = mBackgrounds.get(resourceId);
if (drawable == null) {
drawable = getResources().getDrawable(resourceId);
+ final int insetPadding = mHeader.insetPadding;
+ if (insetPadding > 0) {
+ drawable = new InsetDrawable(drawable, insetPadding);
+ }
mBackgrounds.put(resourceId, drawable);
}
if (getBackground() != drawable) {
@@ -781,8 +803,7 @@
setSelected(mSelected);
mHeader.gadgetMode = mGadgetMode;
- final boolean isUnread = mHeader.unread;
- updateBackground(isUnread);
+ updateBackground();
mHeader.sendersDisplayText = new SpannableStringBuilder();
mHeader.styledSendersString = null;
@@ -1013,18 +1034,25 @@
}
private void createSubject(final boolean isUnread) {
+ // Need to check if we're in wide mode because the badge
+ // does not get added if we're in wide mode.
+ final String badgeText = mCoordinates.isWideMode() ? "" : mHeader.badgeText;
final String subject = filterTag(mHeader.conversation.subject);
final String snippet = mHeader.conversation.getSnippet();
final Spannable displayedStringBuilder = new SpannableString(
- Conversation.getSubjectAndSnippetForDisplay(mContext, subject, snippet));
+ Conversation.getSubjectAndSnippetForDisplay(mContext, badgeText, subject, snippet));
// since spans affect text metrics, add spans to the string before measure/layout or fancy
// ellipsizing
- final int subjectTextLength = (subject != null) ? subject.length() : 0;
+
+ final int badgeTextLength = formatBadgeText(displayedStringBuilder, badgeText);
+
+ final int subjectTextLength = badgeTextLength + ((subject != null) ? subject.length() : 0)
+ + ((badgeTextLength > 0) ? 1 : 0);
if (!TextUtils.isEmpty(subject)) {
displayedStringBuilder.setSpan(TextAppearanceSpan.wrap(
- isUnread ? sSubjectTextUnreadSpan : sSubjectTextReadSpan), 0, subjectTextLength,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ isUnread ? sSubjectTextUnreadSpan : sSubjectTextReadSpan),
+ badgeTextLength, subjectTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (!TextUtils.isEmpty(snippet)) {
final int startOffset = subjectTextLength;
@@ -1035,8 +1063,8 @@
displayedStringBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (isActivated() && showActivatedText()) {
- displayedStringBuilder.setSpan(sActivatedTextSpan, 0, displayedStringBuilder.length(),
- Spannable.SPAN_INCLUSIVE_INCLUSIVE);
+ displayedStringBuilder.setSpan(sActivatedTextSpan, badgeTextLength,
+ displayedStringBuilder.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
}
final int subjectWidth = mCoordinates.subjectWidth;
@@ -1049,6 +1077,53 @@
mSubjectTextView.setText(displayedStringBuilder);
}
+ private void createBadge() {
+ // Do not create badge if in wide mode or badge text is empty.
+ final String badgeText = mHeader.badgeText;
+ if (!mCoordinates.isWideMode() || TextUtils.isEmpty(badgeText)) {
+ return;
+ }
+
+ final Spannable displayedBadgeString = new SpannableString(badgeText);
+ formatBadgeText(displayedBadgeString, badgeText);
+
+ final int badgeWidth = mCoordinates.badgeWidth;
+ final int badgeHeight = mCoordinates.badgeHeight;
+ mBadgeTextView.setLayoutParams(new ViewGroup.LayoutParams(badgeWidth, badgeHeight));
+ mBadgeTextView.setMaxLines(mCoordinates.badgeLineCount);
+ layoutViewExactly(mBadgeTextView, badgeWidth, badgeHeight);
+
+ mBadgeTextView.setText(displayedBadgeString);
+ }
+
+ private int formatBadgeText(Spannable displayedStringBuilder, String badgeText) {
+ final int badgeTextLength = (badgeText != null) ? badgeText.length() : 0;
+ if (!TextUtils.isEmpty(badgeText)) {
+ displayedStringBuilder.setSpan(TextAppearanceSpan.wrap(sBadgeTextSpan),
+ 0, badgeTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ displayedStringBuilder.setSpan(TextAppearanceSpan.wrap(sBadgeBackgroundSpan),
+ 0, badgeTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ displayedStringBuilder.setSpan(new BadgeSpan(displayedStringBuilder, this),
+ 0, badgeTextLength, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ return badgeTextLength;
+ }
+
+ // START BadgeSpan.BadgeSpanDimensions override
+
+ @Override
+ public int getHorizontalPadding() {
+ return sBadgePaddingExtraWidth;
+ }
+
+ @Override
+ public float getRoundedCornerRadius() {
+ return sBadgeRoundedCornerRadius;
+ }
+
+ // END BadgeSpan.BadgeSpanDimensions override
+
private boolean showActivatedText() {
// For activated elements in tablet in conversation mode, we show an activated color, since
// the background is dark blue for activated versus gray for non-activated.
@@ -1098,7 +1173,7 @@
mPaperclipX = (isRtl) ? mDateX + mDateWidth + mCoordinates.datePaddingStart :
mDateX - ATTACHMENT.getWidth() - mCoordinates.datePaddingStart;
- if (mCoordinates.isWide()) {
+ if (mCoordinates.isWideMode()) {
// In wide mode, the end of the senders should align with
// the start of the subject and is based on a max width.
mSendersWidth = mCoordinates.sendersWidth;
@@ -1317,6 +1392,12 @@
drawSubject(canvas);
canvas.restore();
+ if (mCoordinates.isWideMode()) {
+ canvas.save();
+ drawBadge(canvas);
+ canvas.restore();
+ }
+
// Folders.
if (mConfig.areFoldersVisible()) {
mHeader.folderDisplayer.drawFolders(canvas, mCoordinates, ViewUtils.isViewRtl(this));
@@ -1450,6 +1531,11 @@
mSubjectTextView.draw(canvas);
}
+ private void drawBadge(Canvas canvas) {
+ canvas.translate(mCoordinates.badgeLeft, mCoordinates.badgeTop);
+ mBadgeTextView.draw(canvas);
+ }
+
private void drawSenders(Canvas canvas) {
canvas.translate(mSendersX, mCoordinates.sendersY);
mSendersTextView.draw(canvas);
@@ -1469,13 +1555,12 @@
* 2. Tablet / Phone
* 3. Checkbox checked / Unchecked (controls CAB color for item)
* 4. Activated / Not activated (controls the blue highlight on tablet)
- * @param isUnread
*/
- private void updateBackground(boolean isUnread) {
+ private void updateBackground() {
final int background;
if (mBackgroundOverrideResId > 0) {
background = mBackgroundOverrideResId;
- } else if (isUnread) {
+ } else if (mHeader.unread) {
background = R.drawable.conversation_unread_selector;
} else {
background = R.drawable.conversation_read_selector;
@@ -1605,7 +1690,7 @@
}
if (mStarEnabled) {
- if (mCoordinates.getMode() == ConversationItemViewCoordinates.WIDE_MODE) {
+ if (mCoordinates.isWideMode()) {
// Just check that we're to start of the star's touch area
if (isTouchInStarTargetX(isRtl, x)) {
return false;
@@ -1628,7 +1713,7 @@
private boolean isTouchInStar(float x, float y) {
if (mHeader.infoIcon != null
- && mCoordinates.getMode() != ConversationItemViewCoordinates.WIDE_MODE) {
+ && !mCoordinates.isWideMode()) {
// We have an info icon, and it's above the star
// We allow touches everywhere below the top of the subject text
if (y < mCoordinates.subjectY) {
diff --git a/src/com/android/mail/browse/ConversationItemViewCoordinates.java b/src/com/android/mail/browse/ConversationItemViewCoordinates.java
index 209cd16..a35539a 100644
--- a/src/com/android/mail/browse/ConversationItemViewCoordinates.java
+++ b/src/com/android/mail/browse/ConversationItemViewCoordinates.java
@@ -17,6 +17,7 @@
package com.android.mail.browse;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Paint.FontMetricsInt;
@@ -32,8 +33,6 @@
import android.widget.TextView;
import com.android.mail.R;
-import com.android.mail.R.dimen;
-import com.android.mail.R.id;
import com.android.mail.ui.ViewMode;
import com.android.mail.utils.Utils;
import com.android.mail.utils.ViewUtils;
@@ -83,6 +82,7 @@
private boolean mShowReplyState = false;
private boolean mShowColorBlock = false;
private boolean mShowPersonalIndicator = false;
+ private boolean mUseFullMargins = false;
public Config setViewMode(int viewMode) {
mViewMode = viewMode;
@@ -159,7 +159,8 @@
private int getCacheKey() {
// hash the attributes that contribute to item height and child view geometry
return Objects.hashCode(mWidth, mViewMode, mGadgetMode, mAttachmentPreviewMode,
- mShowFolders, mShowReplyState, mShowPersonalIndicator);
+ mShowFolders, mShowReplyState, mShowPersonalIndicator, mLayoutDirection,
+ mUseFullMargins);
}
public Config setLayoutDirection(int layoutDirection) {
@@ -170,6 +171,15 @@
public int getLayoutDirection() {
return mLayoutDirection;
}
+
+ public Config setUseFullMargins(boolean useFullMargins) {
+ mUseFullMargins = useFullMargins;
+ return this;
+ }
+
+ public boolean useFullPadding() {
+ return mUseFullMargins;
+ }
}
public static class CoordinatesCache {
@@ -212,9 +222,15 @@
final int sendersWidth;
final int sendersHeight;
final int sendersLineCount;
- final int sendersLineHeight;
final float sendersFontSize;
+ // Badge. optional.
+ final int badgeLeft;
+ final int badgeTop;
+ final int badgeWidth;
+ final int badgeHeight;
+ final int badgeLineCount;
+
// Subject.
final int subjectX;
final int subjectY;
@@ -316,7 +332,7 @@
mMode = calculateMode(res, config);
final int layoutId;
- if (mMode == WIDE_MODE) {
+ if (isWideMode()) {
layoutId = R.layout.conversation_item_view_wide;
} else {
if (config.getWidth() >= mMinListWidthIsSpacious) {
@@ -379,6 +395,8 @@
personalIndicator.setVisibility(
config.isPersonalIndicatorVisible() ? View.VISIBLE : View.GONE);
+ setFramePadding(context, view, config.useFullPadding());
+
// Layout the appropriate view.
ViewCompat.setLayoutDirection(view, config.getLayoutDirection());
final int widthSpec = MeasureSpec.makeMeasureSpec(config.getWidth(), MeasureSpec.EXACTLY);
@@ -413,13 +431,23 @@
sendersWidth = senders.getWidth();
sendersHeight = senders.getHeight();
sendersLineCount = getLineCount(senders);
- sendersLineHeight = senders.getLineHeight();
sendersFontSize = senders.getTextSize();
+ final TextView badge = (TextView) view.findViewById(R.id.badge);
+ if (badge != null) {
+ badgeLeft = getX(badge);
+ badgeTop = getY(badge);
+ badgeWidth = senders.getWidth();
+ badgeHeight = senders.getHeight();
+ badgeLineCount = getLineCount(senders);
+ } else {
+ badgeLeft = badgeTop = badgeWidth = badgeHeight = badgeLineCount = 0;
+ }
+
final TextView subject = (TextView) view.findViewById(R.id.subject);
final int subjectTopAdjust = getLatinTopAdjustment(subject);
subjectX = getX(subject);
- if (isWide()) {
+ if (isWideMode()) {
subjectY = getY(subject) + subjectTopAdjust;
} else {
subjectY = getY(subject) + sendersTopAdjust;
@@ -434,7 +462,7 @@
final boolean isRtl = ViewUtils.isViewRtl(view);
foldersLeft = (isRtl) ? 0 : subjectX;
foldersRight = (isRtl) ? subjectX + subjectWidth : getX(folders) + folders.getWidth();
- if (isWide()) {
+ if (isWideMode()) {
foldersY = getY(folders);
} else {
foldersY = getY(folders) + sendersTopAdjust;
@@ -502,7 +530,7 @@
attachmentPreviewsHeight = attachmentPreviews.getHeight();
// We only care about the right and bottom of the overflow count
- final TextView overflow = (TextView) view.findViewById(id.ap_overflow);
+ final TextView overflow = (TextView) view.findViewById(R.id.ap_overflow);
final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) overflow
.getLayoutParams();
overflowXEnd = attachmentPreviewsX + attachmentPreviewsWidth - params.rightMargin;
@@ -511,13 +539,13 @@
overflowFontSize = overflow.getTextSize();
overflowTypeface = overflow.getTypeface();
- final View placeholder = view.findViewById(id.ap_placeholder);
+ final View placeholder = view.findViewById(R.id.ap_placeholder);
placeholderWidth = placeholder.getWidth();
placeholderHeight = placeholder.getHeight();
placeholderY = attachmentPreviewsY + attachmentPreviewsHeight / 2
- placeholderHeight / 2;
- final View progressBar = view.findViewById(id.ap_progress_bar);
+ final View progressBar = view.findViewById(R.id.ap_progress_bar);
progressBarWidth = progressBar.getWidth();
progressBarHeight = progressBar.getHeight();
progressBarY = attachmentPreviewsY + attachmentPreviewsHeight / 2
@@ -540,15 +568,31 @@
progressBarHeight = 0;
}
- height = view.getHeight() + (isWide() ? 0 : sendersTopAdjust);
+ height = view.getHeight() + (isWideMode() ? 0 : sendersTopAdjust);
Utils.traceEndSection();
}
+ @SuppressLint("NewApi")
+ private static void setFramePadding(Context context, ViewGroup view, boolean useFullPadding) {
+ final Resources res = context.getResources();
+ final int padding = res.getDimensionPixelSize(useFullPadding ?
+ R.dimen.conv_list_card_border_padding : R.dimen.conv_list_no_border_padding);
+
+ final View frame = view.findViewById(R.id.conversation_item_frame);
+ if (Utils.isRunningJBMR1OrLater()) {
+ // start, top, end, bottom
+ frame.setPaddingRelative(frame.getPaddingStart(), padding,
+ frame.getPaddingEnd(), padding);
+ } else {
+ frame.setPadding(frame.getPaddingLeft(), padding, frame.getPaddingRight(), padding);
+ }
+ }
+
public int getMode() {
return mMode;
}
- public boolean isWide() {
+ public boolean isWideMode() {
return mMode == WIDE_MODE;
}
@@ -587,10 +631,11 @@
final Resources res = context.getResources();
switch (attachmentPreviewMode) {
case ATTACHMENT_PREVIEW_UNREAD:
- return (int) (isWide() ? res.getDimension(dimen.attachment_preview_height_tall_wide)
- : res.getDimension(dimen.attachment_preview_height_tall));
+ return (int) (isWideMode()
+ ? res.getDimension(R.dimen.attachment_preview_height_tall_wide)
+ : res.getDimension(R.dimen.attachment_preview_height_tall));
case ATTACHMENT_PREVIEW_READ:
- return (int) res.getDimension(dimen.attachment_preview_height_short);
+ return (int) res.getDimension(R.dimen.attachment_preview_height_short);
default:
return 0;
}
@@ -623,6 +668,7 @@
/**
* Returns the number of lines of this text view. Delegates to built-in TextView logic on JB+.
*/
+ @SuppressLint("NewApi")
private static int getLineCount(TextView textView) {
if (Utils.isRunningJellybeanOrLater()) {
return textView.getMaxLines();
@@ -705,9 +751,4 @@
public int getFolderMinimumWidth() {
return mFolderMinimumWidth;
}
-
- public static boolean isWideMode(int mode) {
- return mode == WIDE_MODE;
- }
-
}
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index 9ea145b..27216a5 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -67,13 +67,17 @@
// Date
CharSequence dateText;
- public CharSequence dateOverrideText;
+ public boolean showDateText = true;
// Personal level
Bitmap personalLevelBitmap;
public Bitmap infoIcon;
+ public String badgeText;
+
+ public int insetPadding = 0;
+
// Paperclip
Bitmap paperclip;
diff --git a/src/com/android/mail/browse/ConversationViewHeader.java b/src/com/android/mail/browse/ConversationViewHeader.java
index 2522990..c5fff83 100644
--- a/src/com/android/mail/browse/ConversationViewHeader.java
+++ b/src/com/android/mail/browse/ConversationViewHeader.java
@@ -17,6 +17,7 @@
package com.android.mail.browse;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.text.Spannable;
@@ -113,6 +114,7 @@
mFolderDisplayer = new ConversationFolderDisplayer(getContext(), mFoldersView, mIsRtl);
}
+ @SuppressLint("NewApi")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/src/com/android/mail/browse/FolderSpan.java b/src/com/android/mail/browse/FolderSpan.java
index 1bbd79b..12b9b05 100644
--- a/src/com/android/mail/browse/FolderSpan.java
+++ b/src/com/android/mail/browse/FolderSpan.java
@@ -136,8 +136,7 @@
left = x + paddingBefore;
right = x + bgWidth + paddingBefore;
}
- canvas.drawRect(left, top + paddingAbove, right, bottom,
- mWorkPaint);
+ canvas.drawRect(left, top + paddingAbove, right, bottom, mWorkPaint);
mWorkPaint.setColor(prevColor);
mWorkPaint.setStyle(prevStyle);
diff --git a/src/com/android/mail/providers/Conversation.java b/src/com/android/mail/providers/Conversation.java
index 24ed5b7..26d5506 100644
--- a/src/com/android/mail/providers/Conversation.java
+++ b/src/com/android/mail/providers/Conversation.java
@@ -176,6 +176,7 @@
private transient boolean viewed;
private static String sSubjectAndSnippet;
+ private static String sBadgeSubjectAndSnippet;
// Constituents of convFlags below
// Flag indicating that the item has been deleted, but will continue being
@@ -851,13 +852,9 @@
/**
* Get the properly formatted subject and snippet string for display a
* conversation.
- *
- * @param context
- * @param filteredSubject
- * @param snippet
*/
public static String getSubjectAndSnippetForDisplay(Context context,
- String filteredSubject, String snippet) {
+ String badgeText, String filteredSubject, String snippet) {
if (sSubjectAndSnippet == null) {
sSubjectAndSnippet = context.getString(R.string.subject_and_snippet);
}
@@ -867,6 +864,11 @@
return snippet;
} else if (TextUtils.isEmpty(snippet)) {
return filteredSubject;
+ } else if (!TextUtils.isEmpty(badgeText)) {
+ if (sBadgeSubjectAndSnippet == null) {
+ sBadgeSubjectAndSnippet = context.getString(R.string.badge_subject_and_snippet);
+ }
+ return String.format(sBadgeSubjectAndSnippet, badgeText, filteredSubject, snippet);
}
return String.format(sSubjectAndSnippet, filteredSubject, snippet);
diff --git a/src/com/android/mail/widget/WidgetConversationListItemViewBuilder.java b/src/com/android/mail/widget/WidgetConversationListItemViewBuilder.java
index 585eddf..ea8ec90 100644
--- a/src/com/android/mail/widget/WidgetConversationListItemViewBuilder.java
+++ b/src/com/android/mail/widget/WidgetConversationListItemViewBuilder.java
@@ -16,12 +16,6 @@
package com.android.mail.widget;
-import com.android.mail.R;
-import com.android.mail.providers.Conversation;
-import com.android.mail.providers.Folder;
-import com.android.mail.ui.FolderDisplayer;
-import com.android.mail.utils.FolderUri;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -35,6 +29,12 @@
import android.view.View;
import android.widget.RemoteViews;
+import com.android.mail.R;
+import com.android.mail.providers.Conversation;
+import com.android.mail.providers.Folder;
+import com.android.mail.ui.FolderDisplayer;
+import com.android.mail.utils.FolderUri;
+
public class WidgetConversationListItemViewBuilder {
// Static font sizes
private static int DATE_FONT_SIZE;
@@ -160,7 +160,8 @@
// Add style to subject
final int subjectColor = isUnread ? SUBJECT_TEXT_COLOR_UNREAD : SUBJECT_TEXT_COLOR_READ;
final SpannableStringBuilder subjectAndSnippet = new SpannableStringBuilder(
- Conversation.getSubjectAndSnippetForDisplay(mContext, filteredSubject, snippet));
+ Conversation.getSubjectAndSnippetForDisplay(
+ mContext, null /* badgeText */, filteredSubject, snippet));
if (isUnread) {
subjectAndSnippet.setSpan(new StyleSpan(Typeface.BOLD), 0, filteredSubject.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);