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