Home | History | Annotate | Download | only in ui
      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.ui;
     19 
     20 import android.net.Uri;
     21 import android.os.Bundle;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 
     25 import com.android.mail.providers.Conversation;
     26 import com.android.mail.providers.Message;
     27 import com.google.common.collect.Maps;
     28 import com.google.common.collect.Sets;
     29 
     30 import java.util.Map;
     31 import java.util.Set;
     32 
     33 /**
     34  * A small class to keep state for conversation view when restoring.
     35  *
     36  */
     37 public class ConversationViewState implements Parcelable {
     38 
     39     // N.B. don't serialize entire Messages because they contain body HTML/text
     40 
     41     private final Map<Uri, MessageViewState> mMessageViewStates = Maps.newHashMap();
     42 
     43     private byte[] mConversationInfo;
     44 
     45     public static final class ExpansionState {
     46         public static int NONE = 0;
     47         public static int EXPANDED = 1;
     48         public static int COLLAPSED = 2;
     49         public static int SUPER_COLLAPSED = 3;
     50 
     51         private ExpansionState() {}
     52 
     53         public static boolean isExpanded(int state) {
     54             return state == EXPANDED;
     55         }
     56         public static boolean isSuperCollapsed(int state) {
     57             return state == SUPER_COLLAPSED;
     58         }
     59 
     60         /**
     61          * Returns true if the {@link ExpansionState} is
     62          * {@link #COLLAPSED} or {@link #SUPER_COLLAPSED}.
     63          */
     64         public static boolean isCollapsed(int state) {
     65             return state > EXPANDED;
     66         }
     67     }
     68 
     69     public ConversationViewState() {}
     70 
     71     /**
     72      * Copy constructor that will copy overall conversation state, but NOT individual message state.
     73      */
     74     public ConversationViewState(ConversationViewState other) {
     75         mConversationInfo = other.mConversationInfo;
     76     }
     77 
     78     public boolean isUnread(Message m) {
     79         final MessageViewState mvs = mMessageViewStates.get(m.uri);
     80         return (mvs != null && !mvs.read);
     81     }
     82 
     83     public void setReadState(Message m, boolean read) {
     84         MessageViewState mvs = mMessageViewStates.get(m.uri);
     85         if (mvs == null) {
     86             mvs = new MessageViewState();
     87         }
     88         mvs.read = read;
     89         mMessageViewStates.put(m.uri, mvs);
     90     }
     91 
     92     public boolean getShouldShowImages(Message m) {
     93         final MessageViewState mvs = mMessageViewStates.get(m.uri);
     94         return (mvs != null && mvs.showImages);
     95     }
     96 
     97     public void setShouldShowImages(Message m, boolean showImages) {
     98         MessageViewState mvs = mMessageViewStates.get(m.uri);
     99         if (mvs == null) {
    100             mvs = new MessageViewState();
    101         }
    102         mvs.showImages = showImages;
    103         mMessageViewStates.put(m.uri, mvs);
    104     }
    105 
    106     /**
    107      * Returns the expansion state of a message in a conversation view.
    108      *
    109      * @param m a Message in the conversation
    110      * @return 1 = expanded, 2 = collapsed, 3 = super collapsed, or null otherwise
    111      * (see {@link ExpansionState}).
    112      */
    113     public Integer getExpansionState(Message m) {
    114         final MessageViewState mvs = mMessageViewStates.get(m.uri);
    115         return (mvs == null ? null : mvs.expansionState);
    116     }
    117 
    118     public void setExpansionState(Message m, int expansionState) {
    119         MessageViewState mvs = mMessageViewStates.get(m.uri);
    120         if (mvs == null) {
    121             mvs = new MessageViewState();
    122         }
    123         mvs.expansionState = expansionState;
    124         mMessageViewStates.put(m.uri, mvs);
    125     }
    126 
    127     public byte[] getConversationInfo() {
    128         return mConversationInfo;
    129     }
    130 
    131     public void setInfoForConversation(Conversation conv) {
    132         mConversationInfo = conv.conversationInfo != null ? conv.conversationInfo.toBlob() : null;
    133     }
    134 
    135     /**
    136      * Returns URIs of all unread messages in the conversation per
    137      * {@link #setReadState(Message, boolean)}. Returns an empty set for read conversations.
    138      *
    139      */
    140     public Set<Uri> getUnreadMessageUris() {
    141         final Set<Uri> result = Sets.newHashSet();
    142         for (Uri uri : mMessageViewStates.keySet()) {
    143             final MessageViewState mvs = mMessageViewStates.get(uri);
    144             if (mvs != null && !mvs.read) {
    145                 result.add(uri);
    146             }
    147         }
    148         return result;
    149     }
    150 
    151     public boolean contains(Message m) {
    152         return mMessageViewStates.containsKey(m.uri);
    153     }
    154 
    155     @Override
    156     public int describeContents() {
    157         return 0;
    158     }
    159 
    160     @Override
    161     public void writeToParcel(Parcel dest, int flags) {
    162         final Bundle states = new Bundle();
    163         for (Uri uri : mMessageViewStates.keySet()) {
    164             final MessageViewState mvs = mMessageViewStates.get(uri);
    165             states.putParcelable(uri.toString(), mvs);
    166         }
    167         dest.writeBundle(states);
    168         dest.writeByteArray(mConversationInfo);
    169     }
    170 
    171     private ConversationViewState(Parcel source, ClassLoader loader) {
    172         final Bundle states = source.readBundle(loader);
    173         for (String key : states.keySet()) {
    174             final MessageViewState state = states.getParcelable(key);
    175             mMessageViewStates.put(Uri.parse(key), state);
    176         }
    177         mConversationInfo = source.createByteArray();
    178     }
    179 
    180     public static final ClassLoaderCreator<ConversationViewState> CREATOR =
    181             new ClassLoaderCreator<ConversationViewState>() {
    182 
    183         @Override
    184         public ConversationViewState createFromParcel(Parcel source) {
    185             return new ConversationViewState(source, null);
    186         }
    187 
    188         @Override
    189         public ConversationViewState createFromParcel(Parcel source, ClassLoader loader) {
    190             return new ConversationViewState(source, loader);
    191         }
    192 
    193         @Override
    194         public ConversationViewState[] newArray(int size) {
    195             return new ConversationViewState[size];
    196         }
    197 
    198     };
    199 
    200     // Keep per-message state in an inner Parcelable.
    201     // This is a semi-private implementation detail.
    202     static class MessageViewState implements Parcelable {
    203 
    204         public boolean read;
    205         /**
    206          * See {@link ExpansionState} for values.
    207          *
    208          */
    209         public Integer expansionState;
    210         public boolean showImages;
    211 
    212         public MessageViewState() {}
    213 
    214         @Override
    215         public int describeContents() {
    216             return 0;
    217         }
    218 
    219         @Override
    220         public void writeToParcel(Parcel dest, int flags) {
    221             dest.writeInt(read ? 1 : 0);
    222             dest.writeInt(expansionState == null ? -1 : expansionState.intValue());
    223             dest.writeInt(showImages ? 1 : 0);
    224         }
    225 
    226         private MessageViewState(Parcel source) {
    227             read = (source.readInt() != 0);
    228             final int expandedVal = source.readInt();
    229             expansionState = (expandedVal == -1) ? null : expandedVal;
    230             showImages = (source.readInt() != 0);
    231         }
    232 
    233         @SuppressWarnings("hiding")
    234         public static final Parcelable.Creator<MessageViewState> CREATOR =
    235                 new Parcelable.Creator<MessageViewState>() {
    236 
    237             @Override
    238             public MessageViewState createFromParcel(Parcel source) {
    239                 return new MessageViewState(source);
    240             }
    241 
    242             @Override
    243             public MessageViewState[] newArray(int size) {
    244                 return new MessageViewState[size];
    245             }
    246 
    247         };
    248 
    249     }
    250 
    251 }
    252