Message.java revision 3842af9e8ba90ebf5b75dc5018bbfdfb2e044f99
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.content.AsyncQueryHandler; 20import android.content.ContentValues; 21import android.database.Cursor; 22import android.net.Uri; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.text.TextUtils; 26 27import com.android.mail.browse.MessageCursor; 28import com.android.mail.providers.UIProvider.MessageColumns; 29import com.android.mail.ui.AbstractActivityController; 30import com.android.mail.ui.ConversationListCallbacks; 31import com.android.mail.utils.Utils; 32 33import java.util.Collections; 34import java.util.List; 35 36 37public class Message implements Parcelable { 38 public long id; 39 public long serverId; 40 public Uri uri; 41 public String conversationUri; 42 public String subject; 43 public String snippet; 44 public String from; 45 public String to; 46 public String cc; 47 public String bcc; 48 public String replyTo; 49 public long dateReceivedMs; 50 public String bodyHtml; 51 public String bodyText; 52 public boolean embedsExternalResources; 53 public String refMessageId; 54 public int draftType; 55 public boolean appendRefMessageContent; 56 public boolean hasAttachments; 57 public Uri attachmentListUri; 58 public long messageFlags; 59 public String saveUri; 60 public String sendUri; 61 public boolean alwaysShowImages; 62 public boolean read; 63 public boolean starred; 64 public int quotedTextOffset; 65 public String attachmentsJson; 66 public Uri accountUri; 67 public Uri eventIntentUri; 68 69 private transient String[] mToAddresses = null; 70 private transient String[] mCcAddresses = null; 71 private transient String[] mBccAddresses = null; 72 private transient String[] mReplyToAddresses = null; 73 74 private transient List<Attachment> mAttachments = null; 75 76 // While viewing a list of messages, points to the cursor that contains it 77 private transient MessageCursor mOwningCursor = null; 78 private transient ConversationListCallbacks mListController = null; 79 80 @Override 81 public int describeContents() { 82 return 0; 83 } 84 85 @Override 86 public boolean equals(Object o) { 87 if (o == null || !(o instanceof Message)) { 88 return false; 89 } 90 final Uri otherUri = ((Message) o).uri; 91 if (uri == null) { 92 return (otherUri == null); 93 } 94 return uri.equals(otherUri); 95 } 96 97 @Override 98 public int hashCode() { 99 return uri == null ? 0 : uri.hashCode(); 100 } 101 102 @Override 103 public void writeToParcel(Parcel dest, int flags) { 104 dest.writeLong(id); 105 dest.writeLong(serverId); 106 dest.writeParcelable(uri, 0); 107 dest.writeString(conversationUri); 108 dest.writeString(subject); 109 dest.writeString(snippet); 110 dest.writeString(from); 111 dest.writeString(to); 112 dest.writeString(cc); 113 dest.writeString(bcc); 114 dest.writeString(replyTo); 115 dest.writeLong(dateReceivedMs); 116 dest.writeString(bodyHtml); 117 dest.writeString(bodyText); 118 dest.writeInt(embedsExternalResources ? 1 : 0); 119 dest.writeString(refMessageId); 120 dest.writeInt(draftType); 121 dest.writeInt(appendRefMessageContent ? 1 : 0); 122 dest.writeInt(hasAttachments ? 1 : 0); 123 dest.writeParcelable(attachmentListUri, 0); 124 dest.writeLong(messageFlags); 125 dest.writeString(saveUri); 126 dest.writeString(sendUri); 127 dest.writeInt(alwaysShowImages ? 1 : 0); 128 dest.writeInt(quotedTextOffset); 129 dest.writeString(attachmentsJson); 130 dest.writeParcelable(accountUri, 0); 131 dest.writeParcelable(eventIntentUri, 0); 132 } 133 134 private Message(Parcel in) { 135 id = in.readLong(); 136 serverId = in.readLong(); 137 uri = in.readParcelable(null); 138 conversationUri = in.readString(); 139 subject = in.readString(); 140 snippet = in.readString(); 141 from = in.readString(); 142 to = in.readString(); 143 cc = in.readString(); 144 bcc = in.readString(); 145 replyTo = in.readString(); 146 dateReceivedMs = in.readLong(); 147 bodyHtml = in.readString(); 148 bodyText = in.readString(); 149 embedsExternalResources = in.readInt() != 0; 150 refMessageId = in.readString(); 151 draftType = in.readInt(); 152 appendRefMessageContent = in.readInt() != 0; 153 hasAttachments = in.readInt() != 0; 154 attachmentListUri = in.readParcelable(null); 155 messageFlags = in.readLong(); 156 saveUri = in.readString(); 157 sendUri = in.readString(); 158 alwaysShowImages = in.readInt() != 0; 159 quotedTextOffset = in.readInt(); 160 attachmentsJson = in.readString(); 161 accountUri = in.readParcelable(null); 162 eventIntentUri = in.readParcelable(null); 163 } 164 165 public Message() { 166 167 } 168 169 @Override 170 public String toString() { 171 return "[message id=" + id + "]"; 172 } 173 174 public static final Creator<Message> CREATOR = new Creator<Message>() { 175 176 @Override 177 public Message createFromParcel(Parcel source) { 178 return new Message(source); 179 } 180 181 @Override 182 public Message[] newArray(int size) { 183 return new Message[size]; 184 } 185 186 }; 187 188 public Message(MessageCursor cursor, ConversationListCallbacks listController) { 189 this(cursor); 190 // Only set message cursor if appropriate 191 mOwningCursor = cursor; 192 mListController = listController; 193 } 194 195 public Message(Cursor cursor) { 196 if (cursor != null) { 197 id = cursor.getLong(UIProvider.MESSAGE_ID_COLUMN); 198 serverId = cursor.getLong(UIProvider.MESSAGE_SERVER_ID_COLUMN); 199 String message = cursor.getString(UIProvider.MESSAGE_URI_COLUMN); 200 uri = !TextUtils.isEmpty(message) ? Uri.parse(message) : null; 201 conversationUri = cursor.getString(UIProvider.MESSAGE_CONVERSATION_URI_COLUMN); 202 subject = cursor.getString(UIProvider.MESSAGE_SUBJECT_COLUMN); 203 snippet = cursor.getString(UIProvider.MESSAGE_SNIPPET_COLUMN); 204 from = cursor.getString(UIProvider.MESSAGE_FROM_COLUMN); 205 to = cursor.getString(UIProvider.MESSAGE_TO_COLUMN); 206 cc = cursor.getString(UIProvider.MESSAGE_CC_COLUMN); 207 bcc = cursor.getString(UIProvider.MESSAGE_BCC_COLUMN); 208 replyTo = cursor.getString(UIProvider.MESSAGE_REPLY_TO_COLUMN); 209 dateReceivedMs = cursor.getLong(UIProvider.MESSAGE_DATE_RECEIVED_MS_COLUMN); 210 bodyHtml = cursor.getString(UIProvider.MESSAGE_BODY_HTML_COLUMN); 211 bodyText = cursor.getString(UIProvider.MESSAGE_BODY_TEXT_COLUMN); 212 embedsExternalResources = cursor 213 .getInt(UIProvider.MESSAGE_EMBEDS_EXTERNAL_RESOURCES_COLUMN) != 0; 214 refMessageId = cursor.getString(UIProvider.MESSAGE_REF_MESSAGE_ID_COLUMN); 215 draftType = cursor.getInt(UIProvider.MESSAGE_DRAFT_TYPE_COLUMN); 216 appendRefMessageContent = cursor 217 .getInt(UIProvider.MESSAGE_APPEND_REF_MESSAGE_CONTENT_COLUMN) != 0; 218 hasAttachments = cursor.getInt(UIProvider.MESSAGE_HAS_ATTACHMENTS_COLUMN) != 0; 219 final String attachmentsUri = cursor 220 .getString(UIProvider.MESSAGE_ATTACHMENT_LIST_URI_COLUMN); 221 attachmentListUri = hasAttachments && !TextUtils.isEmpty(attachmentsUri) ? Uri 222 .parse(attachmentsUri) : null; 223 messageFlags = cursor.getLong(UIProvider.MESSAGE_FLAGS_COLUMN); 224 saveUri = cursor 225 .getString(UIProvider.MESSAGE_SAVE_URI_COLUMN); 226 sendUri = cursor 227 .getString(UIProvider.MESSAGE_SEND_URI_COLUMN); 228 alwaysShowImages = cursor.getInt(UIProvider.MESSAGE_ALWAYS_SHOW_IMAGES_COLUMN) != 0; 229 read = cursor.getInt(UIProvider.MESSAGE_READ_COLUMN) != 0; 230 starred = cursor.getInt(UIProvider.MESSAGE_STARRED_COLUMN) != 0; 231 quotedTextOffset = cursor.getInt(UIProvider.QUOTED_TEXT_OFFSET_COLUMN); 232 attachmentsJson = cursor.getString(UIProvider.MESSAGE_ATTACHMENTS_COLUMN); 233 String accountUriString = cursor.getString(UIProvider.MESSAGE_ACCOUNT_URI_COLUMN); 234 accountUri = !TextUtils.isEmpty(accountUriString) ? Uri.parse(accountUriString) : null; 235 eventIntentUri = 236 Utils.getValidUri(cursor.getString(UIProvider.MESSAGE_EVENT_INTENT_COLUMN)); 237 } 238 } 239 240 public boolean isFlaggedReplied() { 241 return (messageFlags & UIProvider.MessageFlags.REPLIED) == 242 UIProvider.MessageFlags.REPLIED; 243 } 244 245 public boolean isFlaggedForwarded() { 246 return (messageFlags & UIProvider.MessageFlags.FORWARDED) == 247 UIProvider.MessageFlags.FORWARDED; 248 } 249 250 public boolean isFlaggedCalendarInvite() { 251 return (messageFlags & UIProvider.MessageFlags.CALENDAR_INVITE) == 252 UIProvider.MessageFlags.CALENDAR_INVITE; 253 } 254 255 public synchronized String[] getToAddresses() { 256 if (mToAddresses == null) { 257 mToAddresses = Utils.splitCommaSeparatedString(to); 258 } 259 return mToAddresses; 260 } 261 262 public synchronized String[] getCcAddresses() { 263 if (mCcAddresses == null) { 264 mCcAddresses = Utils.splitCommaSeparatedString(cc); 265 } 266 return mCcAddresses; 267 } 268 269 public synchronized String[] getBccAddresses() { 270 if (mBccAddresses == null) { 271 mBccAddresses = Utils.splitCommaSeparatedString(bcc); 272 } 273 return mBccAddresses; 274 } 275 276 public synchronized String[] getReplyToAddresses() { 277 if (mReplyToAddresses == null) { 278 mReplyToAddresses = Utils.splitCommaSeparatedString(replyTo); 279 } 280 return mReplyToAddresses; 281 } 282 283 public synchronized List<Attachment> getAttachments() { 284 if (mAttachments == null) { 285 if (attachmentsJson != null) { 286 mAttachments = Attachment.fromJSONArray(attachmentsJson); 287 } else { 288 mAttachments = Collections.emptyList(); 289 } 290 } 291 return mAttachments; 292 } 293 294 /** 295 * Returns whether a "Show Pictures" button should initially appear for this message. If the 296 * button is shown, the message must also block all non-local images in the body. Inversely, if 297 * the button is not shown, the message must show all images within (or else the user would be 298 * stuck with no images and no way to reveal them). 299 * 300 * @return true if a "Show Pictures" button should appear. 301 */ 302 public boolean shouldShowImagePrompt() { 303 return embedsExternalResources && !alwaysShowImages; 304 } 305 306 /** 307 * Helper method to command a provider to mark all messages from this sender with the 308 * {@link MessageColumns#ALWAYS_SHOW_IMAGES} flag set. 309 * 310 * @param handler a caller-provided handler to run the query on 311 * @param token (optional) token to identify the command to the handler 312 * @param cookie (optional) cookie to pass to the handler 313 */ 314 public void markAlwaysShowImages(AsyncQueryHandler handler, int token, Object cookie) { 315 final ContentValues values = new ContentValues(1); 316 values.put(UIProvider.MessageColumns.ALWAYS_SHOW_IMAGES, 1); 317 318 handler.startUpdate(token, cookie, uri, values, null, null); 319 } 320 321 /** 322 * Helper method to command a provider to star/unstar this message. 323 * 324 * @param starred whether to star or unstar the message 325 * @param handler a caller-provided handler to run the query on 326 * @param token (optional) token to identify the command to the handler 327 * @param cookie (optional) cookie to pass to the handler 328 */ 329 public void star(boolean starred, AsyncQueryHandler handler, int token, Object cookie) { 330 this.starred = starred; 331 // If we're unstarring, we need to find out if the conversation is still starred 332 if (mListController != null) { 333 boolean conversationStarred = starred; 334 if (!starred) { 335 conversationStarred = mOwningCursor.isConversationStarred(); 336 } 337 // Update the conversation cursor so that changes are reflected simultaneously 338 mListController.sendConversationUriStarred( 339 AbstractActivityController.TAG_CONVERSATION_LIST, conversationUri, 340 conversationStarred, true /*local*/); 341 } 342 final ContentValues values = new ContentValues(1); 343 values.put(UIProvider.MessageColumns.STARRED, starred ? 1 : 0); 344 345 handler.startUpdate(token, cookie, uri, values, null, null); 346 } 347 348} 349