diff options
author | James Lemieux <jplemieux@google.com> | 2014-04-02 22:57:00 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-04-02 22:57:00 +0000 |
commit | 0653f9f2cf6424bbd274a2016b8d72d5431f2125 (patch) | |
tree | d4a0f8eb33da93e09830c685a3a8674fb86a3bc8 | |
parent | 487f79d103753a3eaa51f8c2bd8b6a219534fdf5 (diff) | |
parent | 10ea28ab588d8e922c0f78f0f47fe479739ec2cf (diff) | |
download | android_packages_apps_UnifiedEmail-0653f9f2cf6424bbd274a2016b8d72d5431f2125.tar.gz android_packages_apps_UnifiedEmail-0653f9f2cf6424bbd274a2016b8d72d5431f2125.tar.bz2 android_packages_apps_UnifiedEmail-0653f9f2cf6424bbd274a2016b8d72d5431f2125.zip |
am 10ea28ab: Show "To:<Names>" in sent and outbox index views
* commit '10ea28ab588d8e922c0f78f0f47fe479739ec2cf':
Show "To:<Names>" in sent and outbox index views
-rw-r--r-- | res/values/strings.xml | 8 | ||||
-rw-r--r-- | src/com/android/mail/browse/ConversationItemView.java | 50 | ||||
-rw-r--r-- | src/com/android/mail/browse/ConversationItemViewModel.java | 16 | ||||
-rw-r--r-- | src/com/android/mail/browse/MessageHeaderView.java | 2 | ||||
-rw-r--r-- | src/com/android/mail/browse/SendersView.java | 53 | ||||
-rw-r--r-- | src/com/android/mail/providers/Folder.java | 14 | ||||
-rw-r--r-- | src/com/android/mail/providers/UIProvider.java | 6 | ||||
-rw-r--r-- | src/com/android/mail/ui/FolderSelectionActivity.java | 4 | ||||
-rw-r--r-- | src/com/android/mail/utils/NotificationUtils.java | 3 | ||||
-rw-r--r-- | src/com/android/mail/widget/BaseWidgetProvider.java | 34 | ||||
-rw-r--r-- | src/com/android/mail/widget/WidgetService.java | 74 | ||||
-rw-r--r-- | tests/src/com/android/mail/browse/SendersFormattingTests.java | 8 |
12 files changed, 169 insertions, 103 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml index 54304cd14..838354c9d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -291,9 +291,9 @@ <item quantity="other">Move <xliff:g>%1$d</xliff:g> conversations</item> </plurals> <!-- Formatting string for the content description field of a conversation list item when device is in accessibility mode. [CHAR LIMIT=250] --> - <string name="content_description"><xliff:g id="sender">%1$s</xliff:g> about <xliff:g id="subject">%2$s</xliff:g>, <xliff:g id="snippet">%3$s</xliff:g> on <xliff:g id="date">%4$s</xliff:g>, <xliff:g id="readstate">%5$s</xliff:g></string> + <string name="content_description"><xliff:g id="toHeader">%1$s</xliff:g><xliff:g id="participant">%2$s</xliff:g> about <xliff:g id="subject">%3$s</xliff:g>, <xliff:g id="snippet">%4$s</xliff:g> on <xliff:g id="date">%5$s</xliff:g>, <xliff:g id="readstate">%6$s</xliff:g></string> <!-- Formatting string for the content description field of a conversation list item when device is in accessibility mode and the message was received today. [CHAR LIMI=250] --> - <string name="content_description_today"><xliff:g id="sender">%1$s</xliff:g> about <xliff:g id="subject">%2$s</xliff:g>, <xliff:g id="snippet">%3$s</xliff:g> at <xliff:g id="time">%4$s</xliff:g>, <xliff:g id="readstate">%5$s</xliff:g></string> + <string name="content_description_today"><xliff:g id="toHeader">%1$s</xliff:g><xliff:g id="participant">%2$s</xliff:g> about <xliff:g id="subject">%3$s</xliff:g>, <xliff:g id="snippet">%4$s</xliff:g> at <xliff:g id="time">%5$s</xliff:g>, <xliff:g id="readstate">%6$s</xliff:g></string> <!-- String used in content description field of a conversation list item when device is in accessibility mode and the conversation was read [CHAR LIMIT=250] --> <string name="read_string">conversation read</string> <!-- String used in content description field of a conversation list item when device is in accessibility mode and the conversation was not read [CHAR LIMIT=250] --> @@ -318,10 +318,10 @@ <string name="send_failed">Message wasn\'t sent.</string> <!-- String used to represent "me" when used as an object pronoun. This string is used when showing the list of recipients of a message [CHAR LIMIT=15] --> - <string name="me_object_pronun">me</string> + <string name="me_object_pronoun">me</string> <!-- String used to represent "me"/"I" when used as an subject pronoun. This string is use when showing the list of senders for a conversation list item. [CHAR LIMIT=15] --> - <string name="me_subject_pronun">me</string> + <string name="me_subject_pronoun">me</string> <!-- Header for list of inboxes in the drawer (Inbox, Priority) [CHAR LIMIT=50] --> <string name="inbox_folders_heading">Inbox</string> diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java index 8ab84b1e9..e0613fa7a 100644 --- a/src/com/android/mail/browse/ConversationItemView.java +++ b/src/com/android/mail/browse/ConversationItemView.java @@ -100,8 +100,8 @@ import com.android.mail.utils.ViewUtils; import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.List; import java.util.Iterator; +import java.util.List; public class ConversationItemView extends View implements SwipeableItemView, ToggleableItem, InvalidateCallback, OnScrollListener, @@ -795,7 +795,8 @@ public class ConversationItemView extends View private void setContentDescription() { if (mActivity.isAccessibilityEnabled()) { mHeader.resetContentDescription(); - setContentDescription(mHeader.getContentDescription(mContext)); + setContentDescription( + mHeader.getContentDescription(mContext, mDisplayedFolder.shouldShowRecipients())); } } @@ -849,7 +850,8 @@ public class ConversationItemView extends View SendersView.format(context, mHeader.conversation.conversationInfo, mHeader.messageInfoString.toString(), maxChars, mHeader.styledNames, - mHeader.displayableNames, mHeader.displayableEmails, mAccount, true); + mHeader.displayableNames, mHeader.displayableEmails, mAccount, + mDisplayedFolder.shouldShowRecipients(), true); if (mHeader.displayableEmails.isEmpty() && mHeader.hasDraftMessage) { mHeader.displayableEmails.add(mAccount); @@ -1035,13 +1037,13 @@ public class ConversationItemView extends View v.layout(0, 0, w, h); } - private void layoutParticipantLine(SpannableStringBuilder topLine) { - if (topLine != null) { + private void layoutParticipantText(SpannableStringBuilder participantText) { + if (participantText != null) { if (isActivated() && showActivatedText()) { - topLine.setSpan(sActivatedTextSpan, 0, + participantText.setSpan(sActivatedTextSpan, 0, mHeader.styledMessageInfoStringOffset, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else { - topLine.removeSpan(sActivatedTextSpan); + participantText.removeSpan(sActivatedTextSpan); } final int w = mSendersWidth; @@ -1051,7 +1053,7 @@ public class ConversationItemView extends View mSendersTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCoordinates.sendersFontSize); layoutViewExactly(mSendersTextView, w, h); - mSendersTextView.setText(topLine); + mSendersTextView.setText(participantText); } } @@ -1234,8 +1236,8 @@ public class ConversationItemView extends View sPaint.setTypeface(Typeface.DEFAULT); if (mHeader.styledNames != null) { - final SpannableStringBuilder topLine = ellipsize(mHeader.styledNames); - layoutParticipantLine(topLine); + final SpannableStringBuilder participantText = elideParticipants(mHeader.styledNames); + layoutParticipantText(participantText); } else { // First pass to calculate width of each fragment. if (mSendersWidth < 0) { @@ -1253,16 +1255,33 @@ public class ConversationItemView extends View pauseTimer(PERF_TAG_CALCULATE_COORDINATES); } - // The rules for displaying ellipsized senders are as follows: + // The rules for displaying elided participants are as follows: // 1) If there is message info (either a COUNT or DRAFT info to display), it MUST be shown // 2) If senders do not fit, ellipsize the last one that does fit, and stop // appending new senders - private SpannableStringBuilder ellipsize(List<SpannableString> parts) { - SpannableStringBuilder builder = new SpannableStringBuilder(); + SpannableStringBuilder elideParticipants(List<SpannableString> parts) { + final SpannableStringBuilder builder = new SpannableStringBuilder(); float totalWidth = 0; boolean ellipsize = false; float width; - SpannableStringBuilder messageInfoString = mHeader.messageInfoString; + boolean skipToHeader = false; + + // start with "To: " if we're showing recipients + if (mDisplayedFolder.shouldShowRecipients() && !parts.isEmpty()) { + final SpannableString toHeader = SendersView.getFormattedToHeader(); + CharacterStyle[] spans = toHeader.getSpans(0, toHeader.length(), + CharacterStyle.class); + // There is only 1 character style span; make sure we apply all the + // styles to the paint object before measuring. + if (spans.length > 0) { + spans[0].updateDrawState(sPaint); + } + totalWidth += sPaint.measureText(toHeader.toString()); + builder.append(toHeader); + skipToHeader = true; + } + + final SpannableStringBuilder messageInfoString = mHeader.messageInfoString; if (messageInfoString.length() > 0) { CharacterStyle[] spans = messageInfoString.getSpans(0, messageInfoString.length(), CharacterStyle.class); @@ -1296,13 +1315,14 @@ public class ConversationItemView extends View if (SendersView.sElidedString.equals(sender.toString())) { prevSender = sender; sender = copyStyles(spans, sElidedPaddingToken + sender + sElidedPaddingToken); - } else if (builder.length() > 0 + } else if (!skipToHeader && builder.length() > 0 && (prevSender == null || !SendersView.sElidedString.equals(prevSender .toString()))) { prevSender = sender; sender = copyStyles(spans, sSendersSplitToken + sender); } else { prevSender = sender; + skipToHeader = false; } if (spans.length > 0) { spans[0].updateDrawState(sPaint); diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java index a016519e5..eaea1e339 100644 --- a/src/com/android/mail/browse/ConversationItemViewModel.java +++ b/src/com/android/mail/browse/ConversationItemViewModel.java @@ -48,7 +48,6 @@ import java.util.List; public class ConversationItemViewModel { private static final int MAX_CACHE_SIZE = 100; - int fontColor; @VisibleForTesting static LruCache<Pair<String, Long>, ConversationItemViewModel> sConversationHeaderMap = new LruCache<Pair<String, Long>, ConversationItemViewModel>(MAX_CACHE_SIZE); @@ -286,7 +285,7 @@ public class ConversationItemViewModel { /** * Get conversation information to use for accessibility. */ - public CharSequence getContentDescription(Context context) { + public CharSequence getContentDescription(Context context, boolean showToHeader) { if (mContentDescription == null) { // If any are unread, get the first unread sender. // If all are unread, get the first sender. @@ -300,7 +299,7 @@ public class ConversationItemViewModel { } if (conversation.read) { participant = TextUtils.isEmpty(lastParticipant) ? - SendersView.getMe(context) : lastParticipant; + SendersView.getMe(showToHeader /* useObjectMe */) : lastParticipant; } else { ParticipantInfo firstUnread = null; for (ParticipantInfo p : conversation.conversationInfo.participantInfos) { @@ -311,20 +310,27 @@ public class ConversationItemViewModel { } if (firstUnread != null) { participant = TextUtils.isEmpty(firstUnread.name) ? - SendersView.getMe(context) : firstUnread.name; + SendersView.getMe(showToHeader /* useObjectMe */) : firstUnread.name; } } if (TextUtils.isEmpty(participant)) { // Just take the last sender participant = lastParticipant; } + + // the toHeader should read "To: " if requested + String toHeader = ""; + if (showToHeader && !TextUtils.isEmpty(participant)) { + toHeader = SendersView.getFormattedToHeader().toString(); + } + boolean isToday = DateUtils.isToday(conversation.dateMs); String date = DateUtils.getRelativeTimeSpanString(context, conversation.dateMs) .toString(); String readString = context.getString( conversation.read ? R.string.read_string : R.string.unread_string); int res = isToday ? R.string.content_description_today : R.string.content_description; - mContentDescription = context.getString(res, participant, + mContentDescription = context.getString(res, toHeader, participant, conversation.subject, conversation.getSnippet(), date, readString); } return mContentDescription; diff --git a/src/com/android/mail/browse/MessageHeaderView.java b/src/com/android/mail/browse/MessageHeaderView.java index 07ec19310..7881f07f8 100644 --- a/src/com/android/mail/browse/MessageHeaderView.java +++ b/src/com/android/mail/browse/MessageHeaderView.java @@ -246,7 +246,7 @@ public class MessageHeaderView extends SnapHeader implements OnClickListener, mIsSnappy = false; mEmailCopyMenu = new EmailCopyContextMenu(getContext()); mInflater = LayoutInflater.from(context); - mMyName = context.getString(R.string.me_object_pronun); + mMyName = context.getString(R.string.me_object_pronoun); final Resources resources = getResources(); mContactPhotoWidth = resources.getDimensionPixelSize( diff --git a/src/com/android/mail/browse/SendersView.java b/src/com/android/mail/browse/SendersView.java index 608b4f3db..2d7657ecb 100644 --- a/src/com/android/mail/browse/SendersView.java +++ b/src/com/android/mail/browse/SendersView.java @@ -31,7 +31,6 @@ import android.text.TextUtils; import android.text.style.CharacterStyle; import android.text.style.TextAppearanceSpan; -import com.android.emailcommon.mail.Address; import com.android.mail.R; import com.android.mail.providers.Conversation; import com.android.mail.providers.ConversationInfo; @@ -43,20 +42,14 @@ import com.google.common.base.Objects; import com.google.common.collect.Maps; import java.util.ArrayList; -import java.util.Locale; import java.util.Map; -import java.util.regex.Pattern; public class SendersView { - public static final int DEFAULT_FORMATTING = 0; - public static final int MERGED_FORMATTING = 1; private static final Integer DOES_NOT_EXIST = -5; // FIXME(ath): make all of these statics instance variables, and have callers hold onto this // instance as long as appropriate (e.g. activity lifetime). // no need to listen for configuration changes. private static String sSendersSplitToken; - public static String SENDERS_VERSION_SEPARATOR = "^**^"; - public static Pattern SENDERS_VERSION_SEPARATOR_PATTERN = Pattern.compile("\\^\\*\\*\\^"); private static CharSequence sDraftSingularString; private static CharSequence sDraftPluralString; private static CharSequence sSendingString; @@ -65,8 +58,9 @@ public class SendersView { private static CharacterStyle sSendingStyleSpan; private static TextAppearanceSpan sUnreadStyleSpan; private static CharacterStyle sReadStyleSpan; - private static String sMeString; - private static Locale sMeStringLocale; + private static String sMeSubjectString; + private static String sMeObjectString; + private static String sToHeaderString; private static String sMessageCountSpacerString; public static CharSequence sElidedString; private static BroadcastReceiver sConfigurationChangedReceiver; @@ -117,6 +111,9 @@ public class SendersView { sDraftSingularString = res.getQuantityText(R.plurals.draft, 1); sDraftPluralString = res.getQuantityText(R.plurals.draft, 2); sDraftCountFormatString = res.getString(R.string.draft_count_format); + sMeSubjectString = res.getString(R.string.me_subject_pronoun); + sMeObjectString = res.getString(R.string.me_object_pronoun); + sToHeaderString = res.getString(R.string.to_heading); sMessageInfoUnreadStyleSpan = new TextAppearanceSpan(context, R.style.MessageInfoUnreadTextAppearance); sMessageInfoReadStyleSpan = new TextAppearanceSpan(context, @@ -202,12 +199,12 @@ public class SendersView { public static void format(Context context, ConversationInfo conversationInfo, String messageInfo, int maxChars, ArrayList<SpannableString> styledSenders, ArrayList<String> displayableSenderNames, ArrayList<String> displayableSenderEmails, - String account, final boolean resourceCachingRequired) { + String account, final boolean showToHeader, final boolean resourceCachingRequired) { try { getSenderResources(context, resourceCachingRequired); format(context, conversationInfo, messageInfo, maxChars, styledSenders, displayableSenderNames, displayableSenderEmails, account, - sUnreadStyleSpan, sReadStyleSpan, resourceCachingRequired); + sUnreadStyleSpan, sReadStyleSpan, showToHeader, resourceCachingRequired); } finally { if (!resourceCachingRequired) { clearResourceCache(); @@ -219,12 +216,13 @@ public class SendersView { String messageInfo, int maxChars, ArrayList<SpannableString> styledSenders, ArrayList<String> displayableSenderNames, ArrayList<String> displayableSenderEmails, String account, final TextAppearanceSpan notificationUnreadStyleSpan, - final CharacterStyle notificationReadStyleSpan, final boolean resourceCachingRequired) { + final CharacterStyle notificationReadStyleSpan, final boolean showToHeader, + final boolean resourceCachingRequired) { try { getSenderResources(context, resourceCachingRequired); - handlePriority(context, maxChars, messageInfo, conversationInfo, styledSenders, + handlePriority(maxChars, messageInfo, conversationInfo, styledSenders, displayableSenderNames, displayableSenderEmails, account, - notificationUnreadStyleSpan, notificationReadStyleSpan); + notificationUnreadStyleSpan, notificationReadStyleSpan, showToHeader); } finally { if (!resourceCachingRequired) { clearResourceCache(); @@ -232,11 +230,11 @@ public class SendersView { } } - public static void handlePriority(Context context, int maxChars, String messageInfoString, + private static void handlePriority(int maxChars, String messageInfoString, ConversationInfo conversationInfo, ArrayList<SpannableString> styledSenders, ArrayList<String> displayableSenderNames, ArrayList<String> displayableSenderEmails, String account, final TextAppearanceSpan unreadStyleSpan, - final CharacterStyle readStyleSpan) { + final CharacterStyle readStyleSpan, final boolean showToHeader) { boolean shouldAddPhotos = displayableSenderEmails != null; int maxPriorityToInclude = -1; // inclusive int numCharsUsed = messageInfoString.length(); // draft, number drafts, @@ -294,7 +292,8 @@ public class SendersView { final String currentName = currentParticipant.name; String nameString = !TextUtils.isEmpty(currentName) ? currentName : ""; if (nameString.length() == 0) { - nameString = getMe(context); + // if we're showing the To: header, show the object version of me. + nameString = getMe(showToHeader /* useObjectMe */); } if (numCharsToRemovePerWord != 0) { nameString = nameString.substring(0, @@ -302,7 +301,7 @@ public class SendersView { } final int priority = currentParticipant.priority; - style = getWrappedStyleSpan(currentParticipant.readConversation ? readStyleSpan : + style = CharacterStyle.wrap(currentParticipant.readConversation ? readStyleSpan : unreadStyleSpan); if (priority <= maxPriorityToInclude) { spannableDisplay = new SpannableString(sBidiFormatter.unicodeWrap(nameString)); @@ -372,19 +371,15 @@ public class SendersView { } } - private static CharacterStyle getWrappedStyleSpan(final CharacterStyle characterStyle) { - return CharacterStyle.wrap(characterStyle); + static String getMe(boolean useObjectMe) { + return useObjectMe ? sMeObjectString : sMeSubjectString; } - static String getMe(Context context) { - final Resources resources = context.getResources(); - final Locale locale = resources.getConfiguration().locale; - - if (sMeString == null || !locale.equals(sMeStringLocale)) { - sMeString = resources.getString(R.string.me_subject_pronun); - sMeStringLocale = locale; - } - return sMeString; + public static SpannableString getFormattedToHeader() { + final SpannableString formattedToHeader = new SpannableString(sToHeaderString); + final CharacterStyle readStyle = CharacterStyle.wrap(sReadStyleSpan); + formattedToHeader.setSpan(readStyle, 0, formattedToHeader.length(), 0); + return formattedToHeader; } private static void clearResourceCache() { diff --git a/src/com/android/mail/providers/Folder.java b/src/com/android/mail/providers/Folder.java index 6d620d6de..57cfa451f 100644 --- a/src/com/android/mail/providers/Folder.java +++ b/src/com/android/mail/providers/Folder.java @@ -760,6 +760,20 @@ public class Folder implements Parcelable, Comparable<Folder> { } /** + * Return true if this folder prefers to display recipients over senders. + */ + public boolean shouldShowRecipients() { + return supportsCapability(UIProvider.FolderCapabilities.SHOW_RECIPIENTS); + } + + /** + * Return true if this folder prefers to display recipients over senders. + */ + public static boolean shouldShowRecipients(final int folderCapabilities) { + return (folderCapabilities & UIProvider.FolderCapabilities.SHOW_RECIPIENTS) != 0; + } + + /** * @return a non-user facing English string describing this folder's type */ public String getTypeDescription() { diff --git a/src/com/android/mail/providers/UIProvider.java b/src/com/android/mail/providers/UIProvider.java index d37a083e1..9bcacccbd 100644 --- a/src/com/android/mail/providers/UIProvider.java +++ b/src/com/android/mail/providers/UIProvider.java @@ -857,6 +857,12 @@ public class UIProvider { * inbox. */ public static final int ALLOWS_MOVE_TO_INBOX = 0x10000; + + /** + * For folders that typically represent outgoing mail, this indicates the client should + * display recipients rather than the standard list of senders. + */ + public static final int SHOW_RECIPIENTS = 0x20000; } public static final class FolderColumns implements BaseColumns { diff --git a/src/com/android/mail/ui/FolderSelectionActivity.java b/src/com/android/mail/ui/FolderSelectionActivity.java index 06bf6ab71..76e2af356 100644 --- a/src/com/android/mail/ui/FolderSelectionActivity.java +++ b/src/com/android/mail/ui/FolderSelectionActivity.java @@ -247,8 +247,8 @@ public class FolderSelectionActivity extends Activity implements OnClickListener */ protected void createWidget(int id, Account account, Folder selectedFolder) { WidgetProvider.updateWidget(this, id, account, selectedFolder.type, - selectedFolder.folderUri.fullUri, selectedFolder.conversationListUri, - selectedFolder.name); + selectedFolder.capabilities, selectedFolder.folderUri.fullUri, + selectedFolder.conversationListUri, selectedFolder.name); final Intent result = new Intent(); result.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id); setResult(RESULT_OK, result); diff --git a/src/com/android/mail/utils/NotificationUtils.java b/src/com/android/mail/utils/NotificationUtils.java index 09879b0e5..8f9498c4c 100644 --- a/src/com/android/mail/utils/NotificationUtils.java +++ b/src/com/android/mail/utils/NotificationUtils.java @@ -1171,7 +1171,8 @@ public class NotificationUtils { new TextAppearanceSpan(context, R.style.NotificationSendersReadTextAppearance); } SendersView.format(context, conversationInfo, "", maxLength, senders, null, null, account, - sNotificationUnreadStyleSpan, sNotificationReadStyleSpan, false); + sNotificationUnreadStyleSpan, sNotificationReadStyleSpan, + false /* showToHeader */, false /* resourceCachingRequired */); return ellipsizeStyledSenders(context, senders); } diff --git a/src/com/android/mail/widget/BaseWidgetProvider.java b/src/com/android/mail/widget/BaseWidgetProvider.java index d53256703..6b969d2ba 100644 --- a/src/com/android/mail/widget/BaseWidgetProvider.java +++ b/src/com/android/mail/widget/BaseWidgetProvider.java @@ -49,6 +49,7 @@ import java.util.Set; public abstract class BaseWidgetProvider extends AppWidgetProvider { public static final String EXTRA_FOLDER_TYPE = "folder-type"; + public static final String EXTRA_FOLDER_CAPABILITIES = "folder-capabilities"; public static final String EXTRA_FOLDER_URI = "folder-uri"; public static final String EXTRA_FOLDER_CONVERSATION_LIST_URI = "folder-conversation-list-uri"; public static final String EXTRA_FOLDER_DISPLAY_NAME = "folder-display-name"; @@ -129,14 +130,15 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { final int widgetId = intent.getIntExtra(EXTRA_WIDGET_ID, -1); final Account account = Account.newInstance(intent.getStringExtra(Utils.EXTRA_ACCOUNT)); final int folderType = intent.getIntExtra(EXTRA_FOLDER_TYPE, FolderType.DEFAULT); + final int folderCapabilities = intent.getIntExtra(EXTRA_FOLDER_CAPABILITIES, 0); final Uri folderUri = intent.getParcelableExtra(EXTRA_FOLDER_URI); final Uri folderConversationListUri = intent.getParcelableExtra(EXTRA_FOLDER_CONVERSATION_LIST_URI); final String folderDisplayName = intent.getStringExtra(EXTRA_FOLDER_DISPLAY_NAME); if (widgetId != -1 && account != null && folderUri != null) { - updateWidgetInternal(context, widgetId, account, folderType, folderUri, - folderConversationListUri, folderDisplayName); + updateWidgetInternal(context, widgetId, account, folderType, folderCapabilities, + folderUri, folderConversationListUri, folderDisplayName); } } else if (ACTION_VALIDATE_ALL_WIDGETS.equals(action)) { validateAllWidgetInformation(context); @@ -253,9 +255,11 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { } updateWidgetInternal(mContext, mAppWidgetIds[i], account, - folder == null ? FolderType.DEFAULT : folder.type, folderUri, - folder == null ? null : folder.conversationListUri, folder == null ? null - : folder.name); + folder == null ? FolderType.DEFAULT : folder.type, + folder == null ? 0 : folder.capabilities, + folderUri, + folder == null ? null : folder.conversationListUri, + folder == null ? null : folder.name); } return null; @@ -287,8 +291,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { * Update the widget appWidgetId with the given account and folder */ public static void updateWidget(Context context, int appWidgetId, Account account, - final int folderType, final Uri folderUri, final Uri folderConversationListUri, - final String folderDisplayName) { + final int folderType, final int folderCapabilities, final Uri folderUri, + final Uri folderConversationListUri, final String folderDisplayName) { if (account == null || folderUri == null) { LogUtils.e(LOG_TAG, "Missing account or folder. account: %s folder %s", account, folderUri); @@ -300,6 +304,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { updateWidgetIntent.putExtra(EXTRA_WIDGET_ID, appWidgetId); updateWidgetIntent.putExtra(Utils.EXTRA_ACCOUNT, account.serialize()); updateWidgetIntent.putExtra(EXTRA_FOLDER_TYPE, folderType); + updateWidgetIntent.putExtra(EXTRA_FOLDER_CAPABILITIES, folderCapabilities); updateWidgetIntent.putExtra(EXTRA_FOLDER_URI, folderUri); updateWidgetIntent.putExtra(EXTRA_FOLDER_CONVERSATION_LIST_URI, folderConversationListUri); updateWidgetIntent.putExtra(EXTRA_FOLDER_DISPLAY_NAME, folderDisplayName); @@ -314,8 +319,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { } protected void updateWidgetInternal(Context context, int appWidgetId, Account account, - final int folderType, final Uri folderUri, final Uri folderConversationListUri, - final String folderDisplayName) { + final int folderType, final int folderCapabilities, final Uri folderUri, + final Uri folderConversationListUri, final String folderDisplayName) { final RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget); if (!isAccountValid(context, account) || !isFolderValid(context, folderUri)) { @@ -342,7 +347,7 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { } else { // Set folder to a space here to avoid flicker. configureValidAccountWidget(context, remoteViews, appWidgetId, account, folderType, - folderUri, folderConversationListUri, + folderCapabilities, folderUri, folderConversationListUri, folderDisplayName == null ? " " : folderDisplayName); } @@ -379,10 +384,10 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { } protected void configureValidAccountWidget(Context context, RemoteViews remoteViews, - int appWidgetId, Account account, final int folderType, final Uri folderUri, - final Uri folderConversationListUri, String folderDisplayName) { + int appWidgetId, Account account, final int folderType, final int folderCapabilities, + final Uri folderUri, final Uri folderConversationListUri, String folderDisplayName) { WidgetService.configureValidAccountWidget(context, remoteViews, appWidgetId, account, - folderType, folderUri, folderConversationListUri, folderDisplayName, + folderType, folderCapabilities, folderUri, folderConversationListUri, folderDisplayName, WidgetService.class); } @@ -426,7 +431,8 @@ public abstract class BaseWidgetProvider extends AppWidgetProvider { // unconfigure the widget if it is not valid if (!isAccountValid(context, account) || !isFolderValid(context, folderUri)) { - updateWidgetInternal(context, widgetId, null, FolderType.DEFAULT, null, null, null); + updateWidgetInternal(context, widgetId, null, FolderType.DEFAULT, 0, null, null, + null); } } } diff --git a/src/com/android/mail/widget/WidgetService.java b/src/com/android/mail/widget/WidgetService.java index fab5efaa6..f0624ad28 100644 --- a/src/com/android/mail/widget/WidgetService.java +++ b/src/com/android/mail/widget/WidgetService.java @@ -32,7 +32,6 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.format.DateUtils; import android.text.style.CharacterStyle; -import android.text.style.TextAppearanceSpan; import android.view.View; import android.widget.RemoteViews; import android.widget.RemoteViewsService; @@ -48,13 +47,14 @@ import com.android.mail.providers.UIProvider; import com.android.mail.providers.UIProvider.ConversationListQueryParameters; import com.android.mail.providers.UIProvider.FolderType; import com.android.mail.utils.AccountUtils; -import com.android.mail.utils.FolderUri; import com.android.mail.utils.DelayedTaskHandler; +import com.android.mail.utils.FolderUri; import com.android.mail.utils.LogTag; import com.android.mail.utils.LogUtils; import com.android.mail.utils.Utils; import java.util.ArrayList; +import java.util.List; public class WidgetService extends RemoteViewsService { /** @@ -70,18 +70,20 @@ public class WidgetService extends RemoteViewsService { } protected void configureValidAccountWidget(Context context, RemoteViews remoteViews, - int appWidgetId, Account account, final int folderType, final Uri folderUri, - final Uri folderConversationListUri, String folderName) { + int appWidgetId, Account account, final int folderType, final int folderCapabilities, + final Uri folderUri, final Uri folderConversationListUri, String folderName) { configureValidAccountWidget(context, remoteViews, appWidgetId, account, folderType, - folderUri, folderConversationListUri, folderName, WidgetService.class); + folderCapabilities, folderUri, folderConversationListUri, folderName, + WidgetService.class); } /** * Modifies the remoteView for the given account and folder. */ public static void configureValidAccountWidget(Context context, RemoteViews remoteViews, - int appWidgetId, Account account, final int folderType, final Uri folderUri, - final Uri folderConversationListUri, String folderDisplayName, Class<?> widgetService) { + int appWidgetId, Account account, final int folderType, final int folderCapabilities, + final Uri folderUri, final Uri folderConversationListUri, String folderDisplayName, + Class<?> widgetService) { remoteViews.setViewVisibility(R.id.widget_folder, View.VISIBLE); // If the folder or account name are empty, we don't want to overwrite the valid data that @@ -111,13 +113,14 @@ public class WidgetService extends RemoteViewsService { remoteViews.setEmptyView(R.id.conversation_list, R.id.empty_conversation_list); WidgetService.configureValidWidgetIntents(context, remoteViews, appWidgetId, account, - folderType, folderUri, folderConversationListUri, folderDisplayName, widgetService); + folderType, folderCapabilities, folderUri, folderConversationListUri, + folderDisplayName, widgetService); } public static void configureValidWidgetIntents(Context context, RemoteViews remoteViews, - int appWidgetId, Account account, final int folderType, final Uri folderUri, - final Uri folderConversationListUri, final String folderDisplayName, - Class<?> serviceClass) { + int appWidgetId, Account account, final int folderType, final int folderCapabilities, + final Uri folderUri, final Uri folderConversationListUri, + final String folderDisplayName, Class<?> serviceClass) { remoteViews.setViewVisibility(R.id.widget_configuration, View.GONE); @@ -126,6 +129,7 @@ public class WidgetService extends RemoteViewsService { intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); intent.putExtra(Utils.EXTRA_ACCOUNT, account.serialize()); intent.putExtra(BaseWidgetProvider.EXTRA_FOLDER_TYPE, folderType); + intent.putExtra(BaseWidgetProvider.EXTRA_FOLDER_CAPABILITIES, folderCapabilities); intent.putExtra(BaseWidgetProvider.EXTRA_FOLDER_URI, folderUri); intent.putExtra(BaseWidgetProvider.EXTRA_FOLDER_CONVERSATION_LIST_URI, folderConversationListUri); @@ -208,6 +212,7 @@ public class WidgetService extends RemoteViewsService { private final int mAppWidgetId; private final Account mAccount; private final int mFolderType; + private final int mFolderCapabilities; private final Uri mFolderUri; private final Uri mFolderConversationListUri; private final String mFolderDisplayName; @@ -223,8 +228,6 @@ public class WidgetService extends RemoteViewsService { private final WidgetService mService; private String mSendersSplitToken; private String mElidedPaddingToken; - private TextAppearanceSpan mUnreadStyle; - private TextAppearanceSpan mReadStyle; public MailFactory(Context context, Intent intent, WidgetService service) { mContext = context; @@ -232,6 +235,7 @@ public class WidgetService extends RemoteViewsService { AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); mAccount = Account.newInstance(intent.getStringExtra(Utils.EXTRA_ACCOUNT)); mFolderType = intent.getIntExtra(WidgetProvider.EXTRA_FOLDER_TYPE, FolderType.DEFAULT); + mFolderCapabilities = intent.getIntExtra(WidgetProvider.EXTRA_FOLDER_CAPABILITIES, 0); mFolderDisplayName = intent.getStringExtra(WidgetProvider.EXTRA_FOLDER_DISPLAY_NAME); final Uri folderUri = intent.getParcelableExtra(WidgetProvider.EXTRA_FOLDER_URI); @@ -253,7 +257,8 @@ public class WidgetService extends RemoteViewsService { mFolderConversationListUri = Uri.EMPTY; // this will mark the widget as unconfigured BaseWidgetProvider.updateWidget(mContext, mAppWidgetId, mAccount, mFolderType, - mFolderUri, mFolderConversationListUri, mFolderDisplayName); + mFolderCapabilities, mFolderUri, mFolderConversationListUri, + mFolderDisplayName); } } @@ -271,7 +276,8 @@ public class WidgetService extends RemoteViewsService { // "Tap to configure" mode. if (!mService.isWidgetConfigured(mContext, mAppWidgetId, mAccount)) { BaseWidgetProvider.updateWidget(mContext, mAppWidgetId, mAccount, mFolderType, - mFolderUri, mFolderConversationListUri, mFolderDisplayName); + mFolderCapabilities, mFolderUri, mFolderConversationListUri, + mFolderDisplayName); } mFolderInformationShown = false; @@ -405,12 +411,12 @@ public class WidgetService extends RemoteViewsService { Conversation conversation = new Conversation(mConversationCursor); // Split the senders and status from the instructions. - SpannableStringBuilder senderBuilder = new SpannableStringBuilder(); ArrayList<SpannableString> senders = new ArrayList<SpannableString>(); SendersView.format(mContext, conversation.conversationInfo, "", - MAX_SENDERS_LENGTH, senders, null, null, mAccount.getEmailAddress(), true); - senderBuilder = ellipsizeStyledSenders(senders); + MAX_SENDERS_LENGTH, senders, null, null, mAccount.getEmailAddress(), + Folder.shouldShowRecipients(mFolderCapabilities), true); + final SpannableStringBuilder senderBuilder = elideParticipants(senders); // Get styled date. CharSequence date = DateUtils.getRelativeTimeSpanString(mContext, @@ -437,11 +443,19 @@ public class WidgetService extends RemoteViewsService { } } - private SpannableStringBuilder ellipsizeStyledSenders( - ArrayList<SpannableString> styledSenders) { - SpannableStringBuilder builder = new SpannableStringBuilder(); + private SpannableStringBuilder elideParticipants(List<SpannableString> parts) { + final SpannableStringBuilder builder = new SpannableStringBuilder(); SpannableString prevSender = null; - for (SpannableString sender : styledSenders) { + + boolean skipToHeader = false; + + // start with "To: " if we're showing recipients + if (Folder.shouldShowRecipients(mFolderCapabilities)) { + builder.append(SendersView.getFormattedToHeader()); + skipToHeader = true; + } + + for (SpannableString sender : parts) { if (sender == null) { LogUtils.e(LOG_TAG, "null sender while iterating over styledSenders"); continue; @@ -450,13 +464,14 @@ public class WidgetService extends RemoteViewsService { if (SendersView.sElidedString.equals(sender.toString())) { prevSender = sender; sender = copyStyles(spans, mElidedPaddingToken + sender + mElidedPaddingToken); - } else if (builder.length() > 0 + } else if (!skipToHeader && builder.length() > 0 && (prevSender == null || !SendersView.sElidedString.equals(prevSender .toString()))) { prevSender = sender; sender = copyStyles(spans, mSendersSplitToken + sender); } else { prevSender = sender; + skipToHeader = false; } builder.append(sender); } @@ -514,14 +529,16 @@ public class WidgetService extends RemoteViewsService { if (!mService.isWidgetConfigured(mContext, mAppWidgetId, mAccount)) { BaseWidgetProvider.updateWidget(mContext, mAppWidgetId, mAccount, mFolderType, - mFolderUri, mFolderConversationListUri, mFolderDisplayName); + mFolderCapabilities, mFolderUri, mFolderConversationListUri, + mFolderDisplayName); } if (loader == mFolderLoader) { if (!isDataValid(data)) { // Our folder may have disappeared on us BaseWidgetProvider.updateWidget(mContext, mAppWidgetId, mAccount, mFolderType, - mFolderUri, mFolderConversationListUri, mFolderDisplayName); + mFolderCapabilities, mFolderUri, mFolderConversationListUri, + mFolderDisplayName); return; } @@ -537,8 +554,8 @@ public class WidgetService extends RemoteViewsService { // widget update. This causes the folder name to be shown as blank if the state // of the widget is restored. mService.configureValidAccountWidget(mContext, remoteViews, mAppWidgetId, - mAccount, mFolderType, mFolderUri, mFolderConversationListUri, - folderName); + mAccount, mFolderType, mFolderCapabilities, mFolderUri, + mFolderConversationListUri, folderName); appWidgetManager.updateAppWidget(mAppWidgetId, remoteViews); mFolderInformationShown = true; } @@ -591,7 +608,8 @@ public class WidgetService extends RemoteViewsService { } } else if (loader == mAccountLoader) { BaseWidgetProvider.updateWidget(mContext, mAppWidgetId, mAccount, mFolderType, - mFolderUri, mFolderConversationListUri, mFolderDisplayName); + mFolderCapabilities, mFolderUri, mFolderConversationListUri, + mFolderDisplayName); } } diff --git a/tests/src/com/android/mail/browse/SendersFormattingTests.java b/tests/src/com/android/mail/browse/SendersFormattingTests.java index 4a072c3fa..ecec4dfac 100644 --- a/tests/src/com/android/mail/browse/SendersFormattingTests.java +++ b/tests/src/com/android/mail/browse/SendersFormattingTests.java @@ -40,7 +40,7 @@ public class SendersFormattingTests extends AndroidTestCase { final ArrayList<SpannableString> strings = Lists.newArrayList(); assertEquals(0, strings.size()); - SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false); + SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false, false); assertEquals(1, strings.size()); assertEquals("me", strings.get(0).toString()); } @@ -51,7 +51,7 @@ public class SendersFormattingTests extends AndroidTestCase { final ArrayList<SpannableString> strings = Lists.newArrayList(); assertEquals(0, strings.size()); - SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false); + SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false, false); assertEquals(1, strings.size()); assertEquals("me", strings.get(0).toString()); } @@ -63,7 +63,7 @@ public class SendersFormattingTests extends AndroidTestCase { final ArrayList<SpannableString> strings = Lists.newArrayList(); assertEquals(0, strings.size()); - SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false); + SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false, false); assertEquals(2, strings.size()); assertNull(strings.get(0)); assertEquals("me", strings.get(1).toString()); @@ -77,7 +77,7 @@ public class SendersFormattingTests extends AndroidTestCase { final ArrayList<SpannableString> strings = Lists.newArrayList(); assertEquals(0, strings.size()); - SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false); + SendersView.format(getContext(), conv, "", 100, strings, null, null, null, false, false); assertEquals(2, strings.size()); assertNull(strings.get(0)); assertEquals("Something", strings.get(1).toString()); |