replicant-packages_apps_Email/src/com/android/email/activity/MessageListXLFragmentManage...

562 lines
19 KiB
Java

/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.activity;
import com.android.email.Email;
import com.android.email.R;
import com.android.email.UiUtilities;
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.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;
/**
* A class manages what are showing on {@link MessageListXL} (i.e. account id, mailbox id, and
* message id), and show/hide fragments accordingly.
*
* TODO Highlight selected message on message list
*
* 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.)
*/
class MessageListXLFragmentManager {
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) */
private long mAccountId = -1;
/** Current mailbox id. (-1 = not selected) */
private long mMailboxId = -1;
/** 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;
private MessageViewFragment mMessageViewFragment;
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.
*/
private MessageListFragment.State mMessageListFragmentState;
/**
* 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.
*/
public interface TargetActivity {
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);
}
private final TargetActivity mTargetActivity;
public MessageListXLFragmentManager(MessageListXL activity) {
mContext = activity;
mTargetActivity = activity;
}
/**
* Must be called just after the activity sets up the content view.
*
* (Due to the complexity regarding class/activity initialization order, we can't do this in
* the constructor.)
*/
public void onActivityViewReady() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager.onActivityViewReady");
}
mThreePane = (ThreePaneLayout) mTargetActivity.findViewById(R.id.three_pane);
mThreePane.setCallback(mThreePaneLayoutCallback);
FragmentManager fm = mTargetActivity.getFragmentManager();
mMailboxListFragment = (MailboxListFragment) fm.findFragmentById(
mThreePane.getLeftPaneId());
mMessageListFragment = (MessageListFragment) fm.findFragmentById(
mThreePane.getMiddlePaneId());
mMessageViewFragment = (MessageViewFragment) fm.findFragmentById(
mThreePane.getRightPaneId());
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);
}
/**
* @return the currently selected account ID, *or* {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
*
* @see #getActualAccountId()
*/
public long getUIAccountId() {
return mAccountId;
}
/**
* @return the currently selected account ID. If the current view is the combined view,
* it'll return -1.
*
* @see #getUIAccountId()
*/
public long getActualAccountId() {
return mAccountId == Account.ACCOUNT_ID_COMBINED_VIEW ? -1 : mAccountId;
}
public long getMailboxId() {
return mMailboxId;
}
public long getMessageId() {
return mMessageId;
}
/**
* @return true if an account is selected, or the current view is the combined view.
*/
public boolean isAccountSelected() {
return getUIAccountId() != -1;
}
public boolean isMailboxSelected() {
return getMailboxId() != -1;
}
public boolean isMessageSelected() {
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
}
/**
* Called from {@link MessageListXL#onResume}.
*/
public void onResume() {
if (mIsActivityResumed) {
return;
}
mIsActivityResumed = true;
updateActionBar();
}
/**
* Called from {@link MessageListXL#onPause}.
*/
public void onPause() {
if (!mIsActivityResumed) {
return;
}
mIsActivityResumed = false;
saveMessageListFragmentState();
}
/**
* Called from {@link MessageListXL#onStop}.
*/
public void onStop() {
// Nothing to do
}
/**
* Called from {@link MessageListXL#onDestroy}.
*/
public void onDestroy() {
closeMailboxFinder();
}
public void onSaveInstanceState(Bundle outState) {
outState.putLong(BUNDLE_KEY_ACCOUNT_ID, mAccountId);
outState.putLong(BUNDLE_KEY_MAILBOX_ID, mMailboxId);
outState.putLong(BUNDLE_KEY_MESSAGE_ID, mMessageId);
outState.putParcelable(BUNDLE_KEY_MESSAGE_LIST_STATE, mMessageListFragmentState);
}
public void loadState(Bundle savedInstanceState) {
long accountId = savedInstanceState.getLong(BUNDLE_KEY_ACCOUNT_ID, -1);
long mailboxId = savedInstanceState.getLong(BUNDLE_KEY_MAILBOX_ID, -1);
long messageId = savedInstanceState.getLong(BUNDLE_KEY_MESSAGE_ID, -1);
mMessageListFragmentState = savedInstanceState.getParcelable(BUNDLE_KEY_MESSAGE_LIST_STATE);
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager: Restoring "
+ accountId + "," + mailboxId + "," + messageId);
}
if (accountId == -1) {
return;
}
// selectAccount() calls selectMailbox/Message() if necessary.
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.
*
* @param accountId account ID. Must not be -1.
* @param mailboxId mailbox ID. Pass -1 to open account's inbox.
* @param messageId message ID. Pass -1 to not open a message.
*/
public void selectAccount(long accountId, long mailboxId, long messageId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "selectAccount mAccountId=" + accountId);
}
if (accountId == -1) {
throw new InvalidParameterException();
}
if (mAccountId == accountId) {
return;
}
// Update members.
mAccountId = accountId;
mMailboxId = -1;
mMessageId = -1;
// In case of "message list -> message view -> change account", we don't have to keep it.
mMessageListFragmentState = null;
// Open mailbox list, clear message list / message view
mMailboxListFragment.openMailboxes(mAccountId);
mMessageListFragment.clearContent();
mThreePane.showLeftPane(); // Show mailbox list
if ((accountId == Account.ACCOUNT_ID_COMBINED_VIEW) && (mailboxId == -1)) {
// When opening the Combined view, the right pane will be "combined inbox".
selectMailbox(Mailbox.QUERY_ALL_INBOXES, -1);
} else if (mailboxId == -1) {
startInboxLookup();
} else {
selectMailbox(mailboxId, messageId);
}
mTargetActivity.onAccountChanged(mAccountId);
}
/**
* Handles the back event.
*
* @param isSystemBackKey See {@link ThreePaneLayout#onBackPressed}
* @return true if the event is handled.
*/
public boolean onBackPressed(boolean isSystemBackKey) {
return mThreePane.onBackPressed(isSystemBackKey);
}
/**
* If the current view is MessageView, go back to MessageList.
*/
public void goBackToMailbox() {
if (isMessageSelected()) {
mThreePane.showLeftPane(); // Show mailbox list
}
}
/**
* Call it to select a 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) {
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.
mMailboxId = mailboxId;
mMessageId = -1;
// Open mailbox
mMessageListFragment.openMailbox(mMailboxId);
restoreMesasgeListState();
mMailboxListFragment.setSelectedMailbox(mMailboxId);
mTargetActivity.onMailboxChanged(mAccountId, mMailboxId);
if (messageId == -1) {
mThreePane.showLeftPane(); // Show mailbox list
} 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}.
*/
public void selectMessage(long messageId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "selectMessage messageId=" + messageId);
}
if (messageId == -1) {
throw new InvalidParameterException();
}
if (mMessageId == messageId) {
return;
}
saveMessageListFragmentState();
// Update member.
mMessageId = messageId;
// Open message
mMessageListFragment.setSelectedMessage(mMessageId);
mMessageViewFragment.openMessage(mMessageId);
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();
mMailboxFinder = null;
}
}
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();
}
@Override
public void onMoveToOlder() {
mTargetActivity.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);
}
}
}