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