Merged activity: move UI from activity to UIController

- Renamed XLFragmentManager to UIControllerTwoPane
- Moved UI code from the activity to UIControllerTwoPane
- Bunch of clean-ups (Mostly renames to make things self-descriptive)
- Removed unused class MessageListFragment.State
- Fix bug 4341563

Change-Id: Ia2230bd5ec501fbc5c92b07b2ba874153b577a39
This commit is contained in:
Makoto Onuki 2011-04-26 10:28:18 -07:00
parent 79b97da58c
commit aee368d205
5 changed files with 209 additions and 238 deletions

View File

@ -276,7 +276,7 @@ import android.widget.TextView;
// Long superParentKey = Utility.getFirstRowLong(getContext(), Mailbox.CONTENT_URI,
// new String[] { MailboxColumns.PARENT_KEY }, MailboxColumns.ID + "=?",
// new String[] { Long.toString(mParentKey) }, null, 0);
Long superParentKey = MessageListXLFragmentManager.NO_MAILBOX;
Long superParentKey = Mailbox.PARENT_KEY_NONE;
if (superParentKey != null) {
final Cursor parentCursor = getContext().getContentResolver().query(

View File

@ -170,7 +170,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
* @param mailboxId
* The ID of the selected mailbox. This may be real mailbox ID [e.g. a number > 0],
* or a special mailbox ID
* [e.g. {@link MessageListXLFragmentManager#NO_MAILBOX} for "All Folders" to open
* [e.g. {@link #ROOT_PARENT_MAILBOX_ID} for "All Folders" to open
* the root folders, {@link Mailbox#QUERY_ALL_INBOXES}, etc...].
* @param navigate navigate to the mailbox.
* @param dragDrop true if D&D is in progress.
@ -311,7 +311,8 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
* loaded, the list of top-level mailbox will not be reloaded unless <code>forceReload</code>
* is <code>true</code>.
* @param accountId The ID of the account we want to view
* @param parentMailboxId The ID of the parent mailbox. Use -1 to open the root.
* @param parentMailboxId The ID of the parent mailbox. Use {@link Mailbox#PARENT_KEY_NONE}
* to open the root.
* Otherwise, only load the list of top-level mailboxes if the account changes.
*/
// STOPSHIP Make it private once phone activities are gone
@ -323,7 +324,7 @@ public class MailboxListFragment extends ListFragment implements OnItemClickList
throw new InvalidParameterException();
}
// Normalize -- STOPSHIP should be removed when DEFAULT_MAILBOX_ID becomes -1.
if (parentMailboxId == -1) {
if (parentMailboxId == Mailbox.PARENT_KEY_NONE) {
parentMailboxId = DEFAULT_MAILBOX_ID;
}

View File

@ -146,12 +146,12 @@ public class MessageListFragment extends ListFragment
private boolean mShowSendCommand;
/**
* Visibility. On XL, message list is normally visible, except when message view is shown
* in full-screen on portrait.
*
* When not visible, the contextual action bar will be gone.
* If true, we disable the CAB even if there are selected messages.
* It's used in portrait on the tablet when the message view becomes visible and the message
* list gets pushed out of the screen, in which case we want to keep the selection but the CAB
* should be gone.
*/
private boolean mIsVisible = true;
private boolean mDisableCab;
/** true between {@link #onResume} and {@link #onPause}. */
private boolean mResumed;
@ -404,11 +404,15 @@ public class MessageListFragment extends ListFragment
mCallback = (callback != null) ? callback : EmptyCallback.INSTANCE;
}
public void setVisibility(boolean isVisible) {
if (isVisible == mIsVisible) {
/**
* This method must be called when the fragment is hidden/shown.
*/
public void onHidden(boolean hidden) {
// When hidden, we need to disable CAB.
if (hidden == mDisableCab) {
return;
}
mIsVisible = isVisible;
mDisableCab = hidden;
updateSelectionMode();
}
@ -1284,7 +1288,7 @@ public class MessageListFragment extends ListFragment
*/
public void updateSelectionMode() {
final int numSelected = getSelectedCount();
if ((numSelected == 0) || !mIsVisible) {
if ((numSelected == 0) || mDisableCab) {
finishSelectionMode();
return;
}
@ -1413,53 +1417,6 @@ public class MessageListFragment extends ListFragment
}
}
/**
* Object that holds the current state (right now it's only the ListView state) of the fragment.
*
* Used by {@link MessageListXLFragmentManager} to preserve scroll position through fragment
* transitions.
*/
public static class State implements Parcelable {
private final Parcelable mListState;
private State(Parcel p) {
mListState = p.readParcelable(getClass().getClassLoader());
}
private State(MessageListFragment messageListFragment) {
mListState = messageListFragment.getListView().onSaveInstanceState();
}
public void restore(MessageListFragment messageListFragment) {
messageListFragment.mSavedListState = mListState;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mListState, flags);
}
public static final Parcelable.Creator<State> CREATOR
= new Parcelable.Creator<State>() {
public State createFromParcel(Parcel in) {
return new State(in);
}
public State[] newArray(int size) {
return new State[size];
}
};
}
public State getState() {
return new State(this);
}
/**
* Highlight the selected message.
*/

View File

@ -23,7 +23,6 @@ import com.android.email.Email;
import com.android.email.MessagingExceptionStrings;
import com.android.email.R;
import com.android.email.RefreshManager;
import com.android.email.activity.setup.AccountSecurity;
import com.android.email.activity.setup.AccountSettingsXL;
import com.android.emailcommon.Logging;
import com.android.emailcommon.mail.MessagingException;
@ -53,7 +52,6 @@ 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;
@ -62,14 +60,15 @@ import android.widget.TextView;
import java.security.InvalidParameterException;
/**
* The main activity for multi-pane UIs. The <code>MessageListXL</code> 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.
* The main Email activity, which is used on both the tablet and the phone.
*
* TODO: Fixit: Current account resets to default on screen rotation.
* Because this activity is device agnostic, so most of the UI aren't owned by this, but by
* the UIController.
*
* TODO: Account spinner should also be moved out of this class. (to the UIController or to a
* sepate class.)
*/
public class MessageListXL extends Activity implements MessageListXLFragmentManager.TargetActivity,
View.OnClickListener {
public class MessageListXL extends Activity implements View.OnClickListener {
private static final String EXTRA_ACCOUNT_ID = "ACCOUNT_ID";
private static final String EXTRA_MAILBOX_ID = "MAILBOX_ID";
private static final String EXTRA_MESSAGE_ID = "MESSAGE_ID";
@ -87,15 +86,10 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
private Controller.Result mControllerResult;
private AccountSelectorAdapter mAccountsSelectorAdapter;
private ActionBar mActionBar;
private View mActionBarMailboxNameView;
private TextView mActionBarMailboxName;
private TextView mActionBarUnreadCount;
private final ActionBarNavigationCallback mActionBarNavigationCallback =
new ActionBarNavigationCallback();
private final MessageListXLFragmentManager mFragmentManager =
new MessageListXLFragmentManager(this);
private final UIControllerTwoPane mUIController = new UIControllerTwoPane(this);
private final EmailAsyncTask.Tracker mTaskTracker = new EmailAsyncTask.Tracker();
@ -164,23 +158,18 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
ActivityHelper.debugSetWindowFlags(this);
setContentView(R.layout.message_list_xl);
ActionBar ab = getActionBar();
ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME);
mFragmentManager.onActivityViewReady();
mUIController.onActivityViewReady();
mContext = getApplicationContext();
mController = Controller.getInstance(this);
mControllerResult = new ControllerResultUiThreadWrapper<ControllerResult>(new Handler(),
new ControllerResult());
mController.addResultCallback(mControllerResult);
mRefreshManager = RefreshManager.getInstance(this);
mRefreshManager.registerListener(mRefreshListener);
mAccountsSelectorAdapter = new AccountSelectorAdapter(this, null);
if (savedInstanceState != null) {
mFragmentManager.restoreInstanceState(savedInstanceState);
} else {
initFromIntent();
}
loadAccounts();
// Set up views
@ -191,33 +180,16 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
int errorBannerHeight = getResources().getDimensionPixelSize(R.dimen.error_message_height);
mErrorBanner = new BannerController(this, errorMessage, errorBannerHeight);
mActionBar = getActionBar();
// Install restored fragments.
mUIController.installRestoredFragments();
// 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);
setProgressBarIndeterminateVisibility(false);
mControllerResult = new ControllerResultUiThreadWrapper<ControllerResult>(new Handler(),
new ControllerResult());
mController.addResultCallback(mControllerResult);
mFragmentManager.onActivityCreated();
if (savedInstanceState != null) {
mUIController.restoreInstanceState(savedInstanceState);
} else {
// This needs to be done after installRestoredFragments.
// See UIControllerTwoPane.preFragmentTransactionCheck()
initFromIntent();
}
}
private void initFromIntent() {
@ -230,7 +202,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
}
if (accountId != -1) {
mFragmentManager.open(accountId, mailboxId, messageId);
mUIController.open(accountId, mailboxId, messageId);
}
}
@ -240,7 +212,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
Log.d(Logging.LOG_TAG, "MessageListXL onSaveInstanceState");
}
super.onSaveInstanceState(outState);
mFragmentManager.onSaveInstanceState(outState);
mUIController.onSaveInstanceState(outState);
}
@Override
@ -249,14 +221,14 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
Log.d(Logging.LOG_TAG, "MessageListXL onAttachFragment fragment=" + fragment);
}
super.onAttachFragment(fragment);
mFragmentManager.onAttachFragment(fragment);
mUIController.onAttachFragment(fragment);
}
@Override
protected void onStart() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onStart");
super.onStart();
mFragmentManager.onStart();
mUIController.onStart();
// STOPSHIP Temporary search UI
Intent intent = getIntent();
@ -304,7 +276,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
protected void onResume() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onResume");
super.onResume();
mFragmentManager.onResume();
mUIController.onResume();
/**
* 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
@ -317,14 +289,14 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
protected void onPause() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onPause");
super.onPause();
mFragmentManager.onPause();
mUIController.onPause();
}
@Override
protected void onStop() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) Log.d(Logging.LOG_TAG, "MessageListXL onStop");
super.onStop();
mFragmentManager.onStop();
mUIController.onStop();
}
@Override
@ -333,7 +305,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
mController.removeResultCallback(mControllerResult);
mTaskTracker.cancellAllInterrupt();
mRefreshManager.unregisterListener(mRefreshListener);
mFragmentManager.onDestroy();
mUIController.onDestroy();
super.onDestroy();
}
@ -352,7 +324,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
* <code>false</code> [e.g. the home icon on action bar were pressed].
*/
private boolean onBackPressed(boolean isSystemBackKey) {
if (mFragmentManager.onBackPressed(isSystemBackKey)) {
if (mUIController.onBackPressed(isSystemBackKey)) {
return true;
}
if (isSystemBackKey) {
@ -372,32 +344,14 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
}
}
@Override
public void onAccountSecurityHold(long accountId) {
startActivity(AccountSecurity.actionUpdateSecurityIntent(this, accountId, true));
}
@Override
/**
* Called by the UIController when the current account has changed.
*/
public void onAccountChanged(long accountId) {
invalidateOptionsMenu(); // Update the refresh button
updateRefreshProgress();
loadAccounts(); // This will update the account spinner, and select the account.
}
@Override
public void onMailboxChanged(long accountId, long newMailboxId) {
updateProgressIcon();
}
@Override
public void onMailboxNameChanged(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));
}
/**
* Force dismiss the error banner.
*/
@ -454,12 +408,12 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
// Find the currently selected account, and select it.
int defaultSelection = 0;
if (mFragmentManager.isAccountSelected()) {
if (mUIController.isAccountSelected()) {
accountsCursor.moveToPosition(-1);
int i = 0;
while (accountsCursor.moveToNext()) {
final long accountId = AccountSelectorAdapter.getAccountId(accountsCursor);
if (accountId == mFragmentManager.getUIAccountId()) {
if (accountId == mUIController.getUIAccountId()) {
defaultSelection = i;
break;
}
@ -482,8 +436,8 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
Log.d(Logging.LOG_TAG, "Account selected: accountId=" + accountId);
}
// TODO UIManager should do the check eventually, but it's necessary for now.
if (accountId != mFragmentManager.getUIAccountId()) {
mFragmentManager.openAccount(accountId);
if (accountId != mUIController.getUIAccountId()) {
mUIController.openAccount(accountId);
}
}
@ -499,27 +453,25 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
implements RefreshManager.Listener {
@Override
public void onMessagingError(final long accountId, long mailboxId, final String message) {
updateProgressIcon();
updateRefreshProgress();
}
@Override
public void onRefreshStatusChanged(long accountId, long mailboxId) {
updateProgressIcon();
updateRefreshProgress();
}
}
/**
* If we're refreshing the current mailbox, animate the "mailbox refreshing" progress icon.
* Start/stop the "refresh" animation on the action bar according to the current refresh state.
*
* (We start the animation if {@link UIControllerTwoPane#isRefreshInProgress} returns true,
* and stop otherwise.)
*/
private void updateProgressIcon() {
public void updateRefreshProgress() {
invalidateOptionsMenu();
}
private boolean isProgressActive() {
final long mailboxId = mFragmentManager.getMailboxId();
return (mailboxId >= 0) && mRefreshManager.isMessageListRefreshing(mailboxId);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
@ -532,7 +484,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
// STOPSHIP Temporary search/sync options UI
// Only show search/sync options for EAS
boolean isEas = false;
long accountId = mFragmentManager.getActualAccountId();
long accountId = mUIController.getActualAccountId();
if (accountId > 0) {
if ("eas".equals(Account.getProtocol(mContext, accountId))) {
isEas = true;
@ -544,29 +496,24 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
menu.findItem(R.id.sync_lookback).setVisible(isEas);
menu.findItem(R.id.sync_frequency).setVisible(isEas);
ActivityHelper.updateRefreshMenuIcon(
menu.findItem(R.id.refresh), shouldShowRefreshButton(), isProgressActive());
ActivityHelper.updateRefreshMenuIcon(menu.findItem(R.id.refresh),
mUIController.isRefreshEnabled(),
mUIController.isRefreshInProgress());
return super.onPrepareOptionsMenu(menu);
}
private boolean shouldShowRefreshButton() {
// - Don't show for combined inboxes, but
// - Show even for non-refreshable mailboxes, in which case we refresh the mailbox list.
return -1 != mFragmentManager.getActualAccountId();
}
@Override
public boolean onSearchRequested() {
Bundle bundle = new Bundle();
bundle.putLong(EXTRA_ACCOUNT_ID, mFragmentManager.getActualAccountId());
bundle.putLong(EXTRA_MAILBOX_ID, mFragmentManager.getMailboxId());
bundle.putLong(EXTRA_ACCOUNT_ID, mUIController.getActualAccountId());
bundle.putLong(EXTRA_MAILBOX_ID, mUIController.getMailboxId());
startSearch(null, false, bundle, false);
return true;
}
// STOPSHIP Set column from user options
private void setMailboxColumn(String column, String value) {
final long mailboxId = mFragmentManager.getMailboxId();
final long mailboxId = mUIController.getMailboxId();
if (mailboxId > 0) {
ContentValues cv = new ContentValues();
cv.put(column, value);
@ -607,7 +554,7 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
// STOPSHIP Temporary mailbox settings UI
@Override
protected Dialog onCreateDialog(int id, Bundle args) {
Mailbox mailbox = Mailbox.restoreMailboxWithId(this, mFragmentManager.getMailboxId());
Mailbox mailbox = Mailbox.restoreMailboxWithId(this, mUIController.getMailboxId());
if (mailbox == null) return null;
switch (id) {
case MAILBOX_SYNC_FREQUENCY_DIALOG:
@ -683,35 +630,28 @@ public class MessageListXL extends Activity implements MessageListXLFragmentMana
}
private boolean onCompose() {
if (!mFragmentManager.isAccountSelected()) {
if (!mUIController.isAccountSelected()) {
return false; // this shouldn't really happen
}
MessageCompose.actionCompose(this, mFragmentManager.getActualAccountId());
MessageCompose.actionCompose(this, mUIController.getActualAccountId());
return true;
}
private boolean onAccountSettings() {
AccountSettingsXL.actionSettings(this, mFragmentManager.getActualAccountId());
AccountSettingsXL.actionSettings(this, mUIController.getActualAccountId());
return true;
}
private void onRefresh() {
// Cancel previously running instance if any.
new RefreshTask(mTaskTracker, this, mFragmentManager.getActualAccountId(),
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);
new RefreshTask(mTaskTracker, this, mUIController.getActualAccountId(),
mUIController.getMailboxId()).cancelPreviousAndExecuteParallel();
}
/**
* TODO Move this to UIController, as requirement for this may change for the phone.
* (e.g. should we still do the implicit refresh of mailbox list on the phone?)
*
* Class to handle refresh.
*
* When the user press "refresh",

View File

@ -19,18 +19,21 @@ package com.android.email.activity;
import com.android.email.Email;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.RefreshManager;
import com.android.email.activity.setup.AccountSecurity;
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.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import java.security.InvalidParameterException;
import java.util.ArrayList;
@ -48,7 +51,7 @@ import java.util.Set;
*
* TODO Refine "move to".
*/
class MessageListXLFragmentManager implements
class UIControllerTwoPane implements
MoveMessageToDialog.Callback,
MailboxFinder.Callback,
ThreePaneLayout.Callback,
@ -74,6 +77,11 @@ class MessageListXLFragmentManager implements
/** Current message id */
private long mMessageId = NO_MESSAGE;
// UI elements
private ActionBar mActionBar;
private View mActionBarMailboxNameView;
private TextView mActionBarMailboxName;
private TextView mActionBarUnreadCount;
private ThreePaneLayout mThreePane;
/**
@ -94,6 +102,7 @@ class MessageListXLFragmentManager implements
private MailboxFinder mMailboxFinder;
private RefreshManager mRefreshManager;
private MessageOrderManager mOrderManager;
private final MessageOrderManagerCallback mMessageOrderManagerCallback =
new MessageOrderManagerCallback();
@ -101,48 +110,29 @@ class MessageListXLFragmentManager implements
/**
* List of fragments that are restored by the framework while the activity is being re-created
* for configuration changes (e.g. screen rotation). We'll install them later when the activity
* is created.
* is created in {@link #installRestoredFragments()}.
*/
private final ArrayList<Fragment> mRestoredFragments = new ArrayList<Fragment>();
private boolean mActivityCreated = false;
/**
* 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.
* Whether fragment installation should be hold.
* We hold installing fragments until {@link #installRestoredFragments()} is called.
*/
public interface TargetActivity {
/** Implemented by {@link Activity}, so, signature must match */
public ActionBar getActionBar();
public FragmentManager getFragmentManager();
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 boolean mHoldFragmentInstallation = true;
/** The owner activity */
private final MessageListXL mActivity;
public MessageListXLFragmentManager(MessageListXL activity) {
public UIControllerTwoPane(MessageListXL activity) {
mActivity = activity;
mRefreshManager = RefreshManager.getInstance(mActivity);
}
// MailboxFinder$Callback
@Override
public void onAccountNotFound() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onAccountNotFound()");
Log.d(Logging.LOG_TAG, "" + this + " onAccountNotFound()");
}
// Shouldn't happen
}
@ -150,15 +140,16 @@ class MessageListXLFragmentManager implements
@Override
public void onAccountSecurityHold(long accountId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onAccountSecurityHold()");
Log.d(Logging.LOG_TAG, "" + this + " onAccountSecurityHold()");
}
mActivity.onAccountSecurityHold(accountId);
mActivity.startActivity(AccountSecurity.actionUpdateSecurityIntent(mActivity, accountId,
true));
}
@Override
public void onMailboxFound(long accountId, long mailboxId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onMailboxFound()");
Log.d(Logging.LOG_TAG, "" + this + " onMailboxFound()");
}
updateMessageList(mailboxId, true, true);
}
@ -166,7 +157,7 @@ class MessageListXLFragmentManager implements
@Override
public void onMailboxNotFound(long accountId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager#onMailboxNotFound()");
Log.d(Logging.LOG_TAG, "" + this + " onMailboxNotFound()");
}
// TODO: handle more gracefully.
Log.e(Logging.LOG_TAG, "unable to find mailbox for account " + accountId);
@ -188,8 +179,11 @@ class MessageListXLFragmentManager implements
// ThreePaneLayoutCallback
@Override
public void onVisiblePanesChanged(int previousVisiblePanes) {
updateActionBar();
// If the right pane is gone, remove the message view.
final int visiblePanes = mThreePane.getVisiblePanes();
mActivity.onVisiblePanesChanged(visiblePanes);
if (((visiblePanes & ThreePaneLayout.PANE_RIGHT) == 0) &&
((previousVisiblePanes & ThreePaneLayout.PANE_RIGHT) != 0)) {
// Message view just got hidden
@ -200,11 +194,29 @@ class MessageListXLFragmentManager implements
uninstallMessageViewFragment(mActivity.getFragmentManager().beginTransaction())
.commit();
}
// Disable CAB when the message list is not visible.
if (mMessageListFragment != null) {
mMessageListFragment.setVisibility((visiblePanes & ThreePaneLayout.PANE_MIDDLE) != 0);
mMessageListFragment.onHidden((visiblePanes & ThreePaneLayout.PANE_MIDDLE) == 0);
}
}
/**
* Update the action bar according to the current state.
*
* - Show/hide the "back" button next to the "Home" icon.
* - Show/hide the current mailbox name.
*/
private void updateActionBar() {
final int visiblePanes = mThreePane.getVisiblePanes();
// 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);
}
// MailboxListFragment$Callback
@Override
public void onMailboxSelected(long accountId, long mailboxId, boolean navigate,
@ -234,7 +246,12 @@ class MessageListXLFragmentManager implements
@Override
public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) {
mActivity.onMailboxNameChanged(mailboxName, 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(mActivity, unreadCount, true));
}
// MessageListFragment$Callback
@ -380,8 +397,30 @@ class MessageListXLFragmentManager implements
*/
public void onActivityViewReady() {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager onActivityViewReady");
Log.d(Logging.LOG_TAG, "" + this + " onActivityViewReady");
}
// Set up action bar
mActionBar = mActivity.getActionBar();
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME);
// Set a view for the current mailbox to the action bar.
final LayoutInflater inflater = LayoutInflater.from(mActivity);
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(mActivity.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 up content
mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane);
mThreePane.setCallback(this);
@ -432,10 +471,28 @@ class MessageListXLFragmentManager implements
}
/**
* Called at the end of {@link MessageListXL#onCreate}.
* @return true if refresh is in progress for the current mailbox.
*/
public void onActivityCreated() {
mActivityCreated = true;
public boolean isRefreshInProgress() {
return (mMailboxId >= 0) && mRefreshManager.isMessageListRefreshing(mMailboxId);
}
/**
* @return true if the UI should enable the "refresh" command.
*/
public boolean isRefreshEnabled() {
// - Don't show for combined inboxes, but
// - Show even for non-refreshable mailboxes, in which case we refresh the mailbox list
return -1 != getActualAccountId();
}
/**
* Install all the fragments kept in {@link #mRestoredFragments}.
*
* Must be called at the end of {@link MessageListXL#onCreate}.
*/
public void installRestoredFragments() {
mHoldFragmentInstallation = false;
// Install all the fragments restored by the framework.
for (Fragment fragment : mRestoredFragments) {
@ -452,7 +509,7 @@ class MessageListXLFragmentManager implements
* onCreate.
*/
public void onAttachFragment(Fragment fragment) {
if (!mActivityCreated) {
if (mHoldFragmentInstallation) {
// Fragment being restored by the framework during the activity recreation.
mRestoredFragments.add(fragment);
return;
@ -473,8 +530,7 @@ class MessageListXLFragmentManager implements
* Called from {@link MessageListXL#onResume}.
*/
public void onResume() {
int visiblePanes = mThreePane.getVisiblePanes();
mActivity.onVisiblePanesChanged(visiblePanes);
updateActionBar();
}
/**
@ -494,13 +550,13 @@ class MessageListXLFragmentManager implements
* Called from {@link MessageListXL#onDestroy}.
*/
public void onDestroy() {
mActivityCreated = false;
mHoldFragmentInstallation = true; // No more fragment installation.
closeMailboxFinder();
}
public void onSaveInstanceState(Bundle outState) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager onSaveInstanceState");
Log.d(Logging.LOG_TAG, "" + this + " onSaveInstanceState");
}
outState.putLong(BUNDLE_KEY_ACCOUNT_ID, mAccountId);
outState.putLong(BUNDLE_KEY_MAILBOX_ID, mMailboxId);
@ -509,7 +565,7 @@ class MessageListXLFragmentManager implements
public void restoreInstanceState(Bundle savedInstanceState) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "MessageListXLFragmentManager restoreInstanceState");
Log.d(Logging.LOG_TAG, "" + this + " restoreInstanceState");
}
mAccountId = savedInstanceState.getLong(BUNDLE_KEY_ACCOUNT_ID, NO_ACCOUNT);
mMailboxId = savedInstanceState.getLong(BUNDLE_KEY_MAILBOX_ID, NO_MAILBOX);
@ -589,8 +645,8 @@ class MessageListXLFragmentManager implements
*/
public void open(long accountId, long mailboxId, long messageId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "open accountId=" + accountId + " mailboxId=" + mailboxId
+ " messageId=" + messageId);
Log.d(Logging.LOG_TAG, "" + this + " open accountId=" + accountId
+ " mailboxId=" + mailboxId + " messageId=" + messageId);
}
if (accountId == NO_ACCOUNT) {
throw new IllegalArgumentException();
@ -619,6 +675,20 @@ class MessageListXLFragmentManager implements
}
}
/**
* Pre-fragment transaction check.
*
* @throw IllegalStateException if updateXxx methods can't be called in the current state.
*/
private void preFragmentTransactionCheck() {
if (mHoldFragmentInstallation) {
// Code assumes mMailboxListFragment/etc are set right within the
// commitFragmentTransaction() call (because we use synchronous transaction),
// so updateXxx() can't be called if fragments are not installable yet.
throw new IllegalStateException();
}
}
/**
* Loads the given account and optionally selects the given mailbox and message. If the
* specified account is already selected, no actions will be performed unless
@ -639,9 +709,10 @@ class MessageListXLFragmentManager implements
private void updateMailboxList(long accountId, long parentMailboxId,
boolean changeVisiblePane, boolean clearDependentPane) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "updateMailboxList accountId=" + accountId + " parentMailboxId="
+ parentMailboxId);
Log.d(Logging.LOG_TAG, "" + this + " updateMailboxList accountId=" + accountId
+ " parentMailboxId=" + parentMailboxId);
}
preFragmentTransactionCheck();
if (accountId == NO_ACCOUNT) {
throw new InvalidParameterException();
}
@ -704,8 +775,9 @@ class MessageListXLFragmentManager implements
private void updateMessageList(long mailboxId, boolean changeVisiblePane,
boolean clearDependentPane) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "updateMessageList mMailboxId=" + mailboxId);
Log.d(Logging.LOG_TAG, "" + this + " updateMessageList mMailboxId=" + mailboxId);
}
preFragmentTransactionCheck();
if (mailboxId == 0 || mailboxId == -1) {
throw new InvalidParameterException();
}
@ -725,12 +797,12 @@ class MessageListXLFragmentManager implements
ft.add(mThreePane.getMiddlePaneId(), MessageListFragment.newInstance(mailboxId));
commitFragmentTransaction(ft);
mMailboxListFragment.setSelectedMailbox(mailboxId);
mActivity.onMailboxChanged(mAccountId, mailboxId);
if (changeVisiblePane) {
mThreePane.showLeftPane();
}
mMailboxListFragment.setSelectedMailbox(mailboxId);
mActivity.updateRefreshProgress();
}
/**
@ -740,8 +812,9 @@ class MessageListXLFragmentManager implements
*/
private void updateMessageView(long messageId) {
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "updateMessageView messageId=" + messageId);
Log.d(Logging.LOG_TAG, "" + this + " updateMessageView messageId=" + messageId);
}
preFragmentTransactionCheck();
if (messageId == NO_MESSAGE) {
throw new InvalidParameterException();
}
@ -753,8 +826,6 @@ class MessageListXLFragmentManager implements
mMessageId = messageId;
// Open message
mMessageListFragment.setSelectedMessage(mMessageId);
final FragmentManager fm = mActivity.getFragmentManager();
final FragmentTransaction ft = fm.beginTransaction();
uninstallMessageViewFragment(ft);
@ -762,6 +833,8 @@ class MessageListXLFragmentManager implements
commitFragmentTransaction(ft);
mThreePane.showRightPane(); // Show message view
mMessageListFragment.setSelectedMessage(mMessageId);
}
private void closeMailboxFinder() {