Provide formatting versions for senders.

That way, Gmail can use its formatting, email can use CSV (default)
and we can add another version when necessary.

Change-Id: I088e99376d1fba7cebb2d6a8d260dd8a80c6cbdc
diff --git a/res/layout/conversation_item_view_wide.xml b/res/layout/conversation_item_view_wide.xml
index 9d6ccdb..8e46a7b 100644
--- a/res/layout/conversation_item_view_wide.xml
+++ b/res/layout/conversation_item_view_wide.xml
@@ -43,7 +43,7 @@
         android:textSize="@dimen/wide_senders_font_size"
         android:layout_gravity="center_vertical"
         android:maxLines="2"
-        android:layout_marginTop="@dimen/wide_senders_margin_top"  />
+        android:layout_marginTop="@dimen/wide_senders_margin_top" />
     <TextView
         android:id="@+id/subject"
         android:layout_width="0dip"
diff --git a/src/com/android/mail/browse/ConversationItemView.java b/src/com/android/mail/browse/ConversationItemView.java
index 91cd325..4f2ebf2 100644
--- a/src/com/android/mail/browse/ConversationItemView.java
+++ b/src/com/android/mail/browse/ConversationItemView.java
@@ -549,7 +549,7 @@
         createSubjectSpans(isUnread);
 
         // Parse senders fragments.
-        mCoordinates.sendersView.parseSendersFragments(mHeader, isUnread, mMode);
+        mCoordinates.sendersView.formatSenders(mHeader, isUnread, mMode);
 
         pauseTimer(PERF_TAG_CALCULATE_SENDER_SUBJECT);
         pauseTimer(PERF_TAG_CALCULATE_TEXTS_BITMAPS);
diff --git a/src/com/android/mail/browse/SendersView.java b/src/com/android/mail/browse/SendersView.java
index b99747e..15712f5 100644
--- a/src/com/android/mail/browse/SendersView.java
+++ b/src/com/android/mail/browse/SendersView.java
@@ -18,20 +18,35 @@
 package com.android.mail.browse;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Typeface;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
 import android.text.style.StyleSpan;
 import android.text.util.Rfc822Token;
 import android.text.util.Rfc822Tokenizer;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
+import com.android.mail.R;
 import com.android.mail.providers.Address;
 import com.android.mail.providers.Conversation;
