ActionBarController.java revision ad71b358c639b3dc24b5047338af6f6b6b211f65
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.EmailContent.Account;
22
23import android.app.ActionBar;
24import android.app.LoaderManager;
25import android.app.LoaderManager.LoaderCallbacks;
26import android.content.Context;
27import android.content.Loader;
28import android.database.Cursor;
29import android.os.Bundle;
30import android.view.LayoutInflater;
31import android.view.View;
32import android.widget.TextView;
33
34/**
35 * Manages the account name and the custom view part on the action bar.
36 */
37public class ActionBarController {
38    private static final int LOADER_ID_ACCOUNT_LIST
39            = EmailActivity.ACTION_BAR_CONTROLLER_LOADER_ID_BASE + 0;
40
41    private final Context mContext;
42    private final LoaderManager mLoaderManager;
43    private final ActionBar mActionBar;
44
45    private final View mActionBarMailboxNameView;
46    private final TextView mActionBarMailboxName;
47    private final TextView mActionBarUnreadCount;
48
49    private final ActionBarNavigationCallback mActionBarNavigationCallback =
50        new ActionBarNavigationCallback();
51
52    private final AccountSelectorAdapter mAccountsSelectorAdapter;
53    private Cursor mAccountsSelectorCursor;
54
55    public final Callback mCallback;
56
57    public interface Callback {
58        /** @return true if an account is selected. */
59        public boolean isAccountSelected();
60
61        /**
62         * @return currently selected account ID, {@link Account#ACCOUNT_ID_COMBINED_VIEW},
63         * or -1 if no account is selected.
64         */
65        public long getUIAccountId();
66
67        /** @return true if the current mailbox name should be shown.  */
68        public boolean shouldShowMailboxName();
69
70        /** @return current mailbox name */
71        public String getCurrentMailboxName();
72        /**
73         * @return unread count for the current mailbox.  (0 if the mailbox doesn't have the concept
74         *     of "unread"; e.g. Drafts)
75         */
76        public int getCurrentMailboxUnreadCount();
77
78        /** @return the "UP" arrow should be shown. */
79        public boolean shouldShowUp();
80
81        /**
82         * Called when an account is selected on the account spinner.
83         *
84         * @param accountId ID of the selected account, or
85         * {@link Account#ACCOUNT_ID_COMBINED_VIEW}.
86         */
87        public void onAccountSelected(long accountId);
88
89        /** Called when no accounts are found in the database. */
90        public void onNoAccountsFound();
91    }
92
93    public ActionBarController(Context context, LoaderManager loaderManager,
94            ActionBar actionBar, Callback callback) {
95        mContext = context;
96        mLoaderManager = loaderManager;
97        mActionBar = actionBar;
98        mCallback = callback;
99        mAccountsSelectorAdapter = new AccountSelectorAdapter(mContext);
100
101        mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME
102                | ActionBar.DISPLAY_SHOW_CUSTOM);
103
104        // The custom view for the current mailbox and the unread count.
105        final LayoutInflater inflater = LayoutInflater.from(mContext);
106        mActionBarMailboxNameView = inflater.inflate(R.layout.action_bar_current_mailbox, null);
107        final ActionBar.LayoutParams customViewLayout = new ActionBar.LayoutParams(
108                ActionBar.LayoutParams.WRAP_CONTENT,
109                ActionBar.LayoutParams.MATCH_PARENT);
110        customViewLayout.setMargins(mContext.getResources().getDimensionPixelSize(
111                        R.dimen.action_bar_mailbox_name_left_margin) , 0, 0, 0);
112        mActionBar.setCustomView(mActionBarMailboxNameView, customViewLayout);
113
114        mActionBarMailboxName = UiUtilities.getView(mActionBarMailboxNameView, R.id.mailbox_name);
115        mActionBarUnreadCount = UiUtilities.getView(mActionBarMailboxNameView, R.id.unread_count);
116    }
117
118    /**
119     * Must be called when the host activity is created.
120     */
121    public void onActivityCreated() {
122        loadAccounts();
123        refresh();
124    }
125
126    /** Used only in {@link #refresh()} to determine if the account has changed. */
127    private long mLastAccountIdForDirtyCheck = -1;
128
129    /**
130     * Refresh the content.
131     */
132    public void refresh() {
133        mActionBar.setDisplayOptions(mCallback.shouldShowUp()
134                ? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP);
135
136        mActionBarMailboxNameView.setVisibility(mCallback.shouldShowMailboxName()
137                ? View.VISIBLE : View.GONE);
138
139        mActionBarMailboxName.setText(mCallback.getCurrentMailboxName());
140
141        // Note on action bar, we show only "unread count".  Some mailboxes such as Outbox don't
142        // have the idea of "unread count", in which case we just omit the count.
143        mActionBarUnreadCount.setText(UiUtilities.getMessageCountForUi(mContext,
144                mCallback.getCurrentMailboxUnreadCount(), true));
145
146        // Update the account list only when the account has changed.
147        if (mLastAccountIdForDirtyCheck != mCallback.getUIAccountId()) {
148            mLastAccountIdForDirtyCheck = mCallback.getUIAccountId();
149            updateAccountList();
150        }
151    }
152
153    /**
154     * Load account cursor, and update the action bar.
155     */
156    private void loadAccounts() {
157        mLoaderManager.initLoader(LOADER_ID_ACCOUNT_LIST, null,
158                new LoaderCallbacks<Cursor>() {
159            @Override
160            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
161                return AccountSelectorAdapter.createLoader(mContext);
162            }
163
164            @Override
165            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
166                mAccountsSelectorCursor = data;
167                updateAccountList();
168            }
169
170            @Override
171            public void onLoaderReset(Loader<Cursor> loader) {
172                mAccountsSelectorCursor = null;
173                updateAccountList();
174            }
175        });
176    }
177
178    /**
179     * Called when the LOADER_ID_ACCOUNT_LIST loader loads the data.  Update the account spinner
180     * on the action bar.
181     */
182    private void updateAccountList() {
183        mAccountsSelectorAdapter.swapCursor(mAccountsSelectorCursor);
184
185        final ActionBar ab = mActionBar;
186        if (mAccountsSelectorCursor == null) {
187            // Cursor not ready or closed.
188            mAccountsSelectorAdapter.swapCursor(null);
189            ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
190            ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
191            return;
192        }
193
194        final int count = mAccountsSelectorCursor.getCount();
195        if (count == 0) {
196            mCallback.onNoAccountsFound();
197            return;
198        }
199
200        // If only one acount, don't show the dropdown.
201        if (count == 1) {
202            mAccountsSelectorCursor.moveToFirst();
203
204            // Show the account name as the title.
205            ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE, ActionBar.DISPLAY_SHOW_TITLE);
206            ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
207            ab.setTitle(AccountSelectorAdapter.getAccountDisplayName(mAccountsSelectorCursor));
208            return;
209        }
210
211        // Find the currently selected account, and select it.
212        int defaultSelection = 0;
213        if (mCallback.isAccountSelected()) {
214            final long accountId = mCallback.getUIAccountId();
215            mAccountsSelectorCursor.moveToPosition(-1);
216            int i = 0;
217            while (mAccountsSelectorCursor.moveToNext()) {
218                if (accountId == AccountSelectorAdapter.getAccountId(mAccountsSelectorCursor)) {
219                    defaultSelection = i;
220                    break;
221                }
222                i++;
223            }
224        }
225
226        // Update the dropdown list.
227        if (ab.getNavigationMode() != ActionBar.NAVIGATION_MODE_LIST) {
228            ab.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
229            ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
230            ab.setListNavigationCallbacks(mAccountsSelectorAdapter, mActionBarNavigationCallback);
231        }
232        ab.setSelectedNavigationItem(defaultSelection);
233    }
234
235    private class ActionBarNavigationCallback implements ActionBar.OnNavigationListener {
236        @Override
237        public boolean onNavigationItemSelected(int itemPosition, long accountId) {
238            if (accountId != mCallback.getUIAccountId()) {
239                mCallback.onAccountSelected(accountId);
240            }
241            return true;
242        }
243    }
244}
245