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