SendersView.java revision 648df3f0b0ebcd3c4adf907d70ff0938e5dfc78f
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); 45a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira public static 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) { 73648df3f0b0ebcd3c4adf907d70ff0938e5dfc78fMindy Pereira if (TextUtils.isEmpty(header.conversation.senders) 74648df3f0b0ebcd3c4adf907d70ff0938e5dfc78fMindy Pereira && header.conversation.conversationInfo == null) { 758eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira return; 768eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 77b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira Conversation conversation = header.conversation; 78648df3f0b0ebcd3c4adf907d70ff0938e5dfc78fMindy Pereira String sendersInfo = conversation.conversationInfo != null ? 79648df3f0b0ebcd3c4adf907d70ff0938e5dfc78fMindy Pereira conversation.conversationInfo.sendersInfo : header.conversation.senders; 80648df3f0b0ebcd3c4adf907d70ff0938e5dfc78fMindy Pereira SendersInfo info = new SendersInfo(sendersInfo); 81a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira mFormatVersion = info.version; 82b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira switch (mFormatVersion) { 83b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira case MERGED_FORMATTING: 84a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira formatMerged(header, info.text, isUnread, mode); 85b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira break; 86b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira case DEFAULT_FORMATTING: 87b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira default: 88a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira formatDefault(header, info.text); 89b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira break; 90b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 918eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 928eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira 93b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private void formatDefault(ConversationItemViewModel header, String sendersString) { 948eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira String[] senders = TextUtils.split(sendersString, Address.ADDRESS_DELIMETER); 958eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira String[] namesOnly = new String[senders.length]; 968eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira Rfc822Token[] senderTokens; 978eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira String display; 988eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira for (int i = 0; i < senders.length; i++) { 998eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira senderTokens = Rfc822Tokenizer.tokenize(senders[i]); 1008eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira if (senderTokens != null && senderTokens.length > 0) { 1018eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira display = senderTokens[0].getName(); 1028eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira if (TextUtils.isEmpty(display)) { 1038eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira display = senderTokens[0].getAddress(); 1048eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 1058eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira namesOnly[i] = display; 1068eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 1078eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 108b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = TextUtils.join(Address.ADDRESS_DELIMETER + " ", namesOnly); 109b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(0, header.sendersText.length(), sNormalTextStyle, true); 110b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 111b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 112b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira private void formatMerged(ConversationItemViewModel header, String sendersString, 113b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira boolean isUnread, int mode) { 114b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira SpannableStringBuilder sendersBuilder = new SpannableStringBuilder(); 115b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira SpannableStringBuilder statusBuilder = new SpannableStringBuilder(); 116b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira Utils.getStyledSenderSnippet(getContext(), sendersString, sendersBuilder, 117b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira statusBuilder, ConversationItemViewCoordinates.getSubjectLength(getContext(), mode, 118b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.folderDisplayer.hasVisibleFolders(), 119b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.conversation.hasAttachments), false, false, header.hasDraftMessage); 120b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = sendersBuilder.toString(); 121b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 122b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira CharacterStyle[] spans = sendersBuilder.getSpans(0, sendersBuilder.length(), 123b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira CharacterStyle.class); 124b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.clearSenderFragments(); 125b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int lastPosition = 0; 126b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira CharacterStyle style = sNormalTextStyle; 127b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (spans != null) { 128b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira for (CharacterStyle span : spans) { 129b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira style = span; 130b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int start = sendersBuilder.getSpanStart(style); 131b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int end = sendersBuilder.getSpanEnd(style); 132b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (start > lastPosition) { 133b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(lastPosition, start, sNormalTextStyle, false); 134b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 135b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // From instructions won't be updated until the next sync. So we 136b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // have to override the text style here to be consistent with 137b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // the background color. 138b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (isUnread) { 139b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(start, end, style, false); 140b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } else { 141b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(start, end, sNormalTextStyle, false); 142b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 143b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira lastPosition = end; 144b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 145b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 146b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (lastPosition < sendersBuilder.length()) { 147b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira style = sLightTextStyle; 148b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(lastPosition, sendersBuilder.length(), style, true); 149b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 150b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (statusBuilder.length() > 0) { 151b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira if (header.sendersText.length() > 0) { 152b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = header.sendersText.concat(", "); 153b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 154b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Extend the last fragment to include the comma. 155b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int lastIndex = header.senderFragments.size() - 1; 156b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int start = header.senderFragments.get(lastIndex).start; 157b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int end = header.senderFragments.get(lastIndex).end + 2; 158b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira style = header.senderFragments.get(lastIndex).style; 159b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 160b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // The new fragment is only fixed if the previous fragment 161b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // is fixed. 162b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira boolean isFixed = header.senderFragments.get(lastIndex).isFixed; 163b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 164b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Remove the old fragment. 165b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.senderFragments.remove(lastIndex); 166b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira 167b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira // Add new fragment. 168b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(start, end, style, isFixed); 169b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 170b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira int pos = header.sendersText.length(); 171b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.sendersText = header.sendersText.concat(statusBuilder.toString()); 172b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira header.addSenderFragment(pos, header.sendersText.length(), new ForegroundColorSpan( 173b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira DRAFT_TEXT_COLOR), true); 174b9c036b36542924894f141e3ecd81381a12e94a9Mindy Pereira } 1758eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira } 176a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira 177a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira public static class SendersInfo { 178a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira public int version; 179a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira public String text; 180a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira 181a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira public SendersInfo(String toParse) { 182a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira if (TextUtils.isEmpty(toParse)) { 183a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira version = 0; 184a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira text = ""; 185a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira } else { 186a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira String[] splits = TextUtils.split(toParse, SENDERS_VERSION_SEPARATOR_PATTERN); 187a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira if (splits == null || splits.length < 2) { 188a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira version = SendersView.DEFAULT_FORMATTING; 189a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira text = toParse; 190a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira } else { 191a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira version = Integer.parseInt(splits[0]); 192a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira text = splits[1]; 193a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira } 194a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira } 195a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira } 196a1512b60eb12f732ac249fe7fcdc4fec756ed147Mindy Pereira } 1978eb43be8074acb4e09da1385225fbb41c97b1bd5Mindy Pereira} 198