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