MessageView: next/prev navigation.

in addition:
- fix AND-OR precedence in cursor query in MessageList.
- move special mailbox ids from MessageList to Mailbox
- move shared code from MessageList to com.android.email.Utility
- add invisible prev/next to landscape in order to avoid special-case in code
- select mailbox list using IN() instead of list of OR

Note:  Checked in by Andy to facilitate further work on MessageView.

Change-Id:	I8049be2b45fed1e4e697a0ed895492c4d0e59e0a
This commit is contained in:
Andrew Stadler 2009-08-24 15:00:45 -07:00
parent dad47808e9
commit e1f0b0a9bc
8 changed files with 241 additions and 190 deletions

View File

@ -31,7 +31,19 @@
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1">
<!-- put invisible views for prev/next in order to not special-case the lanscape in code -->
<FrameLayout
android:visibility="gone"
android:layout_width="0dip"
android:layout_height="0dip">
<View
android:id="@+id/previous"
android:layout_width="0dip"
android:layout_height="0dip" />
<View android:id="@+id/next"
android:layout_width="0dip"
android:layout_height="0dip" />
</FrameLayout>
<include layout="@layout/message_view_header" />
</LinearLayout>

View File

@ -16,6 +16,15 @@
package com.android.email;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Mailbox;
import com.android.email.provider.EmailContent.MailboxColumns;
import com.android.email.provider.EmailContent.Message;
import com.android.email.provider.EmailContent.MessageColumns;
import android.content.ContentResolver;
import android.database.Cursor;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@ -221,4 +230,47 @@ public class Utility {
// }
// }
}
// TODO: unit test this
public static String buildMailboxIdSelection(ContentResolver resolver, long mailboxId) {
// Setup default selection & args, then add to it as necessary
StringBuilder selection = new StringBuilder(
Message.FLAG_LOADED + "!=" + Message.NOT_LOADED + " AND ");
if (mailboxId == Mailbox.QUERY_ALL_INBOXES
|| mailboxId == Mailbox.QUERY_ALL_DRAFTS
|| mailboxId == Mailbox.QUERY_ALL_OUTBOX) {
// query for all mailboxes of type INBOX, DRAFTS, or OUTBOX
int type;
if (mailboxId == Mailbox.QUERY_ALL_INBOXES) {
type = Mailbox.TYPE_INBOX;
} else if (mailboxId == Mailbox.QUERY_ALL_DRAFTS) {
type = Mailbox.TYPE_DRAFTS;
} else {
type = Mailbox.TYPE_OUTBOX;
}
StringBuilder inboxes = new StringBuilder();
Cursor c = resolver.query(Mailbox.CONTENT_URI,
EmailContent.ID_PROJECTION,
MailboxColumns.TYPE + "=? AND " + MailboxColumns.FLAG_VISIBLE + "=1",
new String[] { Integer.toString(type) }, null);
// build an IN (mailboxId, ...) list
// TODO do this directly in the provider
while (c.moveToNext()) {
if (inboxes.length() != 0) {
inboxes.append(",");
}
inboxes.append(c.getLong(EmailContent.ID_PROJECTION_COLUMN));
}
c.close();
selection.append(MessageColumns.MAILBOX_KEY + " IN ");
selection.append("(").append(inboxes).append(")");
} else if (mailboxId == Mailbox.QUERY_ALL_UNREAD) {
selection.append(Message.FLAG_READ + "=0");
} else if (mailboxId == Mailbox.QUERY_ALL_FAVORITES) {
selection.append(Message.FLAG_FAVORITE + "=1");
} else {
selection.append(MessageColumns.MAILBOX_KEY + "=" + mailboxId);
}
return selection.toString();
}
}

View File

