Home | History | Annotate | Download | only in browse
      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.os.Build;
     23 import android.text.Spannable;
     24 import android.text.SpannableStringBuilder;
     25 import android.text.TextUtils;
     26 import android.text.style.BackgroundColorSpan;
     27 import android.text.style.ForegroundColorSpan;
     28 import android.util.AttributeSet;
     29 import android.util.TypedValue;
     30 import android.view.View;
     31 import android.view.View.OnClickListener;
     32 import android.view.ViewGroup;
     33 import android.widget.LinearLayout;
     34 import android.widget.TextView;
     35 
     36 import com.android.mail.R;
     37 import com.android.mail.browse.ConversationViewAdapter.ConversationHeaderItem;
     38 import com.android.mail.browse.FolderSpan.FolderSpanDimensions;
     39 import com.android.mail.providers.Conversation;
     40 import com.android.mail.providers.Folder;
     41 import com.android.mail.providers.Settings;
     42 import com.android.mail.ui.FolderDisplayer;
     43 import com.android.mail.utils.LogTag;
     44 import com.android.mail.utils.LogUtils;
     45 import com.android.mail.utils.Utils;
     46 
     47 /**
     48  * A view for the subject and folders in the conversation view. This container
     49  * makes an attempt to combine subject and folders on the same horizontal line if
     50  * there is enough room to fit both without wrapping. If they overlap, it
     51  * adjusts the layout to position the folders below the subject.
     52  */
     53 public class ConversationViewHeader extends LinearLayout implements OnClickListener {
     54 
     55     public interface ConversationViewHeaderCallbacks {
     56         /**
     57          * Called in response to a click on the folders region.
     58          */
     59         void onFoldersClicked();
     60 
     61         /**
     62          * Called when the height of the {@link ConversationViewHeader} changes.
     63          *
     64          * @param newHeight the new height in px
     65          */
     66         void onConversationViewHeaderHeightChange(int newHeight);
     67     }
     68 
     69     private static final String LOG_TAG = LogTag.getLogTag();
     70     private TextView mSubjectView;
     71     private FolderSpanTextView mFoldersView;
     72     private ConversationViewHeaderCallbacks mCallbacks;
     73     private ConversationAccountController mAccountController;
     74     private ConversationFolderDisplayer mFolderDisplayer;
     75     private ConversationHeaderItem mHeaderItem;
     76 
     77     private boolean mLargeText;
     78     private final float mCondensedTextSize;
     79     private final int mCondensedTopPadding;
     80 
     81     /**
     82      * Instantiated from this layout: conversation_view_header.xml
     83      * @param context
     84      */
     85     public ConversationViewHeader(Context context) {
     86         this(context, null);
     87     }
     88 
     89     public ConversationViewHeader(Context context, AttributeSet attrs) {
     90         super(context, attrs);
     91         mLargeText = true;
     92         final Resources resources = getResources();
     93         mCondensedTextSize =
     94                 resources.getDimensionPixelSize(R.dimen.conversation_header_font_size_condensed);
     95         mCondensedTopPadding = resources.getDimensionPixelSize(
     96                 R.dimen.conversation_header_vertical_padding_condensed);
     97     }
     98 
     99     @Override
    100     protected void onFinishInflate() {
    101         super.onFinishInflate();
    102 
    103         mSubjectView = (TextView) findViewById(R.id.subject);
    104         mFoldersView = (FolderSpanTextView) findViewById(R.id.folders);
    105 
    106         mFoldersView.setOnClickListener(this);
    107         mFolderDisplayer = new ConversationFolderDisplayer(getContext(), mFoldersView);
    108     }
    109 
    110     @Override
    111     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    112         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    113 
    114         // If we currently have large text and we have greater than 2 lines,
    115         // switch to smaller text size with smaller top padding and re-measure
    116         if (mLargeText && mSubjectView.getLineCount() > 2) {
    117             mSubjectView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCondensedTextSize);
    118 
    119             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    120                 // start, top, end, bottom
    121                 mSubjectView.setPaddingRelative(mSubjectView.getPaddingStart(),
    122                         mCondensedTopPadding, mSubjectView.getPaddingEnd(),
    123                         mSubjectView.getPaddingBottom());
    124             } else {
    125                 mSubjectView.setPadding(mSubjectView.getPaddingLeft(),
    126                         mCondensedTopPadding, mSubjectView.getPaddingRight(),
    127                         mSubjectView.getPaddingBottom());
    128             }
    129 
    130             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    131         }
    132     }
    133 
    134     public void setCallbacks(ConversationViewHeaderCallbacks callbacks,
    135             ConversationAccountController accountController) {
    136         mCallbacks = callbacks;
    137         mAccountController = accountController;
    138     }
    139 
    140     public void setSubject(final String subject) {
    141         mSubjectView.setText(subject);
    142         if (TextUtils.isEmpty(subject)) {
    143             mSubjectView.setVisibility(GONE);
    144         }
    145     }
    146 
    147     public void setFoldersVisible(boolean show) {
    148         mFoldersView.setVisibility(show ? View.VISIBLE : View.GONE);
    149     }
    150 
    151     public void setFolders(Conversation conv) {
    152         setFoldersVisible(true);
    153         SpannableStringBuilder sb = new SpannableStringBuilder();
    154         final Settings settings = mAccountController.getAccount().settings;
    155         if (settings.priorityArrowsEnabled && conv.isImportant()) {
    156             sb.append('.');
    157             sb.setSpan(new PriorityIndicatorSpan(getContext(),
    158                     R.drawable.ic_email_caret_none_important_unread, mFoldersView.getPadding(), 0,
    159                     mFoldersView.getPaddingAbove()),
    160                     0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
    161         }
    162 
    163         mFolderDisplayer.loadConversationFolders(conv, null /* ignoreFolder */,
    164                 -1 /* ignoreFolderType */);
    165         mFolderDisplayer.appendFolderSpans(sb);
    166 
    167         mFoldersView.setText(sb);
    168     }
    169 
    170     public void bind(ConversationHeaderItem headerItem) {
    171         mHeaderItem = headerItem;
    172     }
    173 
    174     private int measureHeight() {
    175         ViewGroup parent = (ViewGroup) getParent();
    176         if (parent == null) {
    177             LogUtils.e(LOG_TAG, "Unable to measure height of conversation header");
    178             return getHeight();
    179         }
    180         final int h = Utils.measureViewHeight(this, parent);
    181         return h;
    182     }
    183 
    184     /**
    185      * Update the conversation view header to reflect the updated conversation.
    186      */
    187     public void onConversationUpdated(Conversation conv) {
    188         // The only things we have to worry about when the conversation changes
    189         // in the conversation header are the folders and priority indicators.
    190         // Updating these will resize the space for the header.
    191         setFolders(conv);
    192         if (mHeaderItem != null) {
    193             final int h = measureHeight();
    194             if (mHeaderItem.setHeight(h)) {
    195                 mCallbacks.onConversationViewHeaderHeightChange(h);
    196             }
    197         }
    198     }
    199 
    200     @Override
    201     public void onClick(View v) {
    202         if (R.id.folders == v.getId()) {
    203             if (mCallbacks != null) {
    204                 mCallbacks.onFoldersClicked();
    205             }
    206         }
    207     }
    208 
    209     private static class ConversationFolderDisplayer extends FolderDisplayer {
    210 
    211         private FolderSpanDimensions mDims;
    212 
    213         public ConversationFolderDisplayer(Context context, FolderSpanDimensions dims) {
    214             super(context);
    215             mDims = dims;
    216         }
    217 
    218         public void appendFolderSpans(SpannableStringBuilder sb) {
    219             for (final Folder f : mFoldersSortedSet) {
    220                 final int bgColor = f.getBackgroundColor(mDefaultBgColor);
    221                 final int fgColor = f.getForegroundColor(mDefaultFgColor);
    222                 addSpan(sb, f.name, bgColor, fgColor);
    223             }
    224 
    225             if (mFoldersSortedSet.isEmpty()) {
    226                 final Resources r = mContext.getResources();
    227                 final String name = r.getString(R.string.add_label);
    228                 final int bgColor = r.getColor(R.color.conv_header_add_label_background);
    229                 final int fgColor = r.getColor(R.color.conv_header_add_label_text);
    230                 addSpan(sb, name, bgColor, fgColor);
    231             }
    232         }
    233 
    234         private void addSpan(SpannableStringBuilder sb, String name, int bgColor,
    235                              int fgColor) {
    236             final int start = sb.length();
    237             sb.append(name);
    238             final int end = sb.length();
    239 
    240             sb.setSpan(new BackgroundColorSpan(bgColor), start, end,
    241                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    242             sb.setSpan(new ForegroundColorSpan(fgColor), start, end,
    243                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    244             sb.setSpan(new FolderSpan(sb, mDims), start, end,
    245                     Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    246         }
    247 
    248     }
    249 }
    250