• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc.
3  * Licensed to The Android Open Source Project.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.mail.browse;
19 
20 import android.content.Context;
21 import android.content.res.Resources;
22 import android.graphics.drawable.Drawable;
23 import android.support.v4.text.BidiFormatter;
24 import android.text.Layout;
25 import android.text.Spannable;
26 import android.text.SpannableStringBuilder;
27 import android.text.Spanned;
28 import android.text.method.LinkMovementMethod;
29 import android.text.style.BackgroundColorSpan;
30 import android.text.style.DynamicDrawableSpan;
31 import android.text.style.ForegroundColorSpan;
32 import android.util.AttributeSet;
33 import android.widget.TextView;
34 
35 import com.android.mail.R;
36 import com.android.mail.browse.ConversationViewHeader.ConversationViewHeaderCallbacks;
37 import com.android.mail.providers.Account;
38 import com.android.mail.providers.Conversation;
39 import com.android.mail.providers.Folder;
40 import com.android.mail.providers.Settings;
41 import com.android.mail.text.ChangeLabelsSpan;
42 import com.android.mail.ui.FolderDisplayer;
43 import com.android.mail.utils.ViewUtils;
44 
45 /**
46  * A TextView that displays the conversation subject and list of folders for the message.
47  * The view knows the widest that any of its containing {@link FolderSpan}s can be.
48  * They cannot exceed the TextView line width, or else {@link Layout}
49  * will split up the spans in strange places.
50  */
51 public class SubjectAndFolderView extends TextView
52         implements FolderSpan.FolderSpanDimensions {
53 
54     private final int mFolderPadding;
55     private final int mFolderPaddingExtraWidth;
56     private final int mFolderPaddingAfter;
57     private final int mRoundedCornerRadius;
58     private final float mFolderSpanTextSize;
59     private final int mFolderMarginTop;
60 
61     private int mMaxSpanWidth;
62 
63     private ConversationFolderDisplayer mFolderDisplayer;
64 
65     private String mSubject;
66 
67     private boolean mVisibleFolders;
68 
69     private ConversationViewAdapter.ConversationHeaderItem mHeaderItem;
70 
71     private BidiFormatter mBidiFormatter;
72 
SubjectAndFolderView(Context context)73     public SubjectAndFolderView(Context context) {
74         this(context, null);
75     }
76 
SubjectAndFolderView(Context context, AttributeSet attrs)77     public SubjectAndFolderView(Context context, AttributeSet attrs) {
78         super(context, attrs);
79 
80         mVisibleFolders = false;
81         mFolderDisplayer = new ConversationFolderDisplayer(getContext(), this);
82 
83         final Resources r = getResources();
84         mFolderPadding = r.getDimensionPixelOffset(R.dimen.conversation_folder_padding);
85         mFolderPaddingExtraWidth = r.getDimensionPixelOffset(
86                 R.dimen.conversation_folder_padding_extra_width);
87         mFolderPaddingAfter = r.getDimensionPixelOffset(
88                 R.dimen.conversation_folder_padding_after);
89         mRoundedCornerRadius = r.getDimensionPixelOffset(
90                 R.dimen.folder_rounded_corner_radius);
91         mFolderSpanTextSize = r.getDimension(R.dimen.conversation_folder_font_size);
92         mFolderMarginTop = r.getDimensionPixelOffset(R.dimen.conversation_folder_margin_top);
93     }
94 
95     @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)96     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
97         mMaxSpanWidth = MeasureSpec.getSize(widthMeasureSpec) - getTotalPaddingLeft()
98                 - getTotalPaddingRight();
99 
100         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
101     }
102 
103     @Override
getPadding()104     public int getPadding() {
105         return mFolderPadding;
106     }
107 
108     @Override
getPaddingExtraWidth()109     public int getPaddingExtraWidth() {
110         return mFolderPaddingExtraWidth;
111     }
112 
113     @Override
getPaddingAfter()114     public int getPaddingAfter() {
115         return mFolderPaddingAfter;
116     }
117 
118     @Override
getMaxWidth()119     public int getMaxWidth() {
120         return mMaxSpanWidth;
121     }
122 
123     @Override
getRoundedCornerRadius()124     public float getRoundedCornerRadius() {
125         return mRoundedCornerRadius;
126     }
127 
128     @Override
getFolderSpanTextSize()129     public float getFolderSpanTextSize() {
130         return mFolderSpanTextSize;
131     }
132 
133     @Override
getMarginTop()134     public int getMarginTop() {
135         return mFolderMarginTop;
136     }
137 
138     @Override
isRtl()139     public boolean isRtl() {
140         return ViewUtils.isViewRtl(this);
141     }
142 
setSubject(String subject)143     public void setSubject(String subject) {
144         mSubject = Conversation.getSubjectForDisplay(getContext(), null /* badgeText */, subject);
145 
146         if (!mVisibleFolders) {
147             setText(mSubject);
148         }
149     }
150 
setFolders( ConversationViewHeaderCallbacks callbacks, Account account, Conversation conv)151     public void setFolders(
152             ConversationViewHeaderCallbacks callbacks, Account account, Conversation conv) {
153         mVisibleFolders = true;
154         final BidiFormatter bidiFormatter = getBidiFormatter();
155         final SpannableStringBuilder sb =
156                 new SpannableStringBuilder(bidiFormatter.unicodeWrap(mSubject));
157         sb.append('\u0020');
158         final Settings settings = account.settings;
159         final int start = sb.length();
160         if (settings.importanceMarkersEnabled && conv.isImportant()) {
161             sb.append(".\u0020");
162             sb.setSpan(new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
163                            @Override
164                            public Drawable getDrawable() {
165                                Drawable d = getContext().getResources().getDrawable(
166                                        R.drawable.ic_email_caret_none_important_unread);
167                                d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
168                                return d;
169                            }
170                        },
171                     start, start + 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
172         }
173 
174         mFolderDisplayer.loadConversationFolders(conv, null /* ignoreFolder */,
175                 -1 /* ignoreFolderType */);
176         mFolderDisplayer.appendFolderSpans(sb, bidiFormatter);
177 
178         final int end = sb.length();
179         sb.setSpan(new ChangeLabelsSpan(callbacks), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
180 
181         setText(sb);
182         setMovementMethod(LinkMovementMethod.getInstance());
183     }
184 
bind(ConversationViewAdapter.ConversationHeaderItem headerItem)185     public void bind(ConversationViewAdapter.ConversationHeaderItem headerItem) {
186         mHeaderItem = headerItem;
187     }
188 
getBidiFormatter()189     private BidiFormatter getBidiFormatter() {
190         if (mBidiFormatter == null) {
191             final ConversationViewAdapter adapter = mHeaderItem != null
192                     ? mHeaderItem.getAdapter() : null;
193             if (adapter == null) {
194                 mBidiFormatter = BidiFormatter.getInstance();
195             } else {
196                 mBidiFormatter = adapter.getBidiFormatter();
197             }
198         }
199         return mBidiFormatter;
200     }
201 
202     private static class ConversationFolderDisplayer extends FolderDisplayer {
203 
204         private final FolderSpan.FolderSpanDimensions mDims;
205 
ConversationFolderDisplayer(Context context, FolderSpan.FolderSpanDimensions dims)206         public ConversationFolderDisplayer(Context context, FolderSpan.FolderSpanDimensions dims) {
207             super(context);
208             mDims = dims;
209         }
210 
appendFolderSpans(SpannableStringBuilder sb, BidiFormatter bidiFormatter)211         public void appendFolderSpans(SpannableStringBuilder sb, BidiFormatter bidiFormatter) {
212             for (final Folder f : mFoldersSortedSet) {
213                 final int bgColor = f.getBackgroundColor(mDefaultBgColor);
214                 final int fgColor = f.getForegroundColor(mDefaultFgColor);
215                 addSpan(sb, f.name, bgColor, fgColor, bidiFormatter);
216             }
217 
218             if (mFoldersSortedSet.isEmpty()) {
219                 final Resources r = mContext.getResources();
220                 final String name = r.getString(R.string.add_label);
221                 final int bgColor = r.getColor(R.color.conv_header_add_label_background);
222                 final int fgColor = r.getColor(R.color.conv_header_add_label_text);
223                 addSpan(sb, name, bgColor, fgColor, bidiFormatter);
224             }
225         }
226 
addSpan(SpannableStringBuilder sb, String name, int bgColor, int fgColor, BidiFormatter bidiFormatter)227         private void addSpan(SpannableStringBuilder sb, String name,
228                 int bgColor, int fgColor, BidiFormatter bidiFormatter) {
229             final int start = sb.length();
230             sb.append(bidiFormatter.unicodeWrap(name));
231             final int end = sb.length();
232 
233             sb.setSpan(new BackgroundColorSpan(bgColor), start, end,
234                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
235             sb.setSpan(new ForegroundColorSpan(fgColor), start, end,
236                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
237             sb.setSpan(new FolderSpan(sb, mDims), start, end,
238                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
239         }
240     }
241 }
242