diff --git a/src/com/android/email/activity/MessageListXL.java b/src/com/android/email/activity/MessageListXL.java index 9f61f6cd1..4fd381265 100644 --- a/src/com/android/email/activity/MessageListXL.java +++ b/src/com/android/email/activity/MessageListXL.java @@ -21,7 +21,6 @@ import com.android.email.Controller; import com.android.email.ControllerResultUiThreadWrapper; import com.android.email.Email; import com.android.email.MessagingExceptionStrings; -import com.android.email.Preferences; import com.android.email.R; import com.android.email.RefreshManager; import com.android.email.activity.setup.AccountSecurity; @@ -43,6 +42,7 @@ import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -51,12 +51,11 @@ import android.widget.TextView; import java.security.InvalidParameterException; /** - * The main (two-pane) activity for XL devices. - * - * TODO Refine "move to". + * The main activity for multi-pane UIs. The MessageListXL class is responsible + * for managing the "chrome" area of the screen; which primarily includes the action bar. + * The rest of the content area is managed by a fragment manager. */ -public class MessageListXL extends Activity implements - MessageListXLFragmentManager.TargetActivity, MoveMessageToDialog.Callback, +public class MessageListXL extends Activity implements MessageListXLFragmentManager.TargetActivity, View.OnClickListener { private static final String EXTRA_ACCOUNT_ID = "ACCOUNT_ID"; private static final String EXTRA_MAILBOX_ID = "MAILBOX_ID"; @@ -71,28 +70,22 @@ public class MessageListXL extends Activity implements private final RefreshListener mRefreshListener = new RefreshListener(); private Controller.Result mControllerResult; - /** True between onCreate() to onDestroy() */ - private boolean mIsCreated; - private AccountSelectorAdapter mAccountsSelectorAdapter; - private final ActionBarNavigationCallback mActionBarNavigationCallback - = new ActionBarNavigationCallback(); + private ActionBar mActionBar; + private View mActionBarMailboxNameView; + private TextView mActionBarMailboxName; + private TextView mActionBarUnreadCount; + private final ActionBarNavigationCallback mActionBarNavigationCallback = + new ActionBarNavigationCallback(); - private MessageOrderManager mOrderManager; - - private final MessageListXLFragmentManager mFragmentManager - = new MessageListXLFragmentManager(this); - - private final MessageOrderManagerCallback mMessageOrderManagerCallback - = new MessageOrderManagerCallback(); + private final MessageListXLFragmentManager mFragmentManager = + new MessageListXLFragmentManager(this); private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker(); - private BannerController mBannerController; - private TextView mErrorMessageView; - /** - * Id of the account that had a messaging exception most recently. - */ + /** Banner to display errors */ + private BannerController mErrorBanner; + /** Id of the account that had a messaging exception most recently. */ private long mLastErrorAccountId; /** @@ -162,10 +155,6 @@ public class MessageListXL extends Activity implements mRefreshManager = RefreshManager.getInstance(this); mRefreshManager.registerListener(mRefreshListener); - mFragmentManager.setMailboxListFragmentCallback(new MailboxListFragmentCallback()); - mFragmentManager.setMessageListFragmentCallback(new MessageListFragmentCallback()); - mFragmentManager.setMessageViewFragmentCallback(new MessageViewFragmentCallback()); - mAccountsSelectorAdapter = new AccountSelectorAdapter(this, null); if (savedInstanceState != null) { @@ -178,10 +167,28 @@ public class MessageListXL extends Activity implements // Set up views // TODO Probably better to extract mErrorMessageView related code into a separate class, // so that it'll be easy to reuse for the phone activities. - mErrorMessageView = (TextView) findViewById(R.id.error_message); - mErrorMessageView.setOnClickListener(this); - mBannerController = new BannerController(this, mErrorMessageView, - getResources().getDimensionPixelSize(R.dimen.error_message_height)); + TextView errorMessage = (TextView) findViewById(R.id.error_message); + errorMessage.setOnClickListener(this); + int errorBannerHeight = getResources().getDimensionPixelSize(R.dimen.error_message_height); + mErrorBanner = new BannerController(this, errorMessage, errorBannerHeight); + + mActionBar = getActionBar(); + + // Set a view for the current mailbox to the action bar. + final LayoutInflater inflater = LayoutInflater.from(mContext); + mActionBarMailboxNameView = inflater.inflate(R.layout.action_bar_current_mailbox, null); + mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM); + final ActionBar.LayoutParams customViewLayout = new ActionBar.LayoutParams( + ActionBar.LayoutParams.WRAP_CONTENT, + ActionBar.LayoutParams.MATCH_PARENT); + customViewLayout.setMargins(mContext.getResources().getDimensionPixelSize( + R.dimen.action_bar_mailbox_name_left_margin) , 0, 0, 0); + mActionBar.setCustomView(mActionBarMailboxNameView, customViewLayout); + + mActionBarMailboxName = + (TextView) mActionBarMailboxNameView.findViewById(R.id.mailbox_name); + mActionBarUnreadCount = + (TextView) mActionBarMailboxNameView.findViewById(R.id.unread_count); // Halt the progress indicator (we'll display it later when needed) setProgressBarIndeterminate(true); @@ -190,8 +197,6 @@ public class MessageListXL extends Activity implements mControllerResult = new ControllerResultUiThreadWrapper(new Handler(), new ControllerResult()); mController.addResultCallback(mControllerResult); - - mIsCreated = true; } private void initFromIntent() { @@ -221,11 +226,7 @@ public class MessageListXL extends Activity implements protected void onStart() { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onStart"); super.onStart(); - mFragmentManager.onStart(); - if (mFragmentManager.isMessageSelected()) { - updateMessageOrderManager(); - } } @Override @@ -233,12 +234,12 @@ public class MessageListXL extends Activity implements if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onResume"); super.onResume(); mFragmentManager.onResume(); - - // On MessageList.onResume, we go back to Welcome if an account has been added/removed. - // We don't need to do that here, because when the activity resumes, the account list loader - // will load the latest list. - // And if all the accounts have been removed, the loader will detect it and do - // appropriate things. + /** + * In {@link MessageList#onResume()}, we go back to {@link Welcome} if an account + * has been added/removed. We don't need to do that here, because we fetch the most + * up-to-date account list. Additionally, we detect and do the right thing if all + * of the accounts have been removed. + */ } @Override @@ -252,15 +253,12 @@ public class MessageListXL extends Activity implements protected void onStop() { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onStop"); super.onStop(); - mFragmentManager.onStop(); - stopMessageOrderManager(); } @Override protected void onDestroy() { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onDestroy"); - mIsCreated = false; mController.removeResultCallback(mControllerResult); mTaskTracker.cancellAllInterrupt(); mRefreshManager.unregisterListener(mRefreshListener); @@ -279,8 +277,8 @@ public class MessageListXL extends Activity implements /** * Performs the back action. * - * @param isSystemBackKey set true if the system back key is pressed, rather than the home - * icon on action bar. + * @param isSystemBackKey true if the system back key was pressed. Otherwise, + * false [e.g. the home icon on action bar were pressed]. */ private boolean onBackPressed(boolean isSystemBackKey) { if (mFragmentManager.onBackPressed(isSystemBackKey)) { @@ -303,237 +301,6 @@ public class MessageListXL extends Activity implements } } - private void onCurrentMessageGone() { - switch (Preferences.getPreferences(this).getAutoAdvanceDirection()) { - case Preferences.AUTO_ADVANCE_NEWER: - if (moveToNewer()) return; - if (moveToOlder()) return; - break; - case Preferences.AUTO_ADVANCE_OLDER: - if (moveToOlder()) return; - if (moveToNewer()) return; - break; - } - // Last message in the box or AUTO_ADVANCE_MESSAGE_LIST. Go back to message list. - mFragmentManager.goBackToMailbox(); - } - - private void onMoveMessage() { - long messageId = mFragmentManager.getMessageId(); - MoveMessageToDialog dialog = MoveMessageToDialog.newInstance(new long[] {messageId}, - null); - dialog.show(getFragmentManager(), "dialog"); - } - - @Override - public void onMoveToMailboxSelected(long newMailboxId, long[] messageIds) { - ActivityHelper.moveMessages(this, newMailboxId, messageIds); - onCurrentMessageGone(); - } - - /** - * Start {@link MessageOrderManager} if not started, and sync it to the current message. - */ - private void updateMessageOrderManager() { - if (!mFragmentManager.isMailboxSelected()) { - return; - } - final long mailboxId = mFragmentManager.getMailboxId(); - if (mOrderManager == null || mOrderManager.getMailboxId() != mailboxId) { - stopMessageOrderManager(); - mOrderManager = new MessageOrderManager(this, mailboxId, mMessageOrderManagerCallback); - } - if (mFragmentManager.isMessageSelected()) { - mOrderManager.moveTo(mFragmentManager.getMessageId()); - } - } - - private class MessageOrderManagerCallback implements MessageOrderManager.Callback { - @Override - public void onMessagesChanged() { - updateNavigationArrows(); - } - - @Override - public void onMessageNotFound() { - // Current message gone. - mFragmentManager.goBackToMailbox(); - } - } - - /** - * Stop {@link MessageOrderManager}. - */ - private void stopMessageOrderManager() { - if (mOrderManager != null) { - mOrderManager.close(); - mOrderManager = null; - } - } - - /** - * Called when the default account is not found, i.e. there's no account set up. - */ - private void onNoAccountFound() { - // Open Welcome, which in turn shows the adding a new account screen. - Welcome.actionStart(this); - finish(); - return; - } - - /** - * Disable/enable the move-to-newer/older buttons. - */ - private void updateNavigationArrows() { - if (mOrderManager == null) { - // shouldn't happen, but just in case - mFragmentManager.updateMessageCommandButtons(false, false, 0, 0); - } else { - mFragmentManager.updateMessageCommandButtons( - mOrderManager.canMoveToNewer(), mOrderManager.canMoveToOlder(), - mOrderManager.getCurrentPosition(), mOrderManager.getTotalMessageCount()); - } - } - - private boolean moveToOlder() { - if (mFragmentManager.isMessageSelected() && (mOrderManager != null) - && mOrderManager.moveToOlder()) { - mFragmentManager.selectMessage(mOrderManager.getCurrentMessageId()); - return true; - } - return false; - } - - private boolean moveToNewer() { - if (mFragmentManager.isMessageSelected() && (mOrderManager != null) - && mOrderManager.moveToNewer()) { - mFragmentManager.selectMessage(mOrderManager.getCurrentMessageId()); - return true; - } - return false; - } - - private class MailboxListFragmentCallback implements MailboxListFragment.Callback { - @Override - public void onMailboxSelected(long accountId, long mailboxId) { - mFragmentManager.selectMailbox(mailboxId, -1); - } - - @Override - public void onAccountSelected(long accountId) { - mFragmentManager.selectAccount(accountId, -1, -1); - loadAccounts(); // This will update the account spinner, and select the account. - } - - @Override - public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) { - mFragmentManager.setCurrentMailboxName(mailboxName, unreadCount); - } - } - - private class MessageListFragmentCallback implements MessageListFragment.Callback { - @Override - public void onListLoaded() { - } - - @Override - public void onMessageOpen(long messageId, long messageMailboxId, long listMailboxId, - int type) { - if (type == MessageListFragment.Callback.TYPE_DRAFT) { - MessageCompose.actionEditDraft(MessageListXL.this, messageId); - } else { - mFragmentManager.selectMessage(messageId); - } - } - - @Override - public void onMailboxNotFound() { - // TODO: What to do?? - } - - @Override - public void onEnterSelectionMode(boolean enter) { - } - } - - private class MessageViewFragmentCallback implements MessageViewFragment.Callback { - @Override - public void onMessageViewShown(int mailboxType) { - updateMessageOrderManager(); - updateNavigationArrows(); - } - - @Override - public void onMessageViewGone() { - stopMessageOrderManager(); - } - - @Override - public boolean onUrlInMessageClicked(String url) { - return ActivityHelper.openUrlInMessage(MessageListXL.this, url, - mFragmentManager.getActualAccountId()); - } - - @Override - public void onMessageSetUnread() { - mFragmentManager.goBackToMailbox(); - } - - @Override - public void onMessageNotExists() { - mFragmentManager.goBackToMailbox(); - } - - @Override - public void onLoadMessageStarted() { - // TODO Any nice UI for this? - } - - @Override - public void onLoadMessageFinished() { - // TODO Any nice UI for this? - } - - @Override - public void onLoadMessageError(String errorMessage) { - } - - @Override - public void onRespondedToInvite(int response) { - onCurrentMessageGone(); - } - - @Override - public void onCalendarLinkClicked(long epochEventStartTime) { - ActivityHelper.openCalendar(MessageListXL.this, epochEventStartTime); - } - - @Override - public void onBeforeMessageDelete() { - onCurrentMessageGone(); - } - - @Override - public void onMoveMessage() { - MessageListXL.this.onMoveMessage(); - } - - @Override - public void onForward() { - MessageCompose.actionForward(MessageListXL.this, mFragmentManager.getMessageId()); - } - - @Override - public void onReply() { - MessageCompose.actionReply(MessageListXL.this, mFragmentManager.getMessageId(), false); - } - - @Override - public void onReplyAll() { - MessageCompose.actionReply(MessageListXL.this, mFragmentManager.getMessageId(), true); - } - } - @Override public void onAccountSecurityHold(long accountId) { startActivity(AccountSecurity.actionUpdateSecurityIntent(this, accountId, true)); @@ -542,6 +309,7 @@ public class MessageListXL extends Activity implements @Override public void onAccountChanged(long accountId) { invalidateOptionsMenu(); // Update the refresh button + loadAccounts(); // This will update the account spinner, and select the account. } @Override @@ -550,57 +318,20 @@ public class MessageListXL extends Activity implements } @Override - public void onMoveToNewer() { - moveToNewer(); - } + public void onMailboxNameChanged(String mailboxName, int unreadCount) { + mActionBarMailboxName.setText(mailboxName); - @Override - public void onMoveToOlder() { - moveToOlder(); - } - - /** - * Call this when getting a connection error. - */ - private void showErrorMessage(final String rawMessage, final long accountId) { - new EmailAsyncTask(mTaskTracker) { - @Override - protected String doInBackground(Void... params) { - Account account = Account.restoreAccountWithId(MessageListXL.this, accountId); - return (account == null) ? null : account.mDisplayName; - } - - @Override - protected void onPostExecute(String accountName) { - final String message; - if (TextUtils.isEmpty(accountName)) { - message = rawMessage; - } else { - // TODO Use properly designed layout. Don't just concat strings, which isn't - // good for I18N either. - message = rawMessage + " (" + accountName + ")"; - } - if (mBannerController.show(message)) { - mLastErrorAccountId = accountId; - } - } - }.executeParallel(); - } - - /** - * Call this when the connection for an account is considered working. - */ - private void clearErrorMessage(long accountId) { - if (mLastErrorAccountId == accountId) { - dismissErrorMessage(); - } + // Note on action bar, we show only "unread count". Some mailboxes such as Outbox don't + // have the idea of "unread count", in which case we just omit the count. + mActionBarUnreadCount.setText( + UiUtilities.getMessageCountForUi(mContext, unreadCount, true)); } /** * Force dismiss the error banner. */ private void dismissErrorMessage() { - mBannerController.dismiss(); + mErrorBanner.dismiss(); } /** @@ -632,7 +363,9 @@ public class MessageListXL extends Activity implements private void updateAccountList(Cursor accountsCursor) { final int count = accountsCursor.getCount(); if (count == 0) { - onNoAccountFound(); + // Open Welcome, which in turn shows the adding a new account screen. + Welcome.actionStart(this); + finish(); return; } @@ -645,8 +378,6 @@ public class MessageListXL extends Activity implements ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(accountsCursor)); - - selectAccount(AccountSelectorAdapter.getAccountId(accountsCursor)); return; } @@ -772,6 +503,16 @@ public class MessageListXL extends Activity implements mFragmentManager.getMailboxId()).cancelPreviousAndExecuteParallel(); } + @Override + public void onVisiblePanesChanged(int visiblePanes) { + // If the left pane (mailbox list pane) is hidden, the back action on action bar will be + // enabled, and we also show the current mailbox name. + final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0); + mActionBar.setDisplayOptions(leftPaneHidden ? ActionBar.DISPLAY_HOME_AS_UP : 0, + ActionBar.DISPLAY_HOME_AS_UP); + mActionBarMailboxNameView.setVisibility(leftPaneHidden ? View.VISIBLE : View.GONE); + } + /** * Class to handle refresh. * @@ -917,20 +658,42 @@ public class MessageListXL extends Activity implements handleError(result, accountId, progress); } - private void handleError(MessagingException result, long accountId, int progress) { + private void handleError(final MessagingException result, final long accountId, + int progress) { if (accountId == -1) { return; } if (result == null) { if (progress > 0) { - // Connection now working. - clearErrorMessage(accountId); + // Connection now working; clear the error message banner + if (mLastErrorAccountId == accountId) { + dismissErrorMessage(); + } } } else { - // Connection error. - showErrorMessage( - MessagingExceptionStrings.getErrorString(MessageListXL.this, result), - accountId); + // Connection error; show the error message banner + new EmailAsyncTask(mTaskTracker) { + @Override + protected String doInBackground(Void... params) { + Account account = + Account.restoreAccountWithId(MessageListXL.this, accountId); + return (account == null) ? null : account.mDisplayName; + } + + @Override + protected void onPostExecute(String accountName) { + String message = + MessagingExceptionStrings.getErrorString(MessageListXL.this, result); + if (!TextUtils.isEmpty(accountName)) { + // TODO Use properly designed layout. Don't just concatenate strings; + // which is generally poor for I18N. + message = message + " (" + accountName + ")"; + } + if (mErrorBanner.show(message)) { + mLastErrorAccountId = accountId; + } + } + }.executeParallel(); } } } diff --git a/src/com/android/email/activity/MessageListXLFragmentManager.java b/src/com/android/email/activity/MessageListXLFragmentManager.java index 5ad23c449..3d79b856d 100644 --- a/src/com/android/email/activity/MessageListXLFragmentManager.java +++ b/src/com/android/email/activity/MessageListXLFragmentManager.java @@ -17,20 +17,18 @@ package com.android.email.activity; import com.android.email.Email; +import com.android.email.Preferences; import com.android.email.R; import com.android.emailcommon.Logging; import com.android.emailcommon.provider.EmailContent.Account; import com.android.emailcommon.provider.EmailContent.Mailbox; import android.app.ActionBar; +import android.app.Activity; import android.app.FragmentManager; -import android.content.Context; import android.os.Bundle; import android.util.Log; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; import java.security.InvalidParameterException; @@ -42,16 +40,22 @@ import java.security.InvalidParameterException; * * TODO: Test it. It's testable if we implement MockFragmentTransaction, which may be too early * to do so at this point. (API may not be stable enough yet.) + * + * TODO Refine "move to". */ -class MessageListXLFragmentManager { +class MessageListXLFragmentManager implements + MoveMessageToDialog.Callback, + MailboxFinder.Callback, + ThreePaneLayout.Callback, + MailboxListFragment.Callback, + MessageListFragment.Callback, + MessageViewFragment.Callback { private static final String BUNDLE_KEY_ACCOUNT_ID = "MessageListXl.state.account_id"; private static final String BUNDLE_KEY_MAILBOX_ID = "MessageListXl.state.mailbox_id"; private static final String BUNDLE_KEY_MESSAGE_ID = "MessageListXl.state.message_id"; private static final String BUNDLE_KEY_MESSAGE_LIST_STATE = "MessageListXl.state.message_list_state"; - private final Context mContext; - private boolean mIsActivityResumed; /** Current account id. (-1 = not selected) */ @@ -63,11 +67,7 @@ class MessageListXLFragmentManager { /** Current message id. (-1 = not selected) */ private long mMessageId = -1; - private ActionBar mActionBar; private ThreePaneLayout mThreePane; - private View mActionBarMailboxNameView; - private TextView mActionBarMailboxName; - private TextView mActionBarUnreadCount; private MailboxListFragment mMailboxListFragment; private MessageListFragment mMessageListFragment; @@ -75,52 +75,216 @@ class MessageListXLFragmentManager { private MessageCommandButtonView mMessageCommandButtons; private MailboxFinder mMailboxFinder; - private final MailboxFinderCallback mMailboxFinderCallback = new MailboxFinderCallback(); - private final ThreePaneLayoutCallback mThreePaneLayoutCallback = new ThreePaneLayoutCallback(); - /** - * Save state for the "message list -> message view -[back press]-> message list" transition. - */ + /** Save state for the "message list -> message view -[back press]-> message list" transition */ private MessageListFragment.State mMessageListFragmentState; + private MessageOrderManager mOrderManager; + private final MessageOrderManagerCallback mMessageOrderManagerCallback = + new MessageOrderManagerCallback(); + /** * The interface that {@link MessageListXL} implements. We don't call its methods directly, * in the hope that it'll make writing tests easier, and make it clear which methods are needed * for MessageListXLFragmentManager. + * TODO Consider getting rid of this. The fragment manager needs an {@link Activity}, so, + * merely passing around an interface is not sufficient. */ public interface TargetActivity { + /** Implemented by {@link Activity}, so, signature must match */ public ActionBar getActionBar(); public FragmentManager getFragmentManager(); - - /** - * Called when the selected account is on security-hold. - */ - public void onAccountSecurityHold(long accountId); - - /** - * Called when the current account has changed. - */ - public void onAccountChanged(long accountId); - - /** - * Called when the current mailbox has changed. - */ - public void onMailboxChanged(long accountId, long newMailboxId); - - /** Called when "move to newer" button is pressed. */ - public void onMoveToNewer(); - - /** Called when "move to older" button is pressed. */ - public void onMoveToOlder(); - public View findViewById(int id); + + /** Called when the selected account is on security-hold. */ + public void onAccountSecurityHold(long accountId); + /** Called when the current account has changed. */ + public void onAccountChanged(long accountId); + /** Called when the current mailbox has changed. */ + public void onMailboxChanged(long accountId, long newMailboxId); + /** Called when the current mailbox name / unread count has changed. */ + public void onMailboxNameChanged(String mailboxName, int unreadCount); + /** Called when the visible panes have changed. */ + public void onVisiblePanesChanged(int visiblePanes); } - private final TargetActivity mTargetActivity; + private final MessageListXL mActivity; public MessageListXLFragmentManager(MessageListXL activity) { - mContext = activity; - mTargetActivity = activity; + mActivity = activity; + } + + // MailboxFinder$Callback + @Override + public void onAccountNotFound() { + if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { + Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onAccountNotFound()"); + } + // Shouldn't happen + } + + @Override + public void onAccountSecurityHold(long accountId) { + if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { + Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onAccountSecurityHold()"); + } + mActivity.onAccountSecurityHold(accountId); + } + + @Override + public void onMailboxFound(long accountId, long mailboxId) { + if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { + Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onMailboxFound()"); + } + selectMailbox(mailboxId, -1); + } + + @Override + public void onMailboxNotFound(long accountId) { + if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { + Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onMailboxNotFound()"); + } + // Shouldn't happen + } + + // MoveMessageToDialog$Callback + @Override + public void onMoveToMailboxSelected(long newMailboxId, long[] messageIds) { + ActivityHelper.moveMessages(mActivity, newMailboxId, messageIds); + onCurrentMessageGone(); + } + + // ThreePaneLayoutCallback + @Override + public void onVisiblePanesChanged(int previousVisiblePanes) { + final int visiblePanes = mThreePane.getVisiblePanes(); + mActivity.onVisiblePanesChanged(visiblePanes); + if (((visiblePanes & ThreePaneLayout.PANE_RIGHT) == 0) && + ((previousVisiblePanes & ThreePaneLayout.PANE_RIGHT) != 0)) { + // Message view just got hidden + mMessageId = -1; + mMessageListFragment.setSelectedMessage(-1); + mMessageViewFragment.clearContent(); + } + mMessageListFragment.setVisibility((visiblePanes & ThreePaneLayout.PANE_MIDDLE) != 0); + } + + // MailboxListFragment$Callback + @Override + public void onMailboxSelected(long accountId, long mailboxId) { + selectMailbox(mailboxId, -1); + } + + @Override + public void onAccountSelected(long accountId) { + selectAccount(accountId, -1, -1); + } + + @Override + public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) { + mActivity.onMailboxNameChanged(mailboxName, unreadCount); + } + + // MessageListFragment$Callback + @Override + public void onMessageOpen(long messageId, long messageMailboxId, long listMailboxId, + int type) { + if (type == MessageListFragment.Callback.TYPE_DRAFT) { + MessageCompose.actionEditDraft(mActivity, messageId); + } else { + selectMessage(messageId); + } + } + + @Override + public void onMailboxNotFound() { + // TODO: What to do?? + } + + @Override + public void onEnterSelectionMode(boolean enter) { + } + + @Override + public void onListLoaded() { + } + + // MessageViewFragment$Callback + @Override + public void onMessageViewShown(int mailboxType) { + updateMessageOrderManager(); + updateNavigationArrows(); + } + + @Override + public void onMessageViewGone() { + stopMessageOrderManager(); + } + + @Override + public boolean onUrlInMessageClicked(String url) { + return ActivityHelper.openUrlInMessage(mActivity, url, getActualAccountId()); + } + + @Override + public void onMessageSetUnread() { + goBackToMailbox(); + } + + @Override + public void onMessageNotExists() { + goBackToMailbox(); + } + + @Override + public void onLoadMessageStarted() { + // TODO Any nice UI for this? + } + + @Override + public void onLoadMessageFinished() { + // TODO Any nice UI for this? + } + + @Override + public void onLoadMessageError(String errorMessage) { + } + + @Override + public void onRespondedToInvite(int response) { + onCurrentMessageGone(); + } + + @Override + public void onCalendarLinkClicked(long epochEventStartTime) { + ActivityHelper.openCalendar(mActivity, epochEventStartTime); + } + + @Override + public void onBeforeMessageDelete() { + onCurrentMessageGone(); + } + + @Override + public void onMoveMessage() { + long messageId = getMessageId(); + MoveMessageToDialog dialog = MoveMessageToDialog.newInstance(new long[] {messageId}, null); + dialog.show(mActivity.getFragmentManager(), "dialog"); + } + + @Override + public void onForward() { + MessageCompose.actionForward(mActivity, getMessageId()); + } + + @Override + public void onReply() { + MessageCompose.actionReply(mActivity, getMessageId(), false); + } + + @Override + public void onReplyAll() { + MessageCompose.actionReply(mActivity, getMessageId(), true); } /** @@ -133,10 +297,10 @@ class MessageListXLFragmentManager { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager.onActivityViewReady"); } - mThreePane = (ThreePaneLayout) mTargetActivity.findViewById(R.id.three_pane); - mThreePane.setCallback(mThreePaneLayoutCallback); + mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane); + mThreePane.setCallback(this); - FragmentManager fm = mTargetActivity.getFragmentManager(); + FragmentManager fm = mActivity.getFragmentManager(); mMailboxListFragment = (MailboxListFragment) fm.findFragmentById( mThreePane.getLeftPaneId()); mMessageListFragment = (MessageListFragment) fm.findFragmentById( @@ -146,41 +310,9 @@ class MessageListXLFragmentManager { mMessageCommandButtons = mThreePane.getMessageCommandButtons(); mMessageCommandButtons.setCallback(new CommandButtonCallback()); - mActionBar = mTargetActivity.getActionBar(); - - // Set a view for the current mailbox to the action bar. - final LayoutInflater inflater = LayoutInflater.from(mContext); - mActionBarMailboxNameView = inflater.inflate(R.layout.action_bar_current_mailbox, null); - mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM, ActionBar.DISPLAY_SHOW_CUSTOM); - final ActionBar.LayoutParams customViewLayout = new ActionBar.LayoutParams( - ActionBar.LayoutParams.WRAP_CONTENT, - ActionBar.LayoutParams.MATCH_PARENT); - customViewLayout.setMargins(mContext.getResources().getDimensionPixelSize( - R.dimen.action_bar_mailbox_name_left_margin) , 0, 0, 0); - mActionBar.setCustomView(mActionBarMailboxNameView, customViewLayout); - - mActionBarMailboxName = - (TextView) mActionBarMailboxNameView.findViewById(R.id.mailbox_name); - mActionBarUnreadCount = - (TextView) mActionBarMailboxNameView.findViewById(R.id.unread_count); - } - - /** Set callback for fragment. */ - public void setMailboxListFragmentCallback( - MailboxListFragment.Callback mailboxListFragmentCallback) { - mMailboxListFragment.setCallback(mailboxListFragmentCallback); - } - - /** Set callback for fragment. */ - public void setMessageListFragmentCallback( - MessageListFragment.Callback messageListFragmentCallback) { - mMessageListFragment.setCallback(messageListFragmentCallback); - } - - /** Set callback for fragment. */ - public void setMessageViewFragmentCallback( - MessageViewFragment.Callback messageViewFragmentCallback) { - mMessageViewFragment.setCallback(messageViewFragmentCallback); + mMailboxListFragment.setCallback(this); + mMessageListFragment.setCallback(this); + mMessageViewFragment.setCallback(this); } /** @@ -225,35 +357,26 @@ class MessageListXLFragmentManager { return getMessageId() != -1; } - public MailboxListFragment getMailboxListFragment() { - return mMailboxListFragment; - } - - public MessageListFragment getMessageListFragment() { - return mMessageListFragment; - } - - public MessageViewFragment getMessageViewFragment() { - return mMessageViewFragment; - } - /** * Called from {@link MessageListXL#onStart}. */ public void onStart() { - // Nothing to do + if (isMessageSelected()) { + updateMessageOrderManager(); + } } /** * Called from {@link MessageListXL#onResume}. */ public void onResume() { + int visiblePanes = mThreePane.getVisiblePanes(); + mActivity.onVisiblePanesChanged(visiblePanes); + if (mIsActivityResumed) { return; } mIsActivityResumed = true; - - updateActionBar(); } /** @@ -264,14 +387,14 @@ class MessageListXLFragmentManager { return; } mIsActivityResumed = false; - saveMessageListFragmentState(); + mMessageListFragmentState = mMessageListFragment.getState(); } /** * Called from {@link MessageListXL#onStop}. */ public void onStop() { - // Nothing to do + stopMessageOrderManager(); } /** @@ -304,38 +427,6 @@ class MessageListXLFragmentManager { selectAccount(accountId, mailboxId, messageId); } - private void saveMessageListFragmentState() { - if (mMessageListFragment != null) { - mMessageListFragmentState = mMessageListFragment.getState(); - } - } - - private void restoreMesasgeListState() { - if ((mMessageListFragment != null) && (mMessageListFragmentState != null)) { - mMessageListFragmentState.restore(mMessageListFragment); - mMessageListFragmentState = null; - } - } - - private void updateActionBar() { - // If the left pane (mailbox list pane) is hidden, the back action on action bar will be - // enabled, and we also show the current mailbox name. - final int visiblePanes = mThreePane.getVisiblePanes(); - final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0); - mActionBar.setDisplayOptions(leftPaneHidden ? ActionBar.DISPLAY_HOME_AS_UP : 0, - ActionBar.DISPLAY_HOME_AS_UP); - mActionBarMailboxNameView.setVisibility(leftPaneHidden ? View.VISIBLE : View.GONE); - } - - public void setCurrentMailboxName(String mailboxName, int unreadCount) { - mActionBarMailboxName.setText(mailboxName); - - // Note on action bar, we show only "unread count". Some mailboxes such as Outbox don't - // have the idea of "unread count", in which case we just omit the count. - mActionBarUnreadCount.setText( - UiUtilities.getMessageCountForUi(mContext, unreadCount, true)); - } - /** * Call it to select an account. * @@ -371,11 +462,14 @@ class MessageListXLFragmentManager { // When opening the Combined view, the right pane will be "combined inbox". selectMailbox(Mailbox.QUERY_ALL_INBOXES, -1); } else if (mailboxId == -1) { - startInboxLookup(); + // Try to find the inbox for the account + closeMailboxFinder(); + mMailboxFinder = new MailboxFinder(mActivity, mAccountId, Mailbox.TYPE_INBOX, this); + mMailboxFinder.startLookup(); } else { selectMailbox(mailboxId, messageId); } - mTargetActivity.onAccountChanged(mAccountId); + mActivity.onAccountChanged(mAccountId); } /** @@ -389,59 +483,61 @@ class MessageListXLFragmentManager { } /** - * If the current view is MessageView, go back to MessageList. + * Go back to a mailbox list view. If a message view is currently active, it will + * be hidden. */ - public void goBackToMailbox() { + private void goBackToMailbox() { if (isMessageSelected()) { mThreePane.showLeftPane(); // Show mailbox list } } /** - * Call it to select a mailbox. - * + * Select a mailbox and potentially a message within that mailbox. * We assume the mailbox selected here belongs to the account selected with * {@link #selectAccount}. * * @param mailboxId ID of mailbox * @param messageId message ID. Pass -1 to not open a message. */ - public void selectMailbox(long mailboxId, long messageId) { + private void selectMailbox(long mailboxId, long messageId) { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { Log.d(Logging.LOG_TAG, "selectMailbox mMailboxId=" + mailboxId); } if (mailboxId == -1) { throw new InvalidParameterException(); } - if (mMailboxId == mailboxId) { return; } - // Update members. + // Update members mMailboxId = mailboxId; mMessageId = -1; // Open mailbox + if (mMessageListFragmentState != null) { + mMessageListFragmentState.restore(mMessageListFragment); + mMessageListFragmentState = null; + } mMessageListFragment.openMailbox(mMailboxId); - restoreMesasgeListState(); - mMailboxListFragment.setSelectedMailbox(mMailboxId); - mTargetActivity.onMailboxChanged(mAccountId, mMailboxId); + mActivity.onMailboxChanged(mAccountId, mMailboxId); + + // If a message ID was specified, show it; otherwise show the mailbox list if (messageId == -1) { - mThreePane.showLeftPane(); // Show mailbox list + mThreePane.showLeftPane(); } else { selectMessage(messageId); } } /** - * Call it to select a mailbox. - * - * We assume the message passed here belongs to the account/mailbox selected with - * {@link #selectAccount} and {@link #selectMailbox}. + * Select a message to view. + * We assume the message selected here belongs to the mailbox selected with + * {@link #selectMailbox}. */ - public void selectMessage(long messageId) { + private void selectMessage(long messageId) { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { Log.d(Logging.LOG_TAG, "selectMessage messageId=" + messageId); } @@ -452,9 +548,9 @@ class MessageListXLFragmentManager { return; } - saveMessageListFragmentState(); + mMessageListFragmentState = mMessageListFragment.getState(); - // Update member. + // Update member mMessageId = messageId; // Open message @@ -463,28 +559,6 @@ class MessageListXLFragmentManager { mThreePane.showRightPane(); // Show message view } - /** - * Unselect the currently viewed message, if any, and release the resoruce grabbed by the - * message view. - * - * This must be called when the three pane reports that the message view pane gets hidden. - */ - private void onMessageViewClosed() { - mMessageId = -1; - mMessageListFragment.setSelectedMessage(-1); - mMessageViewFragment.clearContent(); - } - - private void startInboxLookup() { - if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { - Log.d(Logging.LOG_TAG, "startLookForInbox account=" + mAccountId); - } - closeMailboxFinder(); - mMailboxFinder = new MailboxFinder(mContext, mAccountId, Mailbox.TYPE_INBOX, - mMailboxFinderCallback); - mMailboxFinder.startLookup(); - } - private void closeMailboxFinder() { if (mMailboxFinder != null) { mMailboxFinder.cancel(); @@ -492,69 +566,104 @@ class MessageListXLFragmentManager { } } - private class MailboxFinderCallback implements MailboxFinder.Callback { - @Override - public void onAccountNotFound() { - if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { - Log.d(Logging.LOG_TAG, "MailboxFinderCallback.onAccountNotFound"); - } - // Shouldn't happen - } - - @Override - public void onAccountSecurityHold(long accountId) { - if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { - Log.d(Logging.LOG_TAG, "MailboxFinderCallback.onAccountSecurityHold"); - } - mTargetActivity.onAccountSecurityHold(accountId); - } - - @Override - public void onMailboxFound(long accountId, long mailboxId) { - if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { - Log.d(Logging.LOG_TAG, " Found inbox"); - } - selectMailbox(mailboxId, -1); - } - - @Override - public void onMailboxNotFound(long accountId) { - if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { - Log.d(Logging.LOG_TAG, "MailboxFinderCallback.onMailboxNotFound"); - } - // Shouldn't happen - } - } - - public void updateMessageCommandButtons(boolean enableMoveToNewer, boolean enableMoveToOlder, - int currentPosition, int countMessages) { - mMessageCommandButtons.enableNavigationButtons(enableMoveToNewer, enableMoveToOlder, - currentPosition, countMessages); - } - private class CommandButtonCallback implements MessageCommandButtonView.Callback { @Override public void onMoveToNewer() { - mTargetActivity.onMoveToNewer(); + MessageListXLFragmentManager.this.onMoveToNewer(); } @Override public void onMoveToOlder() { - mTargetActivity.onMoveToOlder(); + MessageListXLFragmentManager.this.onMoveToOlder(); } } - private class ThreePaneLayoutCallback implements ThreePaneLayout.Callback { - @Override - public void onVisiblePanesChanged(int previousVisiblePanes) { - updateActionBar(); - final int visiblePanes = mThreePane.getVisiblePanes(); - if (((visiblePanes & ThreePaneLayout.PANE_RIGHT) == 0) && - ((previousVisiblePanes & ThreePaneLayout.PANE_RIGHT) != 0)) { - // Message view just got hidden - onMessageViewClosed(); - } - mMessageListFragment.setVisibility((visiblePanes & ThreePaneLayout.PANE_MIDDLE) != 0); + private void onCurrentMessageGone() { + switch (Preferences.getPreferences(mActivity).getAutoAdvanceDirection()) { + case Preferences.AUTO_ADVANCE_NEWER: + if (onMoveToNewer()) return; + if (onMoveToOlder()) return; + break; + case Preferences.AUTO_ADVANCE_OLDER: + if (onMoveToOlder()) return; + if (onMoveToNewer()) return; + break; + } + // Last message in the box or AUTO_ADVANCE_MESSAGE_LIST. Go back to message list. + goBackToMailbox(); + } + + /** + * Potentially create a new {@link MessageOrderManager}; if it's not already started or if + * the account has changed, and sync it to the current message. + */ + private void updateMessageOrderManager() { + if (!isMailboxSelected()) { + return; + } + final long mailboxId = getMailboxId(); + if (mOrderManager == null || mOrderManager.getMailboxId() != mailboxId) { + stopMessageOrderManager(); + mOrderManager = + new MessageOrderManager(mActivity, mailboxId, mMessageOrderManagerCallback); + } + if (isMessageSelected()) { + mOrderManager.moveTo(getMessageId()); } } + + private class MessageOrderManagerCallback implements MessageOrderManager.Callback { + @Override + public void onMessagesChanged() { + updateNavigationArrows(); + } + + @Override + public void onMessageNotFound() { + // Current message gone. + goBackToMailbox(); + } + } + + /** + * Stop {@link MessageOrderManager}. + */ + private void stopMessageOrderManager() { + if (mOrderManager != null) { + mOrderManager.close(); + mOrderManager = null; + } + } + + /** + * Disable/enable the move-to-newer/older buttons. + */ + private void updateNavigationArrows() { + if (mOrderManager == null) { + // shouldn't happen, but just in case + mMessageCommandButtons.enableNavigationButtons(false, false, 0, 0); + } else { + mMessageCommandButtons.enableNavigationButtons( + mOrderManager.canMoveToNewer(), mOrderManager.canMoveToOlder(), + mOrderManager.getCurrentPosition(), mOrderManager.getTotalMessageCount()); + } + } + + private boolean onMoveToOlder() { + if (isMessageSelected() && (mOrderManager != null) + && mOrderManager.moveToOlder()) { + selectMessage(mOrderManager.getCurrentMessageId()); + return true; + } + return false; + } + + private boolean onMoveToNewer() { + if (isMessageSelected() && (mOrderManager != null) + && mOrderManager.moveToNewer()) { + selectMessage(mOrderManager.getCurrentMessageId()); + return true; + } + return false; + } }