SendersView.java revision b9c036b36542924894f141e3ecd81381a12e94a9
18eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira/* 28eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * Copyright (C) 2012 Google Inc. 38eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * Licensed to The Android Open Source Project. 48eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * 58eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 68eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * you may not use this file except in compliance with the License. 78eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * You may obtain a copy of the License at 88eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * 98eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 108eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * 118eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * Unless required by applicable law or agreed to in writing, software 128eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 138eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 148eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * See the License for the specific language governing permissions and 158eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira * limitations under the License. 168eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira */ 178eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 188eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereirapackage com.android.mail.browse; 198eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 208eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.content.Context; 21b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereiraimport android.content.res.Resources; 228eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.graphics.Typeface; 23b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereiraimport android.text.SpannableStringBuilder; 248eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.text.TextUtils; 258eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.text.style.CharacterStyle; 26b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereiraimport android.text.style.ForegroundColorSpan; 278eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.text.style.StyleSpan; 288eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.text.util.Rfc822Token; 298eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.text.util.Rfc822Tokenizer; 308eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.util.AttributeSet; 318eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport android.widget.TextView; 328eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 33b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereiraimport com.android.mail.R; 348eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport com.android.mail.providers.Address; 358eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereiraimport com.android.mail.providers.Conversation; 36b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereiraimport com.android.mail.utils.Utils; 37b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 38b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereiraimport java.util.regex.Pattern; 398eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 408eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereirapublic class SendersView extends TextView { 41b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira public static final int DEFAULT_FORMATTING = 0; 42b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira public static final int MERGED_FORMATTING = 1; 43b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira public static String SENDERS_VERSION_SEPARATOR = "^**^"; 448eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira CharacterStyle sNormalTextStyle = new StyleSpan(Typeface.NORMAL); 45b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private Pattern SENDERS_VERSION_SEPARATOR_PATTERN = Pattern.compile("\\^\\*\\*\\^"); 46b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private int mFormatVersion = -1; 47b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private ForegroundColorSpan sLightTextStyle; 48b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private int DRAFT_TEXT_COLOR; 49b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private int LIGHT_TEXT_COLOR; 508eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 518eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira public SendersView(Context context) { 528eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira this(context, null); 538eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 548eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 558eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira public SendersView(Context context, AttributeSet attrs) { 568eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira this(context, attrs, -1); 578eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 588eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 598eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira public SendersView(Context context, AttributeSet attrs, int defStyle) { 608eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira super(context, attrs, defStyle); 61b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira Resources res = context.getResources(); 62b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira LIGHT_TEXT_COLOR = res.getColor(R.color.light_text_color); 63b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira DRAFT_TEXT_COLOR = res.getColor(R.color.drafts); 64b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira sLightTextStyle = new ForegroundColorSpan(LIGHT_TEXT_COLOR); 658eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 668eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 678eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira public Typeface getTypeface(boolean isUnread) { 68b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira return mFormatVersion == DEFAULT_FORMATTING ? isUnread ? Typeface.DEFAULT_BOLD 69b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira : Typeface.DEFAULT : Typeface.DEFAULT; 708eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 718eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 72b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira public void formatSenders(ConversationItemViewModel header, boolean isUnread, int mode) { 738eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira if (TextUtils.isEmpty(header.conversation.senders)) { 748eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira return; 758eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 76b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira Conversation conversation = header.conversation; 77b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira String sendersString = ""; 78b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira String[] splits = TextUtils.split(conversation.senders, SENDERS_VERSION_SEPARATOR_PATTERN); 79b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (splits == null || splits.length < 2) { 80b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira mFormatVersion = DEFAULT_FORMATTING; 81b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira sendersString = header.conversation.senders; 82b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } else { 83b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira mFormatVersion = Integer.parseInt(splits[0]); 84b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Format the rest of the senders string once the format version is 85b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // stripped. 86b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira sendersString = splits[1]; 87b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 88b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira switch (mFormatVersion) { 89b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira case MERGED_FORMATTING: 90b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira formatMerged(header, sendersString, isUnread, mode); 91b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira break; 92b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira case DEFAULT_FORMATTING: 93b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira default: 94b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira formatDefault(header, sendersString); 95b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira break; 96b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 978eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 988eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 99b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private void formatDefault(ConversationItemViewModel header, String sendersString) { 1008eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira String[] senders = TextUtils.split(sendersString, Address.ADDRESS_DELIMETER); 1018eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira String[] namesOnly = new String[senders.length]; 1028eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira Rfc822Token[] senderTokens; 1038eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira String display; 1048eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira for (int i = 0; i < senders.length; i++) { 1058eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira senderTokens = Rfc822Tokenizer.tokenize(senders[i]); 1068eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira if (senderTokens != null && senderTokens.length > 0) { 1078eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira display = senderTokens[0].getName(); 1088eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira if (TextUtils.isEmpty(display)) { 1098eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira display = senderTokens[0].getAddress(); 1108eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 1118eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira namesOnly[i] = display; 1128eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 1138eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 114b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = TextUtils.join(Address.ADDRESS_DELIMETER + " ", namesOnly); 115b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(0, header.sendersText.length(), sNormalTextStyle, true); 116b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 117b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 118b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private void formatMerged(ConversationItemViewModel header, String sendersString, 119b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira boolean isUnread, int mode) { 120b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira SpannableStringBuilder sendersBuilder = new SpannableStringBuilder(); 121b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira SpannableStringBuilder statusBuilder = new SpannableStringBuilder(); 122b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira Utils.getStyledSenderSnippet(getContext(), sendersString, sendersBuilder, 123b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira statusBuilder, ConversationItemViewCoordinates.getSubjectLength(getContext(), mode, 124b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.folderDisplayer.hasVisibleFolders(), 125b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.conversation.hasAttachments), false, false, header.hasDraftMessage); 126b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = sendersBuilder.toString(); 127b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 128b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira CharacterStyle[] spans = sendersBuilder.getSpans(0, sendersBuilder.length(), 129b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira CharacterStyle.class); 130b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.clearSenderFragments(); 131b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int lastPosition = 0; 132b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira CharacterStyle style = sNormalTextStyle; 133b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (spans != null) { 134b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira for (CharacterStyle span : spans) { 135b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira style = span; 136b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int start = sendersBuilder.getSpanStart(style); 137b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int end = sendersBuilder.getSpanEnd(style); 138b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (start > lastPosition) { 139b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(lastPosition, start, sNormalTextStyle, false); 140b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 141b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // From instructions won't be updated until the next sync. So we 142b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // have to override the text style here to be consistent with 143b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // the background color. 144b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (isUnread) { 145b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(start, end, style, false); 146b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } else { 147b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(start, end, sNormalTextStyle, false); 148b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 149b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira lastPosition = end; 150b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 151b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 152b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (lastPosition < sendersBuilder.length()) { 153b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira style = sLightTextStyle; 154b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(lastPosition, sendersBuilder.length(), style, true); 155b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 156b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (statusBuilder.length() > 0) { 157b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (header.sendersText.length() > 0) { 158b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = header.sendersText.concat(", "); 159b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 160b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Extend the last fragment to include the comma. 161b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int lastIndex = header.senderFragments.size() - 1; 162b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int start = header.senderFragments.get(lastIndex).start; 163b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int end = header.senderFragments.get(lastIndex).end + 2; 164b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira style = header.senderFragments.get(lastIndex).style; 165b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 166b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // The new fragment is only fixed if the previous fragment 167b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // is fixed. 168b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira boolean isFixed = header.senderFragments.get(lastIndex).isFixed; 169b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 170b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Remove the old fragment. 171b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.senderFragments.remove(lastIndex); 172b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 173b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Add new fragment. 174b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(start, end, style, isFixed); 175b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 176b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int pos = header.sendersText.length(); 177b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = header.sendersText.concat(statusBuilder.toString()); 178b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(pos, header.sendersText.length(), new ForegroundColorSpan( 179b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira DRAFT_TEXT_COLOR), true); 180b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 1818eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 1828eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira} 183