diff --git a/res/layout-land/message_view.xml b/res/layout-land/message_view.xml index 45a9eda43..92541fc37 100644 --- a/res/layout-land/message_view.xml +++ b/res/layout-land/message_view.xml @@ -31,7 +31,19 @@ android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1"> - + + + + + diff --git a/src/com/android/email/Utility.java b/src/com/android/email/Utility.java index ede1a0651..13a7f9aa8 100644 --- a/src/com/android/email/Utility.java +++ b/src/com/android/email/Utility.java @@ -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(); + } } diff --git a/src/com/android/email/activity/AccountFolderList.java b/src/com/android/email/activity/AccountFolderList.java index b050a7cfe..25c459001 100644 --- a/src/com/android/email/activity/AccountFolderList.java +++ b/src/com/android/email/activity/AccountFolderList.java @@ -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; diff --git a/src/com/android/email/activity/FolderMessageList.java b/src/com/android/email/activity/FolderMessageList.java index 0419d81e2..baef57865 100644 --- a/src/com/android/email/activity/FolderMessageList.java +++ b/src/com/android/email/activity/FolderMessageList.java @@ -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); } } diff --git a/src/com/android/email/activity/MessageList.java b/src/com/android/email/activity/MessageList.java index 1d4fa1d3c..f35fb627e 100644 --- a/src/com/android/email/activity/MessageList.java +++ b/src/com/android/email/activity/MessageList.java @@ -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)}; } diff --git a/src/com/android/email/activity/MessageView.java b/src/com/android/email/activity/MessageView.java index b307e06b4..eafb181d1 100644 --- a/src/com/android/email/activity/MessageView.java +++ b/src/com/android/email/activity/MessageView.java @@ -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 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 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 { + 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); diff --git a/src/com/android/email/provider/EmailContent.java b/src/com/android/email/provider/EmailContent.java index 14c2b434e..065923b45 100644 --- a/src/com/android/email/provider/EmailContent.java +++ b/src/com/android/email/provider/EmailContent.java @@ -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 diff --git a/src/com/android/email/service/MailService.java b/src/com/android/email/service/MailService.java index 0e84c46f7..58d621d2f 100644 --- a/src/com/android/email/service/MailService.java +++ b/src/com/android/email/service/MailService.java @@ -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