ActionBarController.java revision f5418f1f93b02e7fab9f15eb201800b65510998e
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.email.activity; 18 19import com.android.email.R; 20import com.android.emailcommon.Logging; 21import com.android.emailcommon.provider.Account; 22import com.android.emailcommon.provider.Mailbox; 23 24import android.app.ActionBar; 25import android.app.LoaderManager; 26import android.app.LoaderManager.LoaderCallbacks; 27import android.content.Context; 28import android.content.Loader; 29import android.database.Cursor; 30import android.os.Bundle; 31import android.util.Log; 32import android.view.LayoutInflater; 33import android.view.View; 34import android.widget.TextView; 35 36/** 37 * Manages the account name and the custom view part on the action bar. 38 */ 39public class ActionBarController { 40 private static final int LOADER_ID_ACCOUNT_LIST 41 = EmailActivity.ACTION_BAR_CONTROLLER_LOADER_ID_BASE + 0; 42 43 private final Context mContext; 44 private final LoaderManager mLoaderManager; 45 private final ActionBar mActionBar; 46 47 private final View mActionBarMailboxNameView; 48 private final TextView mActionBarMailboxName; 49 private final TextView mActionBarUnreadCount; 50 51 private final ActionBarNavigationCallback mActionBarNavigationCallback = 52 new ActionBarNavigationCallback(); 53 54 private final AccountSelectorAdapter mAccountsSelectorAdapter; 55 private AccountSelectorAdapter.CursorWithExtras mAccountCursor; 56 /** The current account ID; used to determine if the account has changed. */ 57 private long mLastAccountIdForDirtyCheck = Account.NO_ACCOUNT; 58 59 public final Callback mCallback; 60 61 public interface Callback { 62 /** @return true if an account is selected. */ 63 public boolean isAccountSelected(); 64 65 /** 66 * @return currently selected account ID, {@link Account#ACCOUNT_ID_COMBINED_VIEW}, 67 * or -1 if no account is selected. 68 */ 69 public long getUIAccountId(); 70 71 /** @return true if the current mailbox name should be shown. */ 72 public boolean shouldShowMailboxName(); 73 74 /** @return current mailbox name */ 75 public String getCurrentMailboxName(); 76 /** 77 * @return unread count for the current mailbox. (0 if the mailbox doesn't have the concept 78 * of "unread"; e.g. Drafts) 79 */ 80 public int getCurrentMailboxUnreadCount(); 81 82 /** @return the "UP" arrow should be shown. */ 83 public boolean shouldShowUp(); 84 85 /** 86 * Called when an account is selected on the account spinner. 87 * @param accountId ID of the selected account, or {@link Account#ACCOUNT_ID_COMBINED_VIEW}. 88 */ 89 public void onAccountSelected(long accountId); 90 91 /** 92 * Invoked when a recent mailbox is selected on the account spinner. 93 * @param mailboxId The ID of the selected mailbox, or {@link Mailbox#NO_MAILBOX} if the 94 * special option "show all mailboxes" was selected. 95 */ 96 public void onMailboxSelected(long mailboxId); 97 98 /** Called when no accounts are found in the database. */ 99 public void onNoAccountsFound(); 100 } 101 102 public ActionBarController(Context context, LoaderManager loaderManager, 103 ActionBar actionBar, Callback callback) { 104 mContext = context; 105 mLoaderManager = loaderManager; 106 mActionBar = actionBar; 107 mCallback = callback; 108 mAccountsSelectorAdapter = new AccountSelectorAdapter(mContext); 109 110 mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME 111 | ActionBar.DISPLAY_SHOW_CUSTOM); 112 113 // The custom view for the current mailbox and the unread count. 114 final LayoutInflater inflater = LayoutInflater.from(mContext); 115 mActionBarMailboxNameView = inflater.inflate(R.layout.action_bar_current_mailbox, null); 116 final ActionBar.LayoutParams customViewLayout = new ActionBar.LayoutParams( 117 ActionBar.LayoutParams.WRAP_CONTENT, 118 ActionBar.LayoutParams.MATCH_PARENT); 119 customViewLayout.setMargins(mContext.getResources().getDimensionPixelSize( 120 R.dimen.action_bar_mailbox_name_left_margin) , 0, 0, 0); 121 mActionBar.setCustomView(mActionBarMailboxNameView, customViewLayout); 122 123 mActionBarMailboxName = UiUtilities.getView(mActionBarMailboxNameView, R.id.mailbox_name); 124 mActionBarUnreadCount = UiUtilities.getView(mActionBarMailboxNameView, R.id.unread_count); 125 } 126 127 /** 128 * Must be called when the host activity is created. 129 */ 130 public void onActivityCreated() { 131 loadAccounts(); 132 refresh(); 133 } 134 135 /** Refreshes the action bar display. */ 136 public void refresh() { 137 mActionBar.setDisplayOptions(mCallback.shouldShowUp() 138 ? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP); 139 140 mActionBarMailboxNameView.setVisibility(mCallback.shouldShowMailboxName() 141 ? View.VISIBLE : View.GONE); 142 143 mActionBarMailboxName.setText(mCallback.getCurrentMailboxName()); 144 145 // Note on action bar, we show only "unread count". Some mailboxes such as Outbox don't 146 // have the idea of "unread count", in which case we just omit the count. 147 mActionBarUnreadCount.setText(UiUtilities.getMessageCountForUi(mContext, 148 mCallback.getCurrentMailboxUnreadCount(), true)); 149 150 // Update the account list only when the account has changed. 151 if (mLastAccountIdForDirtyCheck != mCallback.getUIAccountId()) { 152 mLastAccountIdForDirtyCheck = mCallback.getUIAccountId(); 153 // If the selected account changes, reload the cursor to update the recent mailboxes 154 if (mLastAccountIdForDirtyCheck != Account.NO_ACCOUNT) { 155 mLoaderManager.destroyLoader(LOADER_ID_ACCOUNT_LIST); 156 loadAccounts(); 157 } else { 158 updateAccountList(); 159 } 160 } 161 } 162 163 /** 164 * Load account cursor, and update the action bar. 165 */ 166 private void loadAccounts() { 167 mLoaderManager.initLoader(LOADER_ID_ACCOUNT_LIST, null, 168 new LoaderCallbacks<Cursor>() { 169 @Override 170 public Loader<Cursor> onCreateLoader(int id, Bundle args) { 171 return AccountSelectorAdapter.createLoader(mContext, mCallback.getUIAccountId()); 172 } 173 174 @Override 175 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 176 mAccountCursor = (AccountSelectorAdapter.CursorWithExtras) data; 177 updateAccountList(); 178 } 179 180 @Override 181 public void onLoaderReset(Loader<Cursor> loader) { 182 mAccountCursor = null; 183 updateAccountList(); 184 } 185 }); 186 } 187 188 /** 189 * Called when the LOADER_ID_ACCOUNT_LIST loader loads the data. Update the account spinner 190 * on the action bar. 191 */ 192 private void updateAccountList() { 193 mAccountsSelectorAdapter.swapCursor(mAccountCursor); 194 195 final ActionBar ab = mActionBar; 196 if (mAccountCursor == null) { 197 // Cursor not ready or closed. 198 mAccountsSelectorAdapter.swapCursor(null); 199 ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); 200 ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 201 return; 202 } 203 204 final int count = mAccountCursor.mAccountCount + mAccountCursor.mRecentCount; 205 if (count == 0) { 206 mCallback.onNoAccountsFound(); 207 return; 208 } 209 210 // If only one account, don't show the drop down. 211 int selectedPosition = mAccountCursor.getPosition(mCallback.getUIAccountId()); 212 if (count == 1) { 213 // Show the account name as the title. 214 ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE); 215 ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); 216 if (selectedPosition >= 0) { 217 mAccountCursor.moveToPosition(selectedPosition); 218 ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(mAccountCursor)); 219 } 220 return; 221 } 222 223 // Update the drop down list. 224 if (ab.getNavigationMode() != ActionBar.NAVIGATION_MODE_LIST) { 225 ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE); 226 ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 227 ab.setListNavigationCallbacks(mAccountsSelectorAdapter, mActionBarNavigationCallback); 228 } 229 // Find the currently selected account, and select it. 230 if (selectedPosition >= 0) { 231 ab.setSelectedNavigationItem(selectedPosition); 232 } 233 } 234 235 private class ActionBarNavigationCallback implements ActionBar.OnNavigationListener { 236 @Override 237 public boolean onNavigationItemSelected(int itemPosition, long itemId) { 238 if (mAccountsSelectorAdapter.isAccountItem(itemPosition) 239 && itemId != mCallback.getUIAccountId()) { 240 mCallback.onAccountSelected(itemId); 241 } else if (mAccountsSelectorAdapter.isMailboxItem(itemPosition)) { 242 mCallback.onMailboxSelected(itemId); 243 // We need to update the selection, otherwise the user is unable to select the 244 // recent folder a second time w/o first selecting another item in the spinner 245 int selectedPosition = mAccountsSelectorAdapter.getAccountPosition(itemPosition); 246 if (selectedPosition != AccountSelectorAdapter.UNKNOWN_POSITION) { 247 mActionBar.setSelectedNavigationItem(selectedPosition); 248 } 249 } else { 250 Log.i(Logging.LOG_TAG, 251 "Invalid type selected in ActionBarController at index " + itemPosition); 252 } 253 return true; 254 } 255 } 256} 257