+import com.android.mail.utils.Utils;
+
+import java.util.regex.Pattern;
 
 public class SendersView extends TextView {
+    public static final int DEFAULT_FORMATTING = 0;
+    public static final int MERGED_FORMATTING = 1;
+    public static String SENDERS_VERSION_SEPARATOR = "^**^";
     CharacterStyle sNormalTextStyle = new StyleSpan(Typeface.NORMAL);
+    private Pattern SENDERS_VERSION_SEPARATOR_PATTERN = Pattern.compile("\\^\\*\\*\\^");
+    private int mFormatVersion = -1;
+    private ForegroundColorSpan sLightTextStyle;
+    private int DRAFT_TEXT_COLOR;
+    private int LIGHT_TEXT_COLOR;
 
     public SendersView(Context context) {
         this(context, null);
@@ -43,26 +58,45 @@
 
     public SendersView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
+        Resources res = context.getResources();
+        LIGHT_TEXT_COLOR = res.getColor(R.color.light_text_color);
+        DRAFT_TEXT_COLOR = res.getColor(R.color.drafts);
+        sLightTextStyle = new ForegroundColorSpan(LIGHT_TEXT_COLOR);
     }
 
     public Typeface getTypeface(boolean isUnread) {
-        return isUnread ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT;
+        return mFormatVersion == DEFAULT_FORMATTING ? isUnread ? Typeface.DEFAULT_BOLD
+                : Typeface.DEFAULT : Typeface.DEFAULT;
     }
 
-    /**
-     * Parses senders text into small fragments.
-     */
-    public void parseSendersFragments(ConversationItemViewModel header, boolean isUnread,
-            int mode) {
+    public void formatSenders(ConversationItemViewModel header, boolean isUnread, int mode) {
         if (TextUtils.isEmpty(header.conversation.senders)) {
             return;
         }
-        header.sendersText = formatSenders(header.conversation);
-        header.addSenderFragment(0, header.sendersText.length(), sNormalTextStyle, true);
+        Conversation conversation = header.conversation;
+        String sendersString = "";
+        String[] splits = TextUtils.split(conversation.senders, SENDERS_VERSION_SEPARATOR_PATTERN);
+        if (splits == null || splits.length < 2) {
+            mFormatVersion = DEFAULT_FORMATTING;
+            sendersString = header.conversation.senders;
+        } else {
+            mFormatVersion = Integer.parseInt(splits[0]);
+            // Format the rest of the senders string once the format version is
+            // stripped.
+            sendersString = splits[1];
+        }
+        switch (mFormatVersion) {
+            case MERGED_FORMATTING:
+                formatMerged(header, sendersString, isUnread, mode);
+                break;
+            case DEFAULT_FORMATTING:
+            default:
+                formatDefault(header, sendersString);
+                break;
+        }
     }
 
-    public String formatSenders(Conversation conversation) {
-        String sendersString = conversation.senders;
+    private void formatDefault(ConversationItemViewModel header, String sendersString) {
         String[] senders = TextUtils.split(sendersString, Address.ADDRESS_DELIMETER);
         String[] namesOnly = new String[senders.length];
         Rfc822Token[] senderTokens;
@@ -77,6 +111,72 @@
                 namesOnly[i] = display;
             }
         }
-        return TextUtils.join(Address.ADDRESS_DELIMETER + " ", namesOnly);
+        header.sendersText = TextUtils.join(Address.ADDRESS_DELIMETER + " ", namesOnly);
+        header.addSenderFragment(0, header.sendersText.length(), sNormalTextStyle, true);
+    }
+
+    private void formatMerged(ConversationItemViewModel header, String sendersString,
+            boolean isUnread, int mode) {
+        SpannableStringBuilder sendersBuilder = new SpannableStringBuilder();
+        SpannableStringBuilder statusBuilder = new SpannableStringBuilder();
+        Utils.getStyledSenderSnippet(getContext(), sendersString, sendersBuilder,
+                statusBuilder, ConversationItemViewCoordinates.getSubjectLength(getContext(), mode,
+                        header.folderDisplayer.hasVisibleFolders(),
+                        header.conversation.hasAttachments), false, false, header.hasDraftMessage);
+        header.sendersText = sendersBuilder.toString();
+
+        CharacterStyle[] spans = sendersBuilder.getSpans(0, sendersBuilder.length(),
+                CharacterStyle.class);
+        header.clearSenderFragments();
+        int lastPosition = 0;
+        CharacterStyle style = sNormalTextStyle;
+        if (spans != null) {
+            for (CharacterStyle span : spans) {
+                style = span;
+                int start = sendersBuilder.getSpanStart(style);
+                int end = sendersBuilder.getSpanEnd(style);
+                if (start > lastPosition) {
+                    header.addSenderFragment(lastPosition, start, sNormalTextStyle, false);
+                }
+                // From instructions won't be updated until the next sync. So we
+                // have to override the text style here to be consistent with
+                // the background color.
+                if (isUnread) {
+                    header.addSenderFragment(start, end, style, false);
+                } else {
+                    header.addSenderFragment(start, end, sNormalTextStyle, false);
+                }
+                lastPosition = end;
+            }
+        }
+        if (lastPosition < sendersBuilder.length()) {
+            style = sLightTextStyle;
+            header.addSenderFragment(lastPosition, sendersBuilder.length(), style, true);
+        }
+        if (statusBuilder.length() > 0) {
+            if (header.sendersText.length() > 0) {
+                header.sendersText = header.sendersText.concat(", ");
+
+                // Extend the last fragment to include the comma.
+                int lastIndex = header.senderFragments.size() - 1;
+                int start = header.senderFragments.get(lastIndex).start;
+                int end = header.senderFragments.get(lastIndex).end + 2;
+                style = header.senderFragments.get(lastIndex).style;
+
+                // The new fragment is only fixed if the previous fragment
+                // is fixed.
+                boolean isFixed = header.senderFragments.get(lastIndex).isFixed;
+
+                // Remove the old fragment.
+                header.senderFragments.remove(lastIndex);
+
+                // Add new fragment.
+                header.addSenderFragment(start, end, style, isFixed);
+            }
+            int pos = header.sendersText.length();
+            header.sendersText = header.sendersText.concat(statusBuilder.toString());
+            header.addSenderFragment(pos, header.sendersText.length(), new ForegroundColorSpan(
+                    DRAFT_TEXT_COLOR), true);
+        }
     }
 }