Conversation.java revision 7dd054e39986de84a213c56a3c11ac94731402e6
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 com.google.common.collect.ImmutableList;
20
21import android.database.Cursor;
22import android.net.Uri;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.text.TextUtils;
26
27import java.util.Collection;
28import java.util.Collections;
29
30public class Conversation implements Parcelable {
31    public static final int NO_POSITION = -1;
32
33    public long id;
34    public Uri uri;
35    public String subject;
36    public long dateMs;
37    public String snippet;
38    public boolean hasAttachments;
39    public Uri messageListUri;
40    public String senders;
41    public int numMessages;
42    public int numDrafts;
43    public int sendingState;
44    public int priority;
45    public boolean read;
46    public boolean starred;
47    public String folderList;
48    public String rawFolders;
49    public int convFlags;
50    public int personalLevel;
51    public boolean spam;
52    public boolean muted;
53    public int color;
54
55    // Used within the UI to indicate the adapter position of this conversation
56    public transient int position;
57    // Used within the UI to indicate that a Conversation should be removed from the
58    // ConversationCursor when executing an update, e.g. the the Conversation is no longer
59    // in the ConversationList for the current folder, that is it's now in some other folder(s)
60    public transient boolean localDeleteOnUpdate;
61
62    // Constituents of convFlags below
63    // Flag indicating that the item has been deleted, but will continue being shown in the list
64    // Delete/Archive of a mostly-dead item will NOT propagate the delete/archive, but WILL remove
65    // the item from the cursor
66    public static final int FLAG_MOSTLY_DEAD = 1 << 0;
67
68    /** An immutable, empty conversation list */
69    public static final Collection<Conversation> EMPTY = Collections.emptyList();
70
71    @Override
72    public int describeContents() {
73        return 0;
74    }
75
76    @Override
77    public void writeToParcel(Parcel dest, int flags) {
78        dest.writeLong(id);
79        dest.writeParcelable(uri, flags);
80        dest.writeString(subject);
81        dest.writeLong(dateMs);
82        dest.writeString(snippet);
83        dest.writeByte(hasAttachments ? (byte) 1 : 0);
84        dest.writeParcelable(messageListUri, 0);
85        dest.writeString(senders);
86        dest.writeInt(numMessages);
87        dest.writeInt(numDrafts);
88        dest.writeInt(sendingState);
89        dest.writeInt(priority);
90        dest.writeByte(read ? (byte) 1 : 0);
91        dest.writeByte(starred ? (byte) 1 : 0);
92        dest.writeString(folderList);
93        dest.writeString(rawFolders);
94        dest.writeInt(convFlags);
95        dest.writeInt(personalLevel);
96        dest.writeInt(spam ? 1 : 0);
97        dest.writeInt(muted ? 1 : 0);
98        dest.writeInt(color);
99    }
100
101    private Conversation(Parcel in) {
102        id = in.readLong();
103        uri = in.readParcelable(null);
104        subject = in.readString();
105        dateMs = in.readLong();
106        snippet = in.readString();
107        hasAttachments = (in.readByte() != 0);
108        messageListUri = in.readParcelable(null);
109        senders = in.readString();
110        numMessages = in.readInt();
111        numDrafts = in.readInt();
112        sendingState = in.readInt();
113        priority = in.readInt();
114        read = (in.readByte() != 0);
115        starred = (in.readByte() != 0);
116        folderList = in.readString();
117        rawFolders = in.readString();
118        convFlags = in.readInt();
119        personalLevel = in.readInt();
120        spam = in.readInt() != 0;
121        muted = in.readInt() != 0;
122        color = in.readInt();
123        position = NO_POSITION;
124        localDeleteOnUpdate = false;
125    }
126
127    @Override
128    public String toString() {
129        return "[conversation id=" + id + ", subject =" + subject + "]";
130    }
131
132    public static final Creator<Conversation> CREATOR = new Creator<Conversation>() {
133
134        @Override
135        public Conversation createFromParcel(Parcel source) {
136            return new Conversation(source);
137        }
138
139        @Override
140        public Conversation[] newArray(int size) {
141            return new Conversation[size];
142        }
143
144    };
145
146    public static final Uri MOVE_CONVERSATIONS_URI = Uri.parse("content://moveconversations");
147
148    public Conversation(Cursor cursor) {
149        if (cursor != null) {
150            id = cursor.getLong(UIProvider.CONVERSATION_ID_COLUMN);
151            uri = Uri.parse(cursor.getString(UIProvider.CONVERSATION_URI_COLUMN));
152            dateMs = cursor.getLong(UIProvider.CONVERSATION_DATE_RECEIVED_MS_COLUMN);
153            subject = cursor.getString(UIProvider.CONVERSATION_SUBJECT_COLUMN);
154            // Don't allow null subject
155            if (subject == null) {
156                subject = "";
157            }
158            snippet = cursor.getString(UIProvider.CONVERSATION_SNIPPET_COLUMN);
159            hasAttachments = cursor.getInt(UIProvider.CONVERSATION_HAS_ATTACHMENTS_COLUMN) != 0;
160            String messageList = cursor
161                    .getString(UIProvider.CONVERSATION_MESSAGE_LIST_URI_COLUMN);
162            messageListUri = !TextUtils.isEmpty(messageList) ? Uri.parse(messageList) : null;
163            senders = cursor.getString(UIProvider.CONVERSATION_SENDER_INFO_COLUMN);
164            numMessages = cursor.getInt(UIProvider.CONVERSATION_NUM_MESSAGES_COLUMN);
165            numDrafts = cursor.getInt(UIProvider.CONVERSATION_NUM_DRAFTS_COLUMN);
166            sendingState = cursor.getInt(UIProvider.CONVERSATION_SENDING_STATE_COLUMN);
167            priority = cursor.getInt(UIProvider.CONVERSATION_PRIORITY_COLUMN);
168            read = cursor.getInt(UIProvider.CONVERSATION_READ_COLUMN) != 0;
169            starred = cursor.getInt(UIProvider.CONVERSATION_STARRED_COLUMN) != 0;
170            folderList = cursor.getString(UIProvider.CONVERSATION_FOLDER_LIST_COLUMN);
171            rawFolders = cursor.getString(UIProvider.CONVERSATION_RAW_FOLDERS_COLUMN);
172            convFlags = cursor.getInt(UIProvider.CONVERSATION_FLAGS_COLUMN);
173            personalLevel = cursor.getInt(UIProvider.CONVERSATION_PERSONAL_LEVEL_COLUMN);
174            spam = cursor.getInt(UIProvider.CONVERSATION_IS_SPAM_COLUMN) != 0;
175            muted = cursor.getInt(UIProvider.CONVERSATION_MUTED_COLUMN) != 0;
176            color = cursor.getInt(UIProvider.CONVERSATION_COLOR_COLUMN);
177            position = NO_POSITION;
178            localDeleteOnUpdate = false;
179        }
180    }
181
182    public Conversation() {
183    }
184
185    public static Conversation create(long id, Uri uri, String subject, long dateMs,
186            String snippet, boolean hasAttachment, Uri messageListUri, String senders,
187            int numMessages, int numDrafts, int sendingState, int priority, boolean read,
188            boolean starred, String folderList, String rawFolders, int convFlags,
189            int personalLevel, boolean spam, boolean muted) {
190
191        final Conversation conversation = new Conversation();
192
193        conversation.id = id;
194        conversation.uri = uri;
195        conversation.subject = subject;
196        conversation.dateMs = dateMs;
197        conversation.snippet = snippet;
198        conversation.hasAttachments = hasAttachment;
199        conversation.messageListUri = messageListUri;
200        conversation.senders = senders;
201        conversation.numMessages = numMessages;
202        conversation.numDrafts = numDrafts;
203        conversation.sendingState = sendingState;
204        conversation.priority = priority;
205        conversation.read = read;
206        conversation.starred = starred;
207        conversation.folderList = folderList;
208        conversation.rawFolders = rawFolders;
209        conversation.convFlags = convFlags;
210        conversation.personalLevel = personalLevel;
211        conversation.spam = spam;
212        conversation.muted = muted;
213        conversation.color = 0;
214        return conversation;
215    }
216
217    @Override
218    public boolean equals(Object o) {
219        if (o instanceof Conversation) {
220            Conversation conv = (Conversation)o;
221            return conv.uri.equals(uri);
222        }
223        return false;
224    }
225
226    @Override
227    public int hashCode() {
228        return uri.hashCode();
229    }
230
231    /**
232     * Get if this conversation is marked as high priority.
233     */
234    public boolean isImportant() {
235        return priority == UIProvider.ConversationPriority.IMPORTANT;
236    }
237
238    /**
239     * Get if this conversation is mostly dead
240     */
241    public boolean isMostlyDead() {
242        return (convFlags & FLAG_MOSTLY_DEAD) != 0;
243    }
244
245    /**
246     * Returns true if the URI of the conversation specified as the needle was found in the
247     * collection of conversations specified as the haystack. False otherwise. This method is safe
248     * to call with nullarguments.
249     * @param haystack
250     * @param needle
251     * @return true if the needle was found in the haystack, false otherwise.
252     */
253    public final static boolean contains(Collection<Conversation> haystack, Conversation needle) {
254        // If the haystack is empty, it cannot contain anything.
255        if (haystack == null || haystack.size() <= 0) {
256            return false;
257        }
258        // The null folder exists everywhere.
259        if (needle == null) {
260            return true;
261        }
262        final long toFind = needle.id;
263        for (final Conversation c : haystack) {
264            if (toFind == c.id) {
265                return true;
266            }
267        }
268        return false;
269    }
270
271    /**
272     * Returns a collection of a single conversation. This method always returns a valid collection
273     * even if the input conversation is null.
274     * @param in a conversation, possibly null.
275     * @return a collection of the conversation.
276     */
277    public static Collection<Conversation> listOf(Conversation in) {
278        final Collection<Conversation> target = (in == null) ? EMPTY : ImmutableList.of(in);
279        return target;
280    }
281
282    /**
283     * Create a human-readable string of all the conversations
284     * @param collection Any collection of conversations
285     * @return string with a human readable representation of the conversations.
286     */
287    public static String toString(Collection<Conversation> collection) {
288        final StringBuilder out = new StringBuilder(collection.size() + " conversations:");
289        int count = 0;
290        for (final Conversation c : collection) {
291            count++;
292            // Indent the conversations to make them easy to read in debug output.
293            out.append("      " + count + ": " + c.toString() + "\n");
294        }
295        return out.toString();
296    }
297}