Conversation.java revision 76b2062b8c6d18a7b3a05292c385b47b0fcbd09f
1/** 2 * Copyright (c) 2012, Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.mail.providers; 18 19import android.database.Cursor; 20import android.net.Uri; 21import android.os.Parcel; 22import android.os.Parcelable; 23import android.provider.BaseColumns; 24import android.text.TextUtils; 25 26import com.google.common.collect.ImmutableList; 27 28import java.util.Collection; 29import java.util.Collections; 30 31public class Conversation implements Parcelable { 32 public static final int NO_POSITION = -1; 33 34 /** 35 * @see BaseColumns#_ID 36 */ 37 public long id; 38 /** 39 * @see UIProvider.ConversationColumns#URI 40 */ 41 public Uri uri; 42 /** 43 * @see UIProvider.ConversationColumns#SUBJECT 44 */ 45 public String subject; 46 /** 47 * @see UIProvider.ConversationColumns#DATE_RECEIVED_MS 48 */ 49 public long dateMs; 50 /** 51 * @see UIProvider.ConversationColumns#SNIPPET 52 */ 53 public String snippet; 54 /** 55 * @see UIProvider.ConversationColumns#HAS_ATTACHMENTS 56 */ 57 public boolean hasAttachments; 58 /** 59 * @see UIProvider.ConversationColumns#MESSAGE_LIST_URI 60 */ 61 public Uri messageListUri; 62 /** 63 * @see UIProvider.ConversationColumns#SENDER_INFO 64 */ 65 public String senders; 66 /** 67 * @see UIProvider.ConversationColumns#NUM_MESSAGES 68 */ 69 public int numMessages; 70 /** 71 * @see UIProvider.ConversationColumns#NUM_DRAFTS 72 */ 73 public int numDrafts; 74 /** 75 * @see UIProvider.ConversationColumns#SENDING_STATE 76 */ 77 public int sendingState; 78 /** 79 * @see UIProvider.ConversationColumns#PRIORITY 80 */ 81 public int priority; 82 /** 83 * @see UIProvider.ConversationColumns#READ 84 */ 85 public boolean read; 86 /** 87 * @see UIProvider.ConversationColumns#STARRED 88 */ 89 public boolean starred; 90 /** 91 * @see UIProvider.ConversationColumns#FOLDER_LIST 92 */ 93 public String folderList; 94 /** 95 * @see UIProvider.ConversationColumns#RAW_FOLDERS 96 */ 97 public String rawFolders; 98 /** 99 * @see UIProvider.ConversationColumns#FLAGS 100 */ 101 public int convFlags; 102 /** 103 * @see UIProvider.ConversationColumns#PERSONAL_LEVEL 104 */ 105 public int personalLevel; 106 /** 107 * @see UIProvider.ConversationColumns#SPAM 108 */ 109 public boolean spam; 110 /** 111 * @see UIProvider.ConversationColumns#MUTED 112 */ 113 public boolean muted; 114 /** 115 * @see UIProvider.ConversationColumns#PHISHING 116 */ 117 public boolean phishing; 118 /** 119 * @see UIProvider.ConversationColumns#COLOR 120 */ 121 public int color; 122 /** 123 * @see UIProvider.ConversationColumns#ACCOUNT_URI 124 */ 125 public Uri accountUri; 126 127 // Used within the UI to indicate the adapter position of this conversation 128 public transient int position; 129 // Used within the UI to indicate that a Conversation should be removed from the 130 // ConversationCursor when executing an update, e.g. the the Conversation is no longer 131 // in the ConversationList for the current folder, that is it's now in some other folder(s) 132 public transient boolean localDeleteOnUpdate; 133 134 // Constituents of convFlags below 135 // Flag indicating that the item has been deleted, but will continue being shown in the list 136 // Delete/Archive of a mostly-dead item will NOT propagate the delete/archive, but WILL remove 137 // the item from the cursor 138 public static final int FLAG_MOSTLY_DEAD = 1 << 0; 139 140 /** An immutable, empty conversation list */ 141 public static final Collection<Conversation> EMPTY = Collections.emptyList(); 142 143 @Override 144 public int describeContents() { 145 return 0; 146 } 147 148 @Override 149 public void writeToParcel(Parcel dest, int flags) { 150 dest.writeLong(id); 151 dest.writeParcelable(uri, flags); 152 dest.writeString(subject); 153 dest.writeLong(dateMs); 154 dest.writeString(snippet); 155 dest.writeByte(hasAttachments ? (byte) 1 : 0); 156 dest.writeParcelable(messageListUri, 0); 157 dest.writeString(senders); 158 dest.writeInt(numMessages); 159 dest.writeInt(numDrafts); 160 dest.writeInt(sendingState); 161 dest.writeInt(priority); 162 dest.writeByte(read ? (byte) 1 : 0); 163 dest.writeByte(starred ? (byte) 1 : 0); 164 dest.writeString(folderList); 165 dest.writeString(rawFolders); 166 dest.writeInt(convFlags); 167 dest.writeInt(personalLevel); 168 dest.writeInt(spam ? 1 : 0); 169 dest.writeInt(phishing ? 1 : 0); 170 dest.writeInt(muted ? 1 : 0); 171 dest.writeInt(color); 172 dest.writeParcelable(accountUri, 0); 173 } 174 175 private Conversation(Parcel in) { 176 id = in.readLong(); 177 uri = in.readParcelable(null); 178 subject = in.readString(); 179 dateMs = in.readLong(); 180 snippet = in.readString(); 181 hasAttachments = (in.readByte() != 0); 182 messageListUri = in.readParcelable(null); 183 senders = in.readString(); 184 numMessages = in.readInt(); 185 numDrafts = in.readInt(); 186 sendingState = in.readInt(); 187 priority = in.readInt(); 188 read = (in.readByte() != 0); 189 starred = (in.readByte() != 0); 190 folderList = in.readString(); 191 rawFolders = in.readString(); 192 convFlags = in.readInt(); 193 personalLevel = in.readInt(); 194 spam = in.readInt() != 0; 195 phishing = in.readInt() != 0; 196 muted = in.readInt() != 0; 197 color = in.readInt(); 198 accountUri = in.readParcelable(null); 199 position = NO_POSITION; 200 localDeleteOnUpdate = false; 201 } 202 203 @Override 204 public String toString() { 205 return "[conversation id=" + id + ", subject =" + subject + "]"; 206 } 207 208 public static final Creator<Conversation> CREATOR = new Creator<Conversation>() { 209 210 @Override 211 public Conversation createFromParcel(Parcel source) { 212 return new Conversation(source); 213 } 214 215 @Override 216 public Conversation[] newArray(int size) { 217 return new Conversation[size]; 218 } 219 220 }; 221 222 public static final Uri MOVE_CONVERSATIONS_URI = Uri.parse("content://moveconversations"); 223 224 public Conversation(Cursor cursor) { 225 if (cursor != null) { 226 id = cursor.getLong(UIProvider.CONVERSATION_ID_COLUMN); 227 uri = Uri.parse(cursor.getString(UIProvider.CONVERSATION_URI_COLUMN)); 228 dateMs = cursor.getLong(UIProvider.CONVERSATION_DATE_RECEIVED_MS_COLUMN); 229 subject = cursor.getString(UIProvider.CONVERSATION_SUBJECT_COLUMN); 230 // Don't allow null subject 231 if (subject == null) { 232 subject = ""; 233 } 234 snippet = cursor.getString(UIProvider.CONVERSATION_SNIPPET_COLUMN); 235 hasAttachments = cursor.getInt(UIProvider.CONVERSATION_HAS_ATTACHMENTS_COLUMN) != 0; 236 String messageList = cursor 237 .getString(UIProvider.CONVERSATION_MESSAGE_LIST_URI_COLUMN); 238 messageListUri = !TextUtils.isEmpty(messageList) ? Uri.parse(messageList) : null; 239 senders = cursor.getString(UIProvider.CONVERSATION_SENDER_INFO_COLUMN); 240 numMessages = cursor.getInt(UIProvider.CONVERSATION_NUM_MESSAGES_COLUMN); 241 numDrafts = cursor.getInt(UIProvider.CONVERSATION_NUM_DRAFTS_COLUMN); 242 sendingState = cursor.getInt(UIProvider.CONVERSATION_SENDING_STATE_COLUMN); 243 priority = cursor.getInt(UIProvider.CONVERSATION_PRIORITY_COLUMN); 244 read = cursor.getInt(UIProvider.CONVERSATION_READ_COLUMN) != 0; 245 starred = cursor.getInt(UIProvider.CONVERSATION_STARRED_COLUMN) != 0; 246 folderList = cursor.getString(UIProvider.CONVERSATION_FOLDER_LIST_COLUMN); 247 rawFolders = cursor.getString(UIProvider.CONVERSATION_RAW_FOLDERS_COLUMN); 248 convFlags = cursor.getInt(UIProvider.CONVERSATION_FLAGS_COLUMN); 249 personalLevel = cursor.getInt(UIProvider.CONVERSATION_PERSONAL_LEVEL_COLUMN); 250 spam = cursor.getInt(UIProvider.CONVERSATION_IS_SPAM_COLUMN) != 0; 251 phishing = cursor.getInt(UIProvider.CONVERSATION_IS_PHISHING_COLUMN) != 0; 252 muted = cursor.getInt(UIProvider.CONVERSATION_MUTED_COLUMN) != 0; 253 color = cursor.getInt(UIProvider.CONVERSATION_COLOR_COLUMN); 254 String account = cursor.getString(UIProvider.CONVERSATION_ACCOUNT_URI_COLUMN); 255 accountUri = !TextUtils.isEmpty(account) ? Uri.parse(account) : null; 256 position = NO_POSITION; 257 localDeleteOnUpdate = false; 258 } 259 } 260 261 public Conversation() { 262 } 263 264 public static Conversation create(long id, Uri uri, String subject, long dateMs, 265 String snippet, boolean hasAttachment, Uri messageListUri, String senders, 266 int numMessages, int numDrafts, int sendingState, int priority, boolean read, 267 boolean starred, String folderList, String rawFolders, int convFlags, 268 int personalLevel, boolean spam, boolean phishing, boolean muted, Uri accountUri) { 269 270 final Conversation conversation = new Conversation(); 271 272 conversation.id = id; 273 conversation.uri = uri; 274 conversation.subject = subject; 275 conversation.dateMs = dateMs; 276 conversation.snippet = snippet; 277 conversation.hasAttachments = hasAttachment; 278 conversation.messageListUri = messageListUri; 279 conversation.senders = senders; 280 conversation.numMessages = numMessages; 281 conversation.numDrafts = numDrafts; 282 conversation.sendingState = sendingState; 283 conversation.priority = priority; 284 conversation.read = read; 285 conversation.starred = starred; 286 conversation.folderList = folderList; 287 conversation.rawFolders = rawFolders; 288 conversation.convFlags = convFlags; 289 conversation.personalLevel = personalLevel; 290 conversation.spam = spam; 291 conversation.phishing = phishing; 292 conversation.muted = muted; 293 conversation.color = 0; 294 conversation.accountUri = accountUri; 295 return conversation; 296 } 297 298 @Override 299 public boolean equals(Object o) { 300 if (o instanceof Conversation) { 301 Conversation conv = (Conversation)o; 302 return conv.uri.equals(uri); 303 } 304 return false; 305 } 306 307 @Override 308 public int hashCode() { 309 return uri.hashCode(); 310 } 311 312 /** 313 * Get if this conversation is marked as high priority. 314 */ 315 public boolean isImportant() { 316 return priority == UIProvider.ConversationPriority.IMPORTANT; 317 } 318 319 /** 320 * Get if this conversation is mostly dead 321 */ 322 public boolean isMostlyDead() { 323 return (convFlags & FLAG_MOSTLY_DEAD) != 0; 324 } 325 326 /** 327 * Returns true if the URI of the conversation specified as the needle was found in the 328 * collection of conversations specified as the haystack. False otherwise. This method is safe 329 * to call with nullarguments. 330 * @param haystack 331 * @param needle 332 * @return true if the needle was found in the haystack, false otherwise. 333 */ 334 public final static boolean contains(Collection<Conversation> haystack, Conversation needle) { 335 // If the haystack is empty, it cannot contain anything. 336 if (haystack == null || haystack.size() <= 0) { 337 return false; 338 } 339 // The null folder exists everywhere. 340 if (needle == null) { 341 return true; 342 } 343 final long toFind = needle.id; 344 for (final Conversation c : haystack) { 345 if (toFind == c.id) { 346 return true; 347 } 348 } 349 return false; 350 } 351 352 /** 353 * Returns a collection of a single conversation. This method always returns a valid collection 354 * even if the input conversation is null. 355 * @param in a conversation, possibly null. 356 * @return a collection of the conversation. 357 */ 358 public static Collection<Conversation> listOf(Conversation in) { 359 final Collection<Conversation> target = (in == null) ? EMPTY : ImmutableList.of(in); 360 return target; 361 } 362 363 /** 364 * Create a human-readable string of all the conversations 365 * @param collection Any collection of conversations 366 * @return string with a human readable representation of the conversations. 367 */ 368 public static String toString(Collection<Conversation> collection) { 369 final StringBuilder out = new StringBuilder(collection.size() + " conversations:"); 370 int count = 0; 371 for (final Conversation c : collection) { 372 count++; 373 // Indent the conversations to make them easy to read in debug output. 374 out.append(" " + count + ": " + c.toString() + "\n"); 375 } 376 return out.toString(); 377 } 378}