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 public ConversationViewState() {} 62 63 /** 64 * Copy constructor that will copy overall conversation state, but NOT individual message state. 65 */ 66 public ConversationViewState(ConversationViewState other) { 67 mConversationInfo = other.mConversationInfo; 68 } 69 70 public boolean isUnread(Message m) { 71 final MessageViewState mvs = mMessageViewStates.get(m.uri); 72 return (mvs != null && !mvs.read); 73 } 74 75 public void setReadState(Message m, boolean read) { 76 MessageViewState mvs = mMessageViewStates.get(m.uri); 77 if (mvs == null) { 78 mvs = new MessageViewState(); 79 } 80 mvs.read = read; 81 mMessageViewStates.put(m.uri, mvs); 82 } 83 84 public boolean getShouldShowImages(Message m) { 85 final MessageViewState mvs = mMessageViewStates.get(m.uri); 86 return (mvs != null && mvs.showImages); 87 } 88 89 public void setShouldShowImages(Message m, boolean showImages) { 90 MessageViewState mvs = mMessageViewStates.get(m.uri); 91 if (mvs == null) { 92 mvs = new MessageViewState(); 93 } 94 mvs.showImages = showImages; 95 mMessageViewStates.put(m.uri, mvs); 96 } 97 98 /** 99 * Returns the expansion state of a message in a conversation view. 100 * 101 * @param m a Message in the conversation 102 * @return 1 = expanded, 2 = collapsed, 3 = super collapsed, or null otherwise 103 * (see {@link ExpansionState}). 104 */ 105 public Integer getExpansionState(Message m) { 106 final MessageViewState mvs = mMessageViewStates.get(m.uri); 107 return (mvs == null ? null : mvs.expansionState); 108 } 109 110 public void setExpansionState(Message m, int expansionState) { 111 MessageViewState mvs = mMessageViewStates.get(m.uri); 112 if (mvs == null) { 113 mvs = new MessageViewState(); 114 } 115 mvs.expansionState = expansionState; 116 mMessageViewStates.put(m.uri, mvs); 117 } 118 119 public byte[] getConversationInfo() { 120 return mConversationInfo; 121 } 122 123 public void setInfoForConversation(Conversation conv) { 124 mConversationInfo = conv.conversationInfo.toBlob(); 125 } 126 127 /** 128 * Returns URIs of all unread messages in the conversation per 129 * {@link #setReadState(Message, boolean)}. Returns an empty set for read conversations. 130 * 131 */ 132 public Set<Uri> getUnreadMessageUris() { 133 final Set<Uri> result = Sets.newHashSet(); 134 for (Uri uri : mMessageViewStates.keySet()) { 135 final MessageViewState mvs = mMessageViewStates.get(uri); 136 if (mvs != null && !mvs.read) { 137 result.add(uri); 138 } 139 } 140 return result; 141 } 142 143 public boolean contains(Message m) { 144 return mMessageViewStates.containsKey(m.uri); 145 } 146 147 @Override 148 public int describeContents() { 149 return 0; 150 } 151 152 @Override 153 public void writeToParcel(Parcel dest, int flags) { 154 final Bundle states = new Bundle(); 155 for (Uri uri : mMessageViewStates.keySet()) { 156 final MessageViewState mvs = mMessageViewStates.get(uri); 157 states.putParcelable(uri.toString(), mvs); 158 } 159 dest.writeBundle(states); 160 dest.writeByteArray(mConversationInfo); 161 } 162 163 private ConversationViewState(Parcel source, ClassLoader loader) { 164 final Bundle states = source.readBundle(loader); 165 for (String key : states.keySet()) { 166 final MessageViewState state = states.getParcelable(key); 167 mMessageViewStates.put(Uri.parse(key), state); 168 } 169 mConversationInfo = source.createByteArray(); 170 } 171 172 public static final ClassLoaderCreator<ConversationViewState> CREATOR = 173 new ClassLoaderCreator<ConversationViewState>() { 174 175 @Override 176 public ConversationViewState createFromParcel(Parcel source) { 177 return new ConversationViewState(source, null); 178 } 179 180 @Override 181 public ConversationViewState createFromParcel(Parcel source, ClassLoader loader) { 182 return new ConversationViewState(source, loader); 183 } 184 185 @Override 186 public ConversationViewState[] newArray(int size) { 187 return new ConversationViewState[size]; 188 } 189 190 }; 191 192 // Keep per-message state in an inner Parcelable. 193 // This is a semi-private implementation detail. 194 static class MessageViewState implements Parcelable { 195 196 public boolean read; 197 /** 198 * See {@link ExpansionState} for values. 199 * 200 */ 201 public Integer expansionState; 202 public boolean showImages; 203 204 public MessageViewState() {} 205 206 @Override 207 public int describeContents() { 208 return 0; 209 } 210 211 @Override 212 public void writeToParcel(Parcel dest, int flags) { 213 dest.writeInt(read ? 1 : 0); 214 dest.writeInt(expansionState == null ? -1 : expansionState.intValue()); 215 dest.writeInt(showImages ? 1 : 0); 216 } 217 218 private MessageViewState(Parcel source) { 219 read = (source.readInt() != 0); 220 final int expandedVal = source.readInt(); 221 expansionState = (expandedVal == -1) ? null : expandedVal; 222 showImages = (source.readInt() != 0); 223 } 224 225 @SuppressWarnings("hiding") 226 public static final Parcelable.Creator<MessageViewState> CREATOR = 227 new Parcelable.Creator<MessageViewState>() { 228 229 @Override 230 public MessageViewState createFromParcel(Parcel source) { 231 return new MessageViewState(source); 232 } 233 234 @Override 235 public MessageViewState[] newArray(int size) { 236 return new MessageViewState[size]; 237 } 238 239 }; 240 241 } 242 243 } 244