@ -290,7 +290,7 @@ public class AccountFolderList extends ListActivity
count = getUnreadCountByMailboxType(this, Mailbox.TYPE_INBOX);
if (count > 0) {
row = childCursor.newRow();
row.add(Long.valueOf(MessageList.QUERY_ALL_INBOXES)); // MAILBOX_COLUMN_ID = 0;
row.add(Long.valueOf(Mailbox.QUERY_ALL_INBOXES)); // MAILBOX_COLUMN_ID = 0;
row.add(getString(R.string.account_folder_list_summary_inbox)); // MAILBOX_DISPLAY_NAME
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
row.add(Integer.valueOf(Mailbox.TYPE_INBOX)); // MAILBOX_TYPE = 3;
@ -301,7 +301,7 @@ public class AccountFolderList extends ListActivity
count = EmailContent.count(this, Message.CONTENT_URI, FAVORITE_COUNT_SELECTION, null);
if (count > 0) {
row = childCursor.newRow();
row.add(Long.valueOf(MessageList.QUERY_ALL_FAVORITES)); // MAILBOX_COLUMN_ID = 0;
row.add(Long.valueOf(Mailbox.QUERY_ALL_FAVORITES)); // MAILBOX_COLUMN_ID = 0;
// MAILBOX_DISPLAY_NAME
row.add(getString(R.string.account_folder_list_summary_favorite));
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
@ -312,7 +312,7 @@ public class AccountFolderList extends ListActivity
count = getUnreadCountByMailboxType(this, Mailbox.TYPE_DRAFTS);
if (count > 0) {
row = childCursor.newRow();
row.add(Long.valueOf(MessageList.QUERY_ALL_DRAFTS)); // MAILBOX_COLUMN_ID = 0;
row.add(Long.valueOf(Mailbox.QUERY_ALL_DRAFTS)); // MAILBOX_COLUMN_ID = 0;
row.add(getString(R.string.account_folder_list_summary_drafts));// MAILBOX_DISPLAY_NAME
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
row.add(Integer.valueOf(Mailbox.TYPE_DRAFTS)); // MAILBOX_TYPE = 3;
@ -322,7 +322,7 @@ public class AccountFolderList extends ListActivity
count = getUnreadCountByMailboxType(this, Mailbox.TYPE_OUTBOX);
if (count > 0) {
row = childCursor.newRow();
row.add(Long.valueOf(MessageList.QUERY_ALL_OUTBOX)); // MAILBOX_COLUMN_ID = 0;
row.add(Long.valueOf(Mailbox.QUERY_ALL_OUTBOX)); // MAILBOX_COLUMN_ID = 0;
row.add(getString(R.string.account_folder_list_summary_outbox));// MAILBOX_DISPLAY_NAME
row.add(null); // MAILBOX_ACCOUNT_KEY = 2;
row.add(Integer.valueOf(Mailbox.TYPE_OUTBOX)); // MAILBOX_TYPE = 3;

View File

@ -818,7 +818,8 @@ public class FolderMessageList extends ExpandableListActivity {
for (MessageInfoHolder holder : folder.messages) {
folderUids.add(holder.uid);
}
MessageView.actionView(this, mAccountId, folder.name, message.uid, folderUids);
// deprecated
// MessageView.actionView(this, mAccountId, folder.name, message.uid, folderUids);
}
}
@ -841,7 +842,7 @@ public class FolderMessageList extends ExpandableListActivity {
// TODO - save enough data to recreate the cursor, to enable prev/next in MessageView
int messageIdColumn = messageCursor.getColumnIndex(EmailContent.RECORD_ID);
long messageId = messageCursor.getLong(messageIdColumn);
MessageView.actionView(this, messageId);
MessageView.actionView(this, messageId, -1);
}
}

View File

@ -68,16 +68,6 @@ import java.util.HashSet;
import java.util.Set;
public class MessageList extends ListActivity implements OnItemClickListener, OnClickListener {
// Magic mailbox ID's
// NOTE: This is a quick solution for merged mailboxes. I would rather implement this
// with a more generic way of packaging and sharing queries between activities
public static final long QUERY_ALL_INBOXES = -2;
public static final long QUERY_ALL_UNREAD = -3;
public static final long QUERY_ALL_FAVORITES = -4;
public static final long QUERY_ALL_DRAFTS = -5;
public static final long QUERY_ALL_OUTBOX = -6;
// Intent extras (internal to this activity)
private static final String EXTRA_ACCOUNT_ID = "com.android.email.activity._ACCOUNT_ID";
private static final String EXTRA_MAILBOX_TYPE = "com.android.email.activity.MAILBOX_TYPE";
@ -139,12 +129,6 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
private SetTitleTask mSetTitleTask;
private SetFooterTask mSetFooterTask;
/**
* Reduced mailbox projection used to hunt for inboxes
* TODO: remove this and implement a custom URI
*/
public final static int MAILBOX_FIND_INBOX_COLUMN_ID = 0;
public final static String[] MAILBOX_FIND_INBOX_PROJECTION = new String[] {
EmailContent.RECORD_ID, MailboxColumns.TYPE, MailboxColumns.FLAG_VISIBLE
};
@ -491,7 +475,7 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
if (mailbox.mType == EmailContent.Mailbox.TYPE_DRAFTS) {
MessageCompose.actionEditDraft(this, messageId);
} else {
MessageView.actionView(this, messageId);
MessageView.actionView(this, messageId, mailboxId);
}
}
@ -671,12 +655,14 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
*/
private void addFooterView(long mailboxId, long accountId, int mailboxType) {
// first, look for shortcuts that don't need us to spin up a DB access task
if (mailboxId == QUERY_ALL_INBOXES || mailboxId == QUERY_ALL_UNREAD
|| mailboxId == QUERY_ALL_FAVORITES || mailboxId == QUERY_ALL_DRAFTS) {
if (mailboxId == Mailbox.QUERY_ALL_INBOXES
|| mailboxId == Mailbox.QUERY_ALL_UNREAD
|| mailboxId == Mailbox.QUERY_ALL_FAVORITES
|| mailboxId == Mailbox.QUERY_ALL_DRAFTS) {
finishFooterView(LIST_FOOTER_MODE_REFRESH);
return;
}
if (mailboxId == QUERY_ALL_OUTBOX || mailboxType == Mailbox.TYPE_OUTBOX) {
if (mailboxId == Mailbox.QUERY_ALL_OUTBOX || mailboxType == Mailbox.TYPE_OUTBOX) {
finishFooterView(LIST_FOOTER_MODE_SEND);
return;
}
@ -879,60 +865,14 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
@Override
protected Cursor doInBackground(Void... params) {
// Setup default selection & args, then add to it as necessary
StringBuilder selection = new StringBuilder(
Message.FLAG_LOADED + "!=" + Message.NOT_LOADED + " AND ");
String[] selArgs = null;
if (mMailboxKey == QUERY_ALL_INBOXES || mMailboxKey == QUERY_ALL_DRAFTS ||
mMailboxKey == QUERY_ALL_OUTBOX) {
// query for all mailboxes of type INBOX, DRAFTS, or OUTBOX
int type;
if (mMailboxKey == QUERY_ALL_INBOXES) {
type = Mailbox.TYPE_INBOX;
} else if (mMailboxKey == QUERY_ALL_DRAFTS) {
type = Mailbox.TYPE_DRAFTS;
} else {
type = Mailbox.TYPE_OUTBOX;
}
StringBuilder inboxes = new StringBuilder();
Cursor c = MessageList.this.mResolver.query(
Mailbox.CONTENT_URI,
MAILBOX_FIND_INBOX_PROJECTION,
MailboxColumns.TYPE + "=? AND " + MailboxColumns.FLAG_VISIBLE + "=1",
new String[] { Integer.toString(type) }, null);
// build a long WHERE list
// TODO do this directly in the provider
while (c.moveToNext()) {
if (inboxes.length() != 0) {
inboxes.append(" OR ");
}
inboxes.append(MessageColumns.MAILBOX_KEY + "=");
inboxes.append(c.getLong(MAILBOX_FIND_INBOX_COLUMN_ID));
}
c.close();
// This is a hack - if there were no matching mailboxes, the empty selection string
// would match *all* messages. Instead, force a "non-matching" selection, which
// generates an empty Message cursor.
// TODO: handle this properly when we move the compound lookup into the provider
if (inboxes.length() == 0) {
inboxes.append(Message.RECORD_ID + "=-1");
}
// make that the selection
selection.append(inboxes);
} else if (mMailboxKey == QUERY_ALL_UNREAD) {
selection.append(Message.FLAG_READ + "=0");
} else if (mMailboxKey == QUERY_ALL_FAVORITES) {
selection.append(Message.FLAG_FAVORITE + "=1");
} else {
selection.append(MessageColumns.MAILBOX_KEY + "=?");
selArgs = new String[] { String.valueOf(mMailboxKey) };
}
return MessageList.this.managedQuery(
String selection =
Utility.buildMailboxIdSelection(MessageList.this.mResolver, mMailboxKey);
Cursor c = MessageList.this.managedQuery(
EmailContent.Message.CONTENT_URI,
MessageList.this.mListAdapter.PROJECTION,
selection.toString(), selArgs,
selection, null,
EmailContent.MessageColumns.TIMESTAMP + " DESC");
return c;
}
@Override
@ -945,7 +885,7 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
}
// Reset the "new messages" count in the service, since we're seeing them now
if (mMailboxKey == QUERY_ALL_INBOXES) {
if (mMailboxKey == Mailbox.QUERY_ALL_INBOXES) {
MailService.resetNewMessageCount(MessageList.this, -1);
} else if (mMailboxKey >= 0 && mAccountKey != -1) {
MailService.resetNewMessageCount(MessageList.this, mAccountKey);
@ -964,16 +904,16 @@ public class MessageList extends ListActivity implements OnItemClickListener, On
@Override
protected String[] doInBackground(Void... params) {
// Check special Mailboxes
if (mMailboxKey == MessageList.QUERY_ALL_INBOXES) {
if (mMailboxKey == Mailbox.QUERY_ALL_INBOXES) {
return new String[] {null,
getString(R.string.account_folder_list_summary_inbox)};
} else if (mMailboxKey == MessageList.QUERY_ALL_FAVORITES) {
} else if (mMailboxKey == Mailbox.QUERY_ALL_FAVORITES) {
return new String[] {null,
getString(R.string.account_folder_list_summary_favorite)};
} else if (mMailboxKey == MessageList.QUERY_ALL_DRAFTS) {
} else if (mMailboxKey == Mailbox.QUERY_ALL_DRAFTS) {
return new String[] {null,
getString(R.string.account_folder_list_summary_drafts)};
} else if (mMailboxKey == MessageList.QUERY_ALL_OUTBOX) {
} else if (mMailboxKey == Mailbox.QUERY_ALL_OUTBOX) {
return new String[] {null,
getString(R.string.account_folder_list_summary_outbox)};
}

View File

@ -27,6 +27,7 @@ import com.android.email.mail.MessagingException;
import com.android.email.mail.internet.EmailHtmlUtil;
import com.android.email.mail.internet.MimeUtility;
import com.android.email.provider.AttachmentProvider;
import com.android.email.provider.EmailContent;
import com.android.email.provider.EmailContent.Account;
import com.android.email.provider.EmailContent.Attachment;
import com.android.email.provider.EmailContent.Body;
@ -83,10 +84,7 @@ public class MessageView extends Activity
implements OnClickListener {
private static final String EXTRA_MESSAGE_ID = "com.android.email.MessageView_message_id";
private static final String EXTRA_ACCOUNT_ID = "com.android.email.MessageView_account_id";
private static final String EXTRA_FOLDER = "com.android.email.MessageView_folder";
private static final String EXTRA_MESSAGE = "com.android.email.MessageView_message";
private static final String EXTRA_FOLDER_UIDS = "com.android.email.MessageView_folderUids";
private static final String EXTRA_NEXT = "com.android.email.MessageView_next";
private static final String EXTRA_MAILBOX_ID = "com.android.email.MessageView_mailbox_id";
private static final String[] METHODS_WITH_PRESENCE_PROJECTION = new String[] {
People.ContactMethods._ID, // 0
@ -127,6 +125,7 @@ public class MessageView extends Activity
private long mAccountId;
private Account mAccount;
private long mMessageId;
private long mMailboxId;
private Message mMessage;
private LoadMessageTask mLoadMessageTask;
@ -139,7 +138,6 @@ public class MessageView extends Activity
private String mFolder;
private String mMessageUid;
private Cursor mMessageListCursor;
private java.text.DateFormat mDateFormat;
private java.text.DateFormat mTimeFormat;
@ -151,6 +149,11 @@ public class MessageView extends Activity
private MessageViewHandler mHandler = new MessageViewHandler();
private ControllerResults mControllerCallback = new ControllerResults();
private View mPrevious;
private View mNext;
private LoadPrevNextTask mLoadPrevNextTask;
private Cursor mPrevNextCursor;
class MessageViewHandler extends Handler {
private static final int MSG_ATTACHMENT_PROGRESS = 2;
private static final int MSG_SET_ATTACHMENTS_ENABLED = 4;
@ -335,41 +338,60 @@ public class MessageView extends Activity
/**
* View a specific message found in the Email provider.
*
* TODO: Find a way to pass a cursor so we can iterator prev/next as well
* @param messageId the message to view.
* @param mailboxId identifies the sequence of messages used for prev/next navigation.
*/
public static void actionView(Context context, long messageId) {
public static void actionView(Context context, long messageId, long mailboxId) {
Intent i = new Intent(context, MessageView.class);
i.putExtra(EXTRA_MESSAGE_ID, messageId);
i.putExtra(EXTRA_MAILBOX_ID, mailboxId);
context.startActivity(i);
}
@Deprecated
public static void actionView(Context context, long accountId,
String folder, String messageUid, ArrayList<String> folderUids) {
actionView(context, accountId, folder, messageUid, folderUids, null);
/**
* Re-init everything needed for changing message.
*/
private void messageChanged() {
cancelAllTasks();
setTitle("");
mAttachments.setVisibility(View.GONE);
mAttachmentIcon.setVisibility(View.GONE);
// are the text clear below needed?
// likely they only add flicker as the new message is displayed quickly
// mSubjectView.setText(null);
// mFromView.setText(null);
// mTimeView.setText(null);
// mDateView.setText(null);
// mToView.setText(null);
// mCcView.setText(null);
// Start an AsyncTask to make a new cursor and load the message
mLoadMessageTask = new LoadMessageTask(mMessageId);
mLoadMessageTask.execute();
updatePrevNextArrows(mPrevNextCursor);
}
@Deprecated
public static void actionView(Context context, long accountId,
String folder, String messageUid, ArrayList<String> folderUids, Bundle extras) {
Intent i = new Intent(context, MessageView.class);
i.putExtra(EXTRA_ACCOUNT_ID, accountId);
i.putExtra(EXTRA_FOLDER, folder);
i.putExtra(EXTRA_MESSAGE, messageUid);
i.putExtra(EXTRA_FOLDER_UIDS, folderUids);
if (extras != null) {
i.putExtras(extras);
private void updatePrevNextArrows(Cursor cursor) {
if (cursor != null) {
boolean hasPrev, hasNext;
if (cursor.isAfterLast() || cursor.isBeforeFirst()) {
// The cursor not being on a message means that the current message was not found.
// While this should not happen, simply disable prev/next arrows in that case.
hasPrev = hasNext = false;
} else {
hasPrev = !cursor.isFirst();
hasNext = !cursor.isLast();
}
mPrevious.setVisibility(hasPrev ? View.VISIBLE : View.GONE);
mNext.setVisibility(hasNext ? View.VISIBLE : View.GONE);
}
context.startActivity(i);
}
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.message_view);
mSubjectView = (TextView) findViewById(R.id.subject);
@ -385,14 +407,11 @@ public class MessageView extends Activity
mFavoriteIcon = (ImageView) findViewById(R.id.favorite);
mShowPicturesSection = findViewById(R.id.show_pictures_section);
mSenderPresenceView = (ImageView) findViewById(R.id.presence);
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mMessageContentView.setVerticalScrollBarEnabled(false);
mAttachments.setVisibility(View.GONE);
mAttachmentIcon.setVisibility(View.GONE);
mNext = findViewById(R.id.next);
mPrevious = findViewById(R.id.previous);
mNext.setOnClickListener(this);
mPrevious.setOnClickListener(this);
mFromView.setOnClickListener(this);
mSenderPresenceView.setOnClickListener(this);
mFavoriteIcon.setOnClickListener(this);
@ -401,10 +420,13 @@ public class MessageView extends Activity
findViewById(R.id.delete).setOnClickListener(this);
findViewById(R.id.show_pictures).setOnClickListener(this);
mMessageContentView.setVerticalScrollBarEnabled(false);
mMessageContentView.getSettings().setBlockNetworkImage(true);
mMessageContentView.getSettings().setSupportZoom(false);
setTitle("");
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mDateFormat = android.text.format.DateFormat.getDateFormat(this); // short format
mTimeFormat = android.text.format.DateFormat.getTimeFormat(this); // 12/24 date format
@ -414,37 +436,9 @@ public class MessageView extends Activity
Intent intent = getIntent();
mMessageId = intent.getLongExtra(EXTRA_MESSAGE_ID, -1);
// mAccountId = intent.getLongExtra(EXTRA_ACCOUNT_ID, -1);
// mAccount = EmailStore.Account.restoreAccountWithId(this, mAccountId);
// mFolder = intent.getStringExtra(EXTRA_FOLDER);
// mMessageUid = intent.getStringExtra(EXTRA_MESSAGE);
mMessageListCursor = null; // TODO - pass message list cursor so we can prev/next
View next = findViewById(R.id.next);
View previous = findViewById(R.id.previous);
/*
* Next and Previous Message are not shown in landscape mode, so
* we need to check before we use them.
*/
if (next != null && previous != null && mMessageListCursor != null) {
// TODO analyze based on cursor, not on a big nasty array
next.setVisibility(View.GONE);
previous.setVisibility(View.GONE);
/*
next.setOnClickListener(this);
previous.setOnClickListener(this);
findSurroundingMessagesUid();
previous.setVisibility(mPreviousMessageUid != null ? View.VISIBLE : View.GONE);
next.setVisibility(mNextMessageUid != null ? View.VISIBLE : View.GONE);
boolean goNext = intent.getBooleanExtra(EXTRA_NEXT, false);
if (goNext) {
next.requestFocus();
}
*/
}
mMailboxId = intent.getLongExtra(EXTRA_MAILBOX_ID, -1);
messageChanged();
}
/*
MessagingController.getInstance(getApplication()).addListener(mListener);
@ -463,10 +457,6 @@ public class MessageView extends Activity
}
}.start();
*/
// Start an AsyncTask to make a new cursor and load the message
mLoadMessageTask = new LoadMessageTask(mMessageId);
mLoadMessageTask.execute();
}
@Override
public void onResume() {
@ -485,6 +475,23 @@ public class MessageView extends Activity
Controller.getInstance(getApplication()).removeResultCallback(mControllerCallback);
}
private static void cancelTask(AsyncTask task) {
if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) {
task.cancel(true);
}
}
private void cancelAllTasks() {
cancelTask(mLoadMessageTask);
mLoadMessageTask = null;
cancelTask(mLoadBodyTask);
mLoadBodyTask = null;
cancelTask(mLoadAttachmentsTask);
mLoadAttachmentsTask = null;
cancelTask(mLoadPrevNextTask);
mLoadPrevNextTask = null;
}
/**
* We override onDestroy to make sure that the WebView gets explicitly destroyed.
* Otherwise it can leak native references.
@ -492,28 +499,16 @@ public class MessageView extends Activity
@Override
public void onDestroy() {
super.onDestroy();
if (mLoadMessageTask != null
&& mLoadMessageTask.getStatus() != AsyncTask.Status.FINISHED) {
mLoadMessageTask.cancel(true);
mLoadMessageTask = null;
}
if (mLoadBodyTask != null
&& mLoadBodyTask.getStatus() != AsyncTask.Status.FINISHED) {
mLoadBodyTask.cancel(true);
mLoadBodyTask = null;
}
if (mLoadAttachmentsTask != null
&& mLoadAttachmentsTask.getStatus() != AsyncTask.Status.FINISHED) {
mLoadAttachmentsTask.cancel(true);
mLoadAttachmentsTask = null;
}
cancelAllTasks();
// This is synchronized because the listener accesses mMessageContentView from its thread
synchronized (this) {
mMessageContentView.destroy();
mMessageContentView = null;
}
if (mPrevNextCursor != null) {
mPrevNextCursor.close();
mPrevNextCursor = null;
}
}
private void onDelete() {
@ -593,23 +588,23 @@ public class MessageView extends Activity
}
private boolean onNext() {
// TODO make this work using a cursor
return false;
/*
Bundle extras = new Bundle(1);
extras.putBoolean(EXTRA_NEXT, true);
MessageView.actionView(this, mAccountId, mFolder, mNextMessageUid, mFolderUids, extras);
finish();
*/
if (mPrevNextCursor != null && mPrevNextCursor.moveToNext()) {
mMessageId = mPrevNextCursor.getLong(0);
messageChanged();
return true;
} else {
return false;
}
}
private boolean onPrevious() {
// TODO make this work using a cursor
return false;
/*
MessageView.actionView(this, mAccountId, mFolder, mPreviousMessageUid, mFolderUids);
finish();
*/
if (mPrevNextCursor != null && mPrevNextCursor.moveToPrevious()) {
mMessageId = mPrevNextCursor.getLong(0);
messageChanged();
return true;
} else {
return false;
}
}
private void onMarkAsRead(boolean isRead) {
@ -956,6 +951,41 @@ public class MessageView extends Activity
mSenderPresenceView.setImageResource(presenceIconId);
}
/**
* This task finds out the messageId for the previous and next message
* in the order given by mailboxId as used in MessageList.
*
* It generates the same cursor as the one used in MessageList (but with an id-only projection),
* scans through it until finds the current messageId, and takes the previous and next ids.
*/
private class LoadPrevNextTask extends AsyncTask<Void, Void, Cursor> {
private long mLocalMailboxId;
public LoadPrevNextTask(long mailboxId) {
mLocalMailboxId = mailboxId;
}
@Override
protected Cursor doInBackground(Void... params) {
String selection =
Utility.buildMailboxIdSelection(getContentResolver(), mLocalMailboxId);
Cursor c = MessageView.this.managedQuery(EmailContent.Message.CONTENT_URI,
EmailContent.ID_PROJECTION,
selection, null,
EmailContent.MessageColumns.TIMESTAMP + " DESC");
return c;
}
@Override
protected void onPostExecute(Cursor cursor) {
// position the cursor on the current message
while (cursor.moveToNext() && cursor.getLong(0) != mMessageId);
mPrevNextCursor = cursor;
updatePrevNextArrows(mPrevNextCursor);
}
}
/**
* Async task for loading a single message outside of the UI thread
*
@ -1071,7 +1101,15 @@ public class MessageView extends Activity
Message message = new Message().restore(cursor);
mMessage = message;
mAccountId = message.mAccountKey;
if (mMailboxId == -1) {
mMailboxId = message.mMailboxKey;
}
// only start LoadPrevNextTask once
if (mPrevNextCursor == null) {
mLoadPrevNextTask = new LoadPrevNextTask(mMailboxId);
mLoadPrevNextTask.execute();
}
mSubjectView.setText(message.mSubject);
mFromView.setText(Address.toFriendly(Address.unpack(message.mFrom)));
Date date = new Date(message.mTimeStamp);

View File

@ -1812,14 +1812,9 @@ public abstract class EmailContent {
// Push-Hold indicates an EAS push or ping Mailbox shouldn't sync just yet
public static final int CHECK_INTERVAL_PUSH_HOLD = -4;
private static final String WHERE_TYPE_AND_ACCOUNT_KEY =
MailboxColumns.TYPE + "=? and " + MailboxColumns.ACCOUNT_KEY + "=?";
public Mailbox() {
mBaseUri = CONTENT_URI;
}
// Types of mailboxes. The list is ordered to match a typical UI presentation, e.g.
// placing the inbox at the top.
// The "main" mailbox for the account, almost always referred to as "Inbox"
@ -1852,6 +1847,19 @@ public abstract class EmailContent {
public static final int FLAG_CHILDREN_VISIBLE = 1<<1;
public static final int FLAG_CANT_PUSH = 1<<2;
// Magic mailbox ID's
// NOTE: This is a quick solution for merged mailboxes. I would rather implement this
// with a more generic way of packaging and sharing queries between activities
public static final long QUERY_ALL_INBOXES = -2;
public static final long QUERY_ALL_UNREAD = -3;
public static final long QUERY_ALL_FAVORITES = -4;
public static final long QUERY_ALL_DRAFTS = -5;
public static final long QUERY_ALL_OUTBOX = -6;
public Mailbox() {
mBaseUri = CONTENT_URI;
}
/**
* Restore a Mailbox from the database, given its unique id
* @param context

View File

@ -553,7 +553,7 @@ public class MailService extends Service {
R.plurals.notification_new_multi_account_fmt, accountsWithNewMessages,
accountsWithNewMessages);
intent = MessageList.actionHandleAccountIntent(this,
-1, MessageList.QUERY_ALL_INBOXES, -1);
-1, Mailbox.QUERY_ALL_INBOXES, -1);
}
// prepare appropriate pending intent, set up notification, and send