blob: bd38135ab66c053f67ef6c821fc2316102981282 [file] [log] [blame]
/**
* Copyright (c) 2012, Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mail.providers;
import android.content.ContentProviderClient;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import com.android.mail.browse.ConversationCursor.ConversationOperation;
import com.android.mail.browse.ConversationCursor.ConversationProvider;
import java.util.ArrayList;
import java.util.Collection;
public class Conversation implements Parcelable {
public static final int NO_POSITION = -1;
public long id;
public Uri uri;
public String subject;
public long dateMs;
public String snippet;
public boolean hasAttachments;
public Uri messageListUri;
public String senders;
public int numMessages;
public int numDrafts;
public int sendingState;
public int priority;
public boolean read;
public boolean starred;
public String folderList;
public String rawFolders;
// Used within the UI to indicate the adapter position of this conversation
public transient int position;
// Used within the UI to indicate that a Conversation should be removed from the
// ConversationCursor when executing an update, e.g. the the Conversation is no longer
// in the ConversationList for the current folder, that is it's now in some other folder(s)
public transient boolean localDeleteOnUpdate;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeParcelable(uri, flags);
dest.writeString(subject);
dest.writeLong(dateMs);
dest.writeString(snippet);
dest.writeByte(hasAttachments ? (byte) 1 : 0);
dest.writeParcelable(messageListUri, 0);
dest.writeString(senders);
dest.writeInt(numMessages);
dest.writeInt(numDrafts);
dest.writeInt(sendingState);
dest.writeInt(priority);
dest.writeByte(read ? (byte) 1 : 0);
dest.writeByte(starred ? (byte) 1 : 0);
dest.writeString(folderList);
dest.writeString(rawFolders);
}
private Conversation(Parcel in) {
id = in.readLong();
uri = in.readParcelable(null);
subject = in.readString();
dateMs = in.readLong();
snippet = in.readString();
hasAttachments = (in.readByte() != 0);
messageListUri = in.readParcelable(null);
senders = in.readString();
numMessages = in.readInt();
numDrafts = in.readInt();
sendingState = in.readInt();
priority = in.readInt();
read = (in.readByte() != 0);
starred = (in.readByte() != 0);
folderList = in.readString();
rawFolders = in.readString();
position = NO_POSITION;
localDeleteOnUpdate = false;
}
@Override
public String toString() {
return "[conversation id=" + id + "]";
}
public static final Creator<Conversation> CREATOR = new Creator<Conversation>() {
@Override
public Conversation createFromParcel(Parcel source) {
return new Conversation(source);
}
@Override
public Conversation[] newArray(int size) {
return new Conversation[size];
}
};
public Conversation(Cursor cursor) {
if (cursor != null) {
id = cursor.getLong(UIProvider.CONVERSATION_ID_COLUMN);
uri = Uri.parse(cursor.getString(UIProvider.CONVERSATION_URI_COLUMN));
dateMs = cursor.getLong(UIProvider.CONVERSATION_DATE_RECEIVED_MS_COLUMN);
subject = cursor.getString(UIProvider.CONVERSATION_SUBJECT_COLUMN);
// Don't allow null subject
if (subject == null) {
subject = "";
}
snippet = cursor.getString(UIProvider.CONVERSATION_SNIPPET_COLUMN);
hasAttachments = cursor.getInt(UIProvider.CONVERSATION_HAS_ATTACHMENTS_COLUMN) == 1;
String messageList = cursor
.getString(UIProvider.CONVERSATION_MESSAGE_LIST_URI_COLUMN);
messageListUri = !TextUtils.isEmpty(messageList) ? Uri.parse(messageList) : null;
senders = cursor.getString(UIProvider.CONVERSATION_SENDER_INFO_COLUMN);
numMessages = cursor.getInt(UIProvider.CONVERSATION_NUM_MESSAGES_COLUMN);
numDrafts = cursor.getInt(UIProvider.CONVERSATION_NUM_DRAFTS_COLUMN);
sendingState = cursor.getInt(UIProvider.CONVERSATION_SENDING_STATE_COLUMN);
priority = cursor.getInt(UIProvider.CONVERSATION_PRIORITY_COLUMN);
read = cursor.getInt(UIProvider.CONVERSATION_READ_COLUMN) == 1;
starred = cursor.getInt(UIProvider.CONVERSATION_STARRED_COLUMN) == 1;
folderList = cursor.getString(UIProvider.CONVERSATION_FOLDER_LIST_COLUMN);
rawFolders = cursor.getString(UIProvider.CONVERSATION_RAW_FOLDERS_COLUMN);
position = NO_POSITION;
localDeleteOnUpdate = false;
}
}
/**
* Get if this conversation is marked as high priority.
*/
public boolean isImportant() {
return priority == UIProvider.ConversationPriority.HIGH;
}
// Below are methods that update Conversation data (update/delete)
/**
* Update an integer column for a single conversation (see updateBoolean below)
*/
public int updateInt(Context context, String columnName, int value) {
ArrayList<Conversation> conversations = new ArrayList<Conversation>();
conversations.add(this);
return updateInt(context, conversations, columnName, value);
}
/**
* Update an integer column for a group of conversations (see updateValues below)
*/
public static int updateInt(Context context, Collection<Conversation> conversations,
String columnName, int value) {
ContentValues cv = new ContentValues();
cv.put(columnName, value);
return updateValues(context, conversations, cv);
}
/**
* Update a boolean column for a single conversation (see updateBoolean below)
*/
public int updateBoolean(Context context, String columnName, boolean value) {
ArrayList<Conversation> conversations = new ArrayList<Conversation>();
conversations.add(this);
return updateBoolean(context, conversations, columnName, value);
}
/**
* Update a string column for a group of conversations (see updateValues below)
*/
public static int updateBoolean(Context context, Collection<Conversation> conversations,
String columnName, boolean value) {
ContentValues cv = new ContentValues();
cv.put(columnName, value);
return updateValues(context, conversations, cv);
}
/**
* Update a string column for a single conversation (see updateString below)
*/
public int updateString(Context context, String columnName, String value) {
ArrayList<Conversation> conversations = new ArrayList<Conversation>();
conversations.add(this);
return updateString(context, conversations, columnName, value);
}
/**
* Update a string column for a group of conversations (see updateValues below)
*/
public static int updateString(Context context, Collection<Conversation> conversations,
String columnName, String value) {
ContentValues cv = new ContentValues();
cv.put(columnName, value);
return updateValues(context, conversations, cv);
}
/**
* Update a boolean column for a group of conversations, immediately in the UI and in a single
* transaction in the underlying provider
* @param conversations a collection of conversations
* @param context the caller's context
* @param columnName the column to update
* @param value the new value
* @return the sequence number of the operation (for undo)
*/
private static int updateValues(Context context, Collection<Conversation> conversations,
ContentValues values) {
ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
for (Conversation conv: conversations) {
ConversationOperation op =
new ConversationOperation(ConversationOperation.UPDATE, conv, values);
ops.add(op);
}
return apply(context, ops);
}
/**
* Delete a single conversation
* @param context the caller's context
* @return the sequence number of the operation (for undo)
*/
public int delete(Context context) {
ArrayList<Conversation> conversations = new ArrayList<Conversation>();
conversations.add(this);
return delete(context, conversations);
}
/**
* Delete a group of conversations immediately in the UI and in a single transaction in the
* underlying provider
* @param context the caller's context
* @param conversations a collection of conversations
* @return the sequence number of the operation (for undo)
*/
public static int delete(Context context, Collection<Conversation> conversations) {
ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
for (Conversation conv: conversations) {
ConversationOperation op =
new ConversationOperation(ConversationOperation.DELETE, conv);
ops.add(op);
}
return apply(context, ops);
}
// Convenience methods
private static int apply(Context context, ArrayList<ConversationOperation> operations) {
ContentProviderClient client =
context.getContentResolver().acquireContentProviderClient(
ConversationProvider.AUTHORITY);
try {
ConversationProvider cp = (ConversationProvider)client.getLocalContentProvider();
return cp.apply(operations);
} finally {
client.release();
}
}
public static void undo(final Context context, final Uri undoUri) {
new Thread(new Runnable() {
@Override
public void run() {
Cursor c = context.getContentResolver().query(undoUri, UIProvider.UNDO_PROJECTION,
null, null, null);
if (c != null) {
c.close();
}
}
}).start();
}
public static int archive(Context context, Collection<Conversation> conversations) {
ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
for (Conversation conv: conversations) {
ConversationOperation op =
new ConversationOperation(ConversationOperation.ARCHIVE, conv);
ops.add(op);
}
return apply(context, ops);
}
public static int mute(Context context, Collection<Conversation> conversations) {
ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
for (Conversation conv: conversations) {
ConversationOperation op =
new ConversationOperation(ConversationOperation.MUTE, conv);
ops.add(op);
}
return apply(context, ops);
}
public static int reportSpam(Context context, Collection<Conversation> conversations) {
ArrayList<ConversationOperation> ops = new ArrayList<ConversationOperation>();
for (Conversation conv: conversations) {
ConversationOperation op =
new ConversationOperation(ConversationOperation.REPORT_SPAM, conv);
ops.add(op);
}
return apply(context, ops);
}
}