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