Merge "Extract action bar related code"

This commit is contained in:
Makoto Onuki 2011-05-09 09:24:49 -07:00 committed by Android (Google) Code Review
commit c0042a2278
3 changed files with 324 additions and 158 deletions

View File

@ -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<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return AccountSelectorAdapter.createLoader(mContext);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAccountsSelectorCursor = data;
updateAccountList();
}
@Override
public void onLoaderReset(Loader<Cursor> 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;
}
}
}

View File

@ -68,6 +68,9 @@ public class EmailActivity extends Activity implements View.OnClickListener {
/** Loader IDs starting with this is safe to use from UIControllers. */ /** Loader IDs starting with this is safe to use from UIControllers. */
static final int UI_CONTROLLER_LOADER_ID_BASE = 100; 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_FREQUENCY_DIALOG = 1;
private static final int MAILBOX_SYNC_LOOKBACK_DIALOG = 2; private static final int MAILBOX_SYNC_LOOKBACK_DIALOG = 2;

View File

@ -29,23 +29,16 @@ import com.android.emailcommon.provider.EmailContent.Mailbox;
import com.android.emailcommon.utility.EmailAsyncTask; import com.android.emailcommon.utility.EmailAsyncTask;
import com.android.emailcommon.utility.Utility; import com.android.emailcommon.utility.Utility;
import android.app.ActionBar;
import android.app.Activity; import android.app.Activity;
import android.app.Fragment; import android.app.Fragment;
import android.app.FragmentManager; import android.app.FragmentManager;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context; import android.content.Context;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.util.ArrayList; 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 MAILBOX_REFRESH_MIN_INTERVAL = 30 * 1000; // in milliseconds
/* package */ static final int INBOX_AUTO_REFRESH_MIN_INTERVAL = 10 * 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 */ /** No account selected */
static final long NO_ACCOUNT = -1; static final long NO_ACCOUNT = -1;
/** No mailbox selected */ /** No mailbox selected */
@ -102,14 +92,9 @@ class UIControllerTwoPane implements
/** Current message id */ /** Current message id */
private long mMessageId = NO_MESSAGE; private long mMessageId = NO_MESSAGE;
// Action bar private ActionBarController mActionBarController;
private ActionBar mActionBar; private final ActionBarControllerCallback mActionBarControllerCallback =
private AccountSelectorAdapter mAccountsSelectorAdapter; new ActionBarControllerCallback();
private final ActionBarNavigationCallback mActionBarNavigationCallback =
new ActionBarNavigationCallback();
private View mActionBarMailboxNameView;
private TextView mActionBarMailboxName;
private TextView mActionBarUnreadCount;
// Other UI elements // Other UI elements
private ThreePaneLayout mThreePane; private ThreePaneLayout mThreePane;
@ -140,6 +125,20 @@ class UIControllerTwoPane implements
/** Mailbox IDs that the user has navigated away from; used to provide "back" functionality */ /** Mailbox IDs that the user has navigated away from; used to provide "back" functionality */
private final Stack<Long> mMailboxStack = new Stack<Long>(); private final Stack<Long> mMailboxStack = new Stack<Long>();
/**
* 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 * 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 * for configuration changes (e.g. screen rotation). We'll install them later when the activity
@ -207,8 +206,7 @@ class UIControllerTwoPane implements
// ThreePaneLayoutCallback // ThreePaneLayoutCallback
@Override @Override
public void onVisiblePanesChanged(int previousVisiblePanes) { public void onVisiblePanesChanged(int previousVisiblePanes) {
refreshActionBar();
updateActionBar();
// If the right pane is gone, remove the message view. // If the right pane is gone, remove the message view.
final int visiblePanes = mThreePane.getVisiblePanes(); final int visiblePanes = mThreePane.getVisiblePanes();
@ -228,22 +226,10 @@ class UIControllerTwoPane implements
} }
} }
/** private void refreshActionBar() {
* Update the action bar according to the current state. if (mActionBarController != null) {
* mActionBarController.refresh();
* - 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);
} }
// MailboxListFragment$Callback // MailboxListFragment$Callback
@ -276,18 +262,14 @@ class UIControllerTwoPane implements
// TODO openAccount should do the check eventually, but it's necessary for now. // TODO openAccount should do the check eventually, but it's necessary for now.
if (accountId != getUIAccountId()) { if (accountId != getUIAccountId()) {
openAccount(accountId); openAccount(accountId);
loadAccounts(); // update account spinner
} }
} }
@Override @Override
public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) { public void onCurrentMailboxUpdated(long mailboxId, String mailboxName, int unreadCount) {
mActionBarMailboxName.setText(mailboxName); mCurrentMailboxName = mailboxName;
mCurrentMailboxUnreadCount = unreadCount;
// Note on action bar, we show only "unread count". Some mailboxes such as Outbox don't refreshActionBar();
// have the idea of "unread count", in which case we just omit the count.
mActionBarUnreadCount.setText(
UiUtilities.getMessageCountForUi(mActivity, unreadCount, true));
} }
// MessageListFragment$Callback // MessageListFragment$Callback
@ -433,26 +415,8 @@ class UIControllerTwoPane implements
if (Email.DEBUG_LIFECYCLE && Email.DEBUG) { if (Email.DEBUG_LIFECYCLE && Email.DEBUG) {
Log.d(Logging.LOG_TAG, "" + this + " onActivityViewReady"); Log.d(Logging.LOG_TAG, "" + this + " onActivityViewReady");
} }
// Set up action bar mActionBarController = new ActionBarController(mActivity, mActivity.getLoaderManager(),
mActionBar = mActivity.getActionBar(); mActivity.getActionBar(), mActionBarControllerCallback);
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 // Set up content
mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane); mThreePane = (ThreePaneLayout) mActivity.findViewById(R.id.three_pane);
@ -534,7 +498,7 @@ class UIControllerTwoPane implements
*/ */
public void onActivityCreated() { public void onActivityCreated() {
mRefreshManager.registerListener(mRefreshListener); mRefreshManager.registerListener(mRefreshListener);
loadAccounts(); mActionBarController.onActivityCreated();
} }
/** /**
@ -581,7 +545,7 @@ class UIControllerTwoPane implements
* Called from {@link EmailActivity#onResume}. * Called from {@link EmailActivity#onResume}.
*/ */
public void onResume() { public void onResume() {
updateActionBar(); refreshActionBar();
} }
/** /**
@ -698,8 +662,8 @@ class UIControllerTwoPane implements
*/ */
public void openAccount(long accountId) { public void openAccount(long accountId) {
mMailboxStack.clear(); mMailboxStack.clear();
updateActionBar();
open(accountId, NO_MAILBOX, NO_MESSAGE); 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. * mailbox is not associated with the account, the behaviour is undefined.
*/ */
private void openMailbox(long accountId, long mailboxId) { private void openMailbox(long accountId, long mailboxId) {
updateActionBar();
updateMailboxList(accountId, mailboxId, true, true); updateMailboxList(accountId, mailboxId, true, true);
updateMessageList(mailboxId, true, true); updateMessageList(mailboxId, true, true);
refreshActionBar();
} }
/** /**
@ -1012,97 +976,6 @@ class UIControllerTwoPane implements
return false; 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<Cursor>() {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return AccountSelectorAdapter.createLoader(mActivity);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
updateAccountList(data);
}
@Override
public void onLoaderReset(Loader<Cursor> 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. * Handles {@link android.app.Activity#onCreateOptionsMenu} callback.
*/ */
@ -1321,4 +1194,50 @@ class UIControllerTwoPane implements
return true; 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();
}
}
} }