From ad71b358c639b3dc24b5047338af6f6b6b211f65 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Thu, 5 May 2011 14:22:33 -0700 Subject: [PATCH] Extract action bar related code ...so that we can easily reuse it for the one pane UI controller. The one pane controller should eventually have its own action bar controller, but we can use it for the time beeing, until we get more detailed UI spec. Change-Id: I10c92963350dad9eb834fd7474c597aedad5eb80 --- .../email/activity/ActionBarController.java | 244 ++++++++++++++++++ .../android/email/activity/EmailActivity.java | 3 + .../email/activity/UIControllerTwoPane.java | 235 ++++++----------- 3 files changed, 324 insertions(+), 158 deletions(-) create mode 100644 src/com/android/email/activity/ActionBarController.java diff --git a/src/com/android/email/activity/ActionBarController.java b/src/com/android/email/activity/ActionBarController.java new file mode 100644 index 000000000..2db3b7caf --- /dev/null +++ b/src/com/android/email/activity/ActionBarController.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2011 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.R; +import com.android.emailcommon.Logging; +import com.android.emailcommon.provider.EmailContent.Account; + +import android.app.ActionBar; +import android.app.LoaderManager; +import android.app.LoaderManager.LoaderCallbacks; +import android.content.Context; +import android.content.Loader; +import android.database.Cursor; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +/** + * Manages the account name and the custom view part on the action bar. + */ +public class ActionBarController { + private static final int LOADER_ID_ACCOUNT_LIST + = EmailActivity.ACTION_BAR_CONTROLLER_LOADER_ID_BASE + 0; + + private final Context mContext; + private final LoaderManager mLoaderManager; + private final ActionBar mActionBar; + + private final View mActionBarMailboxNameView; + private final TextView mActionBarMailboxName; + private final TextView mActionBarUnreadCount; + + private final ActionBarNavigationCallback mActionBarNavigationCallback = + new ActionBarNavigationCallback(); + + private final AccountSelectorAdapter mAccountsSelectorAdapter; + private Cursor mAccountsSelectorCursor; + + public final Callback mCallback; + + public interface Callback { + /** @return true if an account is selected. */ + public boolean isAccountSelected(); + + /** + * @return currently selected account ID, {@link Account#ACCOUNT_ID_COMBINED_VIEW}, + * or -1 if no account is selected. + */ + public long getUIAccountId(); + + /** @return true if the current mailbox name should be shown. */ + public boolean shouldShowMailboxName(); + + /** @return current mailbox name */ + public String getCurrentMailboxName(); + /** + * @return unread count for the current mailbox. (0 if the mailbox doesn't have the concept + * of "unread"; e.g. Drafts) + */ + public int getCurrentMailboxUnreadCount(); + + /** @return the "UP" arrow should be shown. */ + public boolean shouldShowUp(); + + /** + * Called when an account is selected on the account spinner. + * + * @param accountId ID of the selected account, or + * {@link Account#ACCOUNT_ID_COMBINED_VIEW}. + */ + public void onAccountSelected(long accountId); + + /** Called when no accounts are found in the database. */ + public void onNoAccountsFound(); + } + + public ActionBarController(Context context, LoaderManager loaderManager, + ActionBar actionBar, Callback callback) { + mContext = context; + mLoaderManager = loaderManager; + mActionBar = actionBar; + mCallback = callback; + mAccountsSelectorAdapter = new AccountSelectorAdapter(mContext); + + mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME + | ActionBar.DISPLAY_SHOW_CUSTOM); + + // The custom view for the current mailbox and the unread count. + final LayoutInflater inflater = LayoutInflater.from(mContext); + mActionBarMailboxNameView = inflater.inflate(R.layout.action_bar_current_mailbox, null); + 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 = UiUtilities.getView(mActionBarMailboxNameView, R.id.mailbox_name); + mActionBarUnreadCount = UiUtilities.getView(mActionBarMailboxNameView, R.id.unread_count); + } + + /** + * Must be called when the host activity is created. + */ + public void onActivityCreated() { + loadAccounts(); + refresh(); + } + + /** Used only in {@link #refresh()} to determine if the account has changed. */ + private long mLastAccountIdForDirtyCheck = -1; + + /** + * Refresh the content. + */ + public void refresh() { + mActionBar.setDisplayOptions(mCallback.shouldShowUp() + ? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP); + + mActionBarMailboxNameView.setVisibility(mCallback.shouldShowMailboxName() + ? View.VISIBLE : View.GONE); + + mActionBarMailboxName.setText(mCallback.getCurrentMailboxName()); + + // 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, + mCallback.getCurrentMailboxUnreadCount(), true)); + + // Update the account list only when the account has changed. + if (mLastAccountIdForDirtyCheck != mCallback.getUIAccountId()) { + mLastAccountIdForDirtyCheck = mCallback.getUIAccountId(); + updateAccountList(); + } + } + + /** + * Load account cursor, and update the action bar. + */ + private void loadAccounts() { + mLoaderManager.initLoader(LOADER_ID_ACCOUNT_LIST, null, + new LoaderCallbacks() { + @Override + public Loader onCreateLoader(int id, Bundle args) { + return AccountSelectorAdapter.createLoader(mContext); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + mAccountsSelectorCursor = data; + updateAccountList(); + } + + @Override + public void onLoaderReset(Loader loader) { + mAccountsSelectorCursor = null; + updateAccountList(); + } + }); + } + + /** + * Called when the LOADER_ID_ACCOUNT_LIST loader loads the data. Update the account spinner + * on the action bar. + */ + private void updateAccountList() { + mAccountsSelectorAdapter.swapCursor(mAccountsSelectorCursor); + + final ActionBar ab = mActionBar; + if (mAccountsSelectorCursor == null) { + // Cursor not ready or closed. + mAccountsSelectorAdapter.swapCursor(null); + ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); + ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + return; + } + + final int count = mAccountsSelectorCursor.getCount(); + if (count == 0) { + mCallback.onNoAccountsFound(); + return; + } + + // If only one acount, don't show the dropdown. + if (count == 1) { + mAccountsSelectorCursor.moveToFirst(); + + // Show the account name as the title. + ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); + ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(mAccountsSelectorCursor)); + return; + } + + // Find the currently selected account, and select it. + int defaultSelection = 0; + if (mCallback.isAccountSelected()) { + final long accountId = mCallback.getUIAccountId(); + mAccountsSelectorCursor.moveToPosition(-1); + int i = 0; + while (mAccountsSelectorCursor.moveToNext()) { + if (accountId == AccountSelectorAdapter.getAccountId(mAccountsSelectorCursor)) { + defaultSelection = i; + break; + } + i++; + } + } + + // Update the dropdown list. + if (ab.getNavigationMode() != ActionBar.NAVIGATION_MODE_LIST) { + ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); + ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + ab.setListNavigationCallbacks(mAccountsSelectorAdapter, mActionBarNavigationCallback); + } + ab.setSelectedNavigationItem(defaultSelection); + } + + private class ActionBarNavigationCallback implements ActionBar.OnNavigationListener { + @Override + public boolean onNavigationItemSelected(int itemPosition, long accountId) { + if (accountId != mCallback.getUIAccountId()) { + mCallback.onAccountSelected(accountId); + } + return true; + } + } +} diff --git a/src/com/android/email/activity/EmailActivity.java b/src/com/android/email/activity/EmailActivity.java index cd05b326d..6df605657 100644 --- a/src/com/android/email/activity/EmailActivity.java +++ b/src/com/android/email/activity/EmailActivity.java @@ -66,6 +66,9 @@ public class EmailActivity extends Activity implements View.OnClickListener { /** Loader IDs starting with this is safe to use from UIControllers. */ static final int UI_CONTROLLER_LOADER_ID_BASE = 100; + /** Loader IDs starting with this is safe to use from ActionBarController. */ + static final int ACTION_BAR_CONTROLLER_LOADER_ID_BASE = 200; + private static final int MAILBOX_SYNC_FREQUENCY_DIALOG = 1; private static final int MAILBOX_SYNC_LOOKBACK_DIALOG = 2; diff --git a/src/com/android/email/activity/UIControllerTwoPane.java b/src/com/android/email/activity/UIControllerTwoPane.java index 9794e497c..13afb364d 100644 --- a/src/com/android/email/activity/UIControllerTwoPane.java +++ b/src/com/android/email/activity/UIControllerTwoPane.java @@ -29,23 +29,16 @@ import com.android.emailcommon.provider.EmailContent.Mailbox; import com.android.emailcommon.utility.EmailAsyncTask; import com.android.emailcommon.utility.Utility; -import android.app.ActionBar; import android.app.Activity; import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; -import android.app.LoaderManager.LoaderCallbacks; import android.content.Context; -import android.content.Loader; -import android.database.Cursor; import android.os.Bundle; import android.util.Log; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; import java.security.InvalidParameterException; import java.util.ArrayList; @@ -78,9 +71,6 @@ class UIControllerTwoPane implements /* package */ static final int MAILBOX_REFRESH_MIN_INTERVAL = 30 * 1000; // in milliseconds /* package */ static final int INBOX_AUTO_REFRESH_MIN_INTERVAL = 10 * 1000; // in milliseconds - private static final int LOADER_ID_ACCOUNT_LIST - = EmailActivity.UI_CONTROLLER_LOADER_ID_BASE + 0; - /** No account selected */ static final long NO_ACCOUNT = -1; /** No mailbox selected */ @@ -102,14 +92,9 @@ class UIControllerTwoPane implements /** Current message id */ private long mMessageId = NO_MESSAGE; - // Action bar - private ActionBar mActionBar; - private AccountSelectorAdapter mAccountsSelectorAdapter; - private final ActionBarNavigationCallback mActionBarNavigationCallback = - new ActionBarNavigationCallback(); - private View mActionBarMailboxNameView; - private TextView mActionBarMailboxName; - private TextView mActionBarUnreadCount; + private ActionBarController mActionBarController; + private final ActionBarControllerCallback mActionBarControllerCallback = + new ActionBarControllerCallback(); // Other UI elements private ThreePaneLayout mThreePane; @@ -140,6 +125,20 @@ class UIControllerTwoPane implements /** Mailbox IDs that the user has navigated away from; used to provide "back" functionality */ private final Stack mMailboxStack = new Stack(); + /** + * The mailbox name selected on the mailbox list. + * Passed via {@link #onCurrentMailboxUpdated}. + */ + private String mCurrentMailboxName; + + /** + * The unread count for the mailbox selected on the mailbox list. + * Passed via {@link #onCurrentMailboxUpdated}. + * + * 0 if the mailbox doesn't have the concept of "unread". e.g. Drafts. + */ + private int mCurrentMailboxUnreadCount; + /** * 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 @@ -207,8 +206,7 @@ class UIControllerTwoPane implements // ThreePaneLayoutCallback @Override public void onVisiblePanesChanged(int previousVisiblePanes) { - - updateActionBar(); + refreshActionBar(); // If the right pane is gone, remove the message view. final int visiblePanes = mThreePane.getVisiblePanes(); @@ -228,22 +226,10 @@ class UIControllerTwoPane implements } } - /** - * 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); - boolean displayUp = leftPaneHidden || !mMailboxStack.isEmpty(); - mActionBar.setDisplayOptions(displayUp ? ActionBar.DISPLAY_HOME_AS_UP : 0, - ActionBar.DISPLAY_HOME_AS_UP); - mActionBarMailboxNameView.setVisibility(leftPaneHidden ? View.VISIBLE : View.GONE); + private void refreshActionBar() { + if (mActionBarController != null) { + mActionBarController.refresh(); + } } // MailboxListFragment$Callback @@ -276,18 +262,14 @@ class UIControllerTwoPane implements // TODO openAccount should do the check eventually, but it's necessary for now. if (accountId != getUIAccountId()) { openAccount(accountId); - loadAccounts(); // update account spinner } } @Override public void onCurrentMailboxUpdated(long mailboxId, 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(mActivity, unreadCount, true)); + mCurrentMailboxName = mailboxName; + mCurrentMailboxUnreadCount = unreadCount; + refreshActionBar(); } // MessageListFragment$Callback @@ -433,26 +415,8 @@ class UIControllerTwoPane implements if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { 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); - + mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(), + mActivity.getActionBar(), mActionBarControllerCallback); // Set up content mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane); @@ -534,7 +498,7 @@ class UIControllerTwoPane implements */ public void onActivityCreated() { mRefreshManager.registerListener(mRefreshListener); - loadAccounts(); + mActionBarController.onActivityCreated(); } /** @@ -581,7 +545,7 @@ class UIControllerTwoPane implements * Called from {@link EmailActivity#onResume}. */ public void onResume() { - updateActionBar(); + refreshActionBar(); } /** @@ -698,8 +662,8 @@ class UIControllerTwoPane implements */ public void openAccount(long accountId) { mMailboxStack.clear(); - updateActionBar(); open(accountId, NO_MAILBOX, NO_MESSAGE); + refreshActionBar(); } /** @@ -710,9 +674,9 @@ class UIControllerTwoPane implements * mailbox is not associated with the account, the behaviour is undefined. */ private void openMailbox(long accountId, long mailboxId) { - updateActionBar(); updateMailboxList(accountId, mailboxId, true, true); updateMessageList(mailboxId, true, true); + refreshActionBar(); } /** @@ -1012,97 +976,6 @@ class UIControllerTwoPane implements return false; } - /** - * Load account list for the action bar. - * - * If there's only one account configured, show the account name in the action bar. - * If more than one account are configured, show a spinner in the action bar, and select the - * current account. - */ - private void loadAccounts() { - if (mAccountsSelectorAdapter == null) { - mAccountsSelectorAdapter = new AccountSelectorAdapter(mActivity); - } - mActivity.getLoaderManager().initLoader(LOADER_ID_ACCOUNT_LIST, null, - new LoaderCallbacks() { - @Override - public Loader onCreateLoader(int id, Bundle args) { - return AccountSelectorAdapter.createLoader(mActivity); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - updateAccountList(data); - } - - @Override - public void onLoaderReset(Loader loader) { - mAccountsSelectorAdapter.swapCursor(null); - } - }); - } - - /** - * Called when the LOADER_ID_ACCOUNT_LIST loader loads the data. Update the account spinner - * on the action bar. - */ - private void updateAccountList(Cursor accountsCursor) { - final int count = accountsCursor.getCount(); - if (count == 0) { - // Open Welcome, which in turn shows the adding a new account screen. - Welcome.actionStart(mActivity); - mActivity.finish(); - return; - } - - // If ony one acount, don't show dropdown. - final ActionBar ab = mActionBar; - if (count == 1) { - accountsCursor.moveToFirst(); - - // Show the account name as the title. - ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); - ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(accountsCursor)); - return; - } - - // Find the currently selected account, and select it. - int defaultSelection = 0; - if (isAccountSelected()) { - accountsCursor.moveToPosition(-1); - int i = 0; - while (accountsCursor.moveToNext()) { - final long accountId = AccountSelectorAdapter.getAccountId(accountsCursor); - if (accountId == getUIAccountId()) { - defaultSelection = i; - break; - } - i++; - } - } - - // Update the dropdown list. - mAccountsSelectorAdapter.swapCursor(accountsCursor); - - // Don't show the title. - ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); - ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); - ab.setListNavigationCallbacks(mAccountsSelectorAdapter, mActionBarNavigationCallback); - ab.setSelectedNavigationItem(defaultSelection); - } - - private class ActionBarNavigationCallback implements ActionBar.OnNavigationListener { - @Override - public boolean onNavigationItemSelected(int itemPosition, long accountId) { - // TODO openAccount should do the check eventually, but it's necessary for now. - if (accountId != getUIAccountId()) { - openAccount(accountId); - } - return true; - } - } - /** * Handles {@link android.app.Activity#onCreateOptionsMenu} callback. */ @@ -1321,4 +1194,50 @@ class UIControllerTwoPane implements return true; } } + + private class ActionBarControllerCallback implements ActionBarController.Callback { + @Override + public String getCurrentMailboxName() { + return mCurrentMailboxName; + } + + @Override + public int getCurrentMailboxUnreadCount() { + return mCurrentMailboxUnreadCount; + } + + @Override + public long getUIAccountId() { + return UIControllerTwoPane.this.getUIAccountId(); + } + + @Override + public boolean isAccountSelected() { + return UIControllerTwoPane.this.isAccountSelected(); + } + + @Override + public void onAccountSelected(long accountId) { + openAccount(accountId); + } + + @Override + public void onNoAccountsFound() { + Welcome.actionStart(mActivity); + mActivity.finish(); + } + + @Override + public boolean shouldShowMailboxName() { + // Show when the left pane is hidden. + return (mThreePane.getVisiblePanes() & ThreePaneLayout.PANE_LEFT) == 0; + } + + @Override + public boolean shouldShowUp() { + final int visiblePanes = mThreePane.getVisiblePanes(); + final boolean leftPaneHidden = ((visiblePanes & ThreePaneLayout.PANE_LEFT) == 0); + return leftPaneHidden || !mMailboxStack.isEmpty(); + } + } }