blob: 13b53129ec3d0159a24d2624ac7ad485adb735e9 [file] [log] [blame]
Mindy Pereira68f2e222012-03-07 10:36:54 -08001/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -08004 *
Mindy Pereira68f2e222012-03-07 10:36:54 -08005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -08008 *
Mindy Pereira68f2e222012-03-07 10:36:54 -08009 * http://www.apache.org/licenses/LICENSE-2.0
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080010 *
Mindy Pereira68f2e222012-03-07 10:36:54 -080011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080017
Vikram Aggarwal1ddcf0f2012-01-13 11:45:02 -080018package com.android.mail.ui;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080019
20import android.app.ActionBar;
Mindy Pereira68f2e222012-03-07 10:36:54 -080021import android.app.SearchManager;
22import android.app.SearchableInfo;
Vikram Aggarwal2175d0a2012-02-17 16:04:23 -080023import android.app.ActionBar.OnNavigationListener;
Mindy Pereira68f2e222012-03-07 10:36:54 -080024import android.content.Context;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080025import android.os.Bundle;
Mindy Pereira68f2e222012-03-07 10:36:54 -080026import android.util.AttributeSet;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080027import android.view.Menu;
Mindy Pereira68f2e222012-03-07 10:36:54 -080028import android.view.MenuItem;
29import android.view.View;
30import android.widget.LinearLayout;
31import android.widget.SearchView;
32import android.widget.SearchView.OnQueryTextListener;
33import android.widget.SpinnerAdapter;
34import android.widget.TextView;
35import android.widget.Toast;
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080036
Mindy Pereira68f2e222012-03-07 10:36:54 -080037import com.android.mail.R;
38import com.android.mail.AccountSpinnerAdapter;
39import com.android.mail.ConversationListContext;
Vikram Aggarwala9b93f32012-02-23 14:51:58 -080040import com.android.mail.providers.Account;
Mindy Pereira68f2e222012-03-07 10:36:54 -080041import com.android.mail.providers.UIProvider.AccountCapabilities;
Mindy Pereiraf9323cd2012-02-29 13:47:09 -080042import com.android.mail.providers.Folder;
Vikram Aggarwala9b93f32012-02-23 14:51:58 -080043
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080044/**
Mindy Pereira68f2e222012-03-07 10:36:54 -080045 * View to manage the various states of the Mail Action Bar
46 *
47 * TODO(viki): Include ConversationSubjectDisplayer here as well.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080048 */
Mindy Pereira68f2e222012-03-07 10:36:54 -080049public final class ActionBarView extends LinearLayout implements OnNavigationListener,
50 ViewMode.ModeChangeListener, OnQueryTextListener {
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080051 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -080052 * This interface is used to send notifications back to the calling
53 * activity. MenuHandler takes care of updating the provider, so this
54 * interface should be used for notification purposes only (such as updating
55 * the UI).
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -080056 */
Mindy Pereira68f2e222012-03-07 10:36:54 -080057 // TODO(viki): This callback is currently unused and may be entirely unnecessary in the new
58 // code, where the Actionbar is switched into navigation mode, relying on the framework for most
59 // heavy lifting. Also, we can switch ViewMode to the appropriate mode and rely on all UI
60 // components updating through ViewMode change listeners.
61 public interface Callback {
62 /**
63 * Returns the current account.
64 */
65 Account getCurrentAccount();
66
67 /**
68 * Called when the TwoPaneActionBar wants to get the current conversation list context.
69 */
70 ConversationListContext getCurrentListContext();
71
72 /**
73 * Invoked when the user is already viewing search results
74 * and enters a new query.
75 * @param string Query
76 */
77 void reloadSearch(String string);
78
79 void showFolderList();
80
81 void startActionBarStatusCursorLoader(String account);
82
83 void stopActionBarStatusCursorLoader(String account);
84 }
85
86 private String[] mAccountNames;
87 private ActionBar mActionBar;
88 private RestrictedActivity mActivity;
89 private ActivityController mCallback;
90 private View mFolderView;
91 /**
92 * The current mode of the ActionBar. This references constants in {@link ViewMode}
93 */
94 private int mMode = ViewMode.UNKNOWN;
95
96 private MenuItem mSearch;
97 AccountSpinnerAdapter mSpinner;
98 /**
99 * The account currently being shown
100 */
101 private Account mAccount;
102
103 // TODO(viki): This is a SnippetTextView in the Gmail source code. Resolve.
104 private TextView mSubjectView;
105 private SearchView mSearchWidget;
106 private MenuItem mHelpItem;
107
108 public ActionBarView(Context context) {
109 this(context, null);
110 }
111
112 public ActionBarView(Context context, AttributeSet attrs) {
113 this(context, attrs, 0);
114 }
115
116 public ActionBarView(Context context, AttributeSet attrs, int defStyle) {
117 super(context, attrs, defStyle);
118 }
119
120 public boolean onCreateOptionsMenu(Menu menu) {
121 // If the mode is valid, then set the initial menu
122 if (mMode == ViewMode.UNKNOWN) {
123 return false;
124 }
125 MenuItem search = menu.findItem(R.id.search);
126 if (search != null) {
127 mSearchWidget = (SearchView) search.getActionView();
128 SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
129 .getSystemService(Context.SEARCH_SERVICE);
130 if (searchManager != null) {
131 SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
132 mSearchWidget.setSearchableInfo(info);
133 mSearchWidget.setOnQueryTextListener(this);
134 }
135 }
136 mHelpItem = menu.findItem(R.id.help_info_menu_item);
137 return true;
138 }
139
140 public int getOptionsMenuId() {
141 // Relies on the ordering of the view modes, since they are integer constants.
142 final int[] modeMenu = {
143 // 0: UNKNOWN
144 R.menu.conversation_list_menu,
145 // 1: CONVERSATION
146 R.menu.conversation_actions,
147 // 2: CONVERSATION_LIST
148 R.menu.conversation_list_menu,
149 // 3: FOLDER_LIST
150 R.menu.folder_list_menu,
151 // 4: SEARCH_RESULTS_LIST
152 R.menu.conversation_list_search_results_actions,
153 // 5: SEARCH_RESULTS_CONVERSATION
154 R.menu.conversation_actions
155 };
156 return modeMenu[mMode];
157 }
158
159 public void handleRestore(Bundle savedInstanceState) {
160 }
161
162 public void handleSaveInstanceState(Bundle outState) {
163 }
164
165 public void initialize(RestrictedActivity activity, ActivityController callback,
166 ViewMode viewMode, ActionBar actionBar) {
167 mActionBar = actionBar;
168 mCallback = callback;
169 mActivity = activity;
170
171 mSpinner = new AccountSpinnerAdapter(getContext());
172 // Set the mode to Navigation mode and listen on navigation changes.
173 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
174 mActionBar.setListNavigationCallbacks(mSpinner, this);
175 }
176
177 public void setAccounts(Account[] accounts) {
178 Account currentAccount = mCallback.getCurrentAccount();
179 mSpinner.setAccounts(accounts);
180 mSpinner.setCurrentAccount(currentAccount);
181 int position = -1;
182 for (position = 0; position < accounts.length; position++) {
183 if (accounts[position].equals(currentAccount)) {
184 break;
185 }
186 }
187 if (position >= accounts.length) {
188 position = 0;
189 }
190 mActionBar.setSelectedNavigationItem(position);
191 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800192
193 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800194 * Called by the owner of the ActionBar to set the
195 * folder that is currently being displayed.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800196 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800197 public void setFolder(Folder folder) {
198 mSpinner.setCurrentFolder(folder);
199 mSpinner.notifyDataSetChanged();
200 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800201
202 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800203 * Called by the owner of the ActionBar to set the
204 * account that is currently being displayed.
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800205 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800206 public void setAccount(Account account) {
207 mSpinner.setCurrentAccount(account);
208 mSpinner.notifyDataSetChanged();
209 }
210
211 @Override
212 public boolean onNavigationItemSelected(int position, long id) {
213 final int type = mSpinner.getItemViewType(position);
214 switch (type) {
215 case AccountSpinnerAdapter.TYPE_ACCOUNT:
216 // Get the capabilities associated with this account.
217 final Object item = mSpinner.getItem(position);
218 assert (item instanceof Account);
219 mCallback.onAccountChanged((Account) mSpinner.getItem(position));
220 break;
221 case AccountSpinnerAdapter.TYPE_FOLDER:
222 final Object folder = mSpinner.getItem(position);
223 assert (folder instanceof Folder);
224 mCallback.onFolderChanged((Folder) folder);
225 break;
226 }
227 return false;
228 }
229
230 public void onPause() {
231 }
232
233 public void onResume() {
234 }
235
236 public void onStatusResult(String account, int status) {
237 // Update the inbox folder if required
238 mCallback.stopActionBarStatusCursorLoader(account);
239 }
240
241 public void onViewModeChanged(int newMode) {
242 mMode = newMode;
243 // Always update the options menu and redraw. This will read the new mode and redraw
244 // the options menu.
245 mActivity.invalidateOptionsMenu();
246 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800247
248 /**
Mindy Pereira68f2e222012-03-07 10:36:54 -0800249 * If shouldSetView is true, then the view is made visible, otherwise its visiblity is View.GONE
250 * @param view the view whose visibility is modified
251 * @param shouldSetView if true, the view is made visible, GONE otherwise
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800252 */
Mindy Pereira68f2e222012-03-07 10:36:54 -0800253 private void setVisibility(int resourceId, boolean shouldSetView) {
254 final View view = findViewById(resourceId);
255 assert (view != null);
256 final int visibility = shouldSetView ? View.VISIBLE : View.GONE;
257 view.setVisibility(visibility);
258 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800259
Mindy Pereira68f2e222012-03-07 10:36:54 -0800260 public boolean prepareOptionsMenu(Menu menu) {
261 // We start out with every option enabled. Based on the current view, we disable actions
262 // that are possible.
263 if (mSubjectView != null){
264 mSubjectView.setVisibility(GONE);
265 }
266 if (mFolderView != null){
267 mFolderView.setVisibility(GONE);
268 }
269 if (mAccount == null) {
270 return false;
271 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800272
Mindy Pereira68f2e222012-03-07 10:36:54 -0800273 if (mHelpItem != null) {
274 mHelpItem.setVisible(mAccount != null
275 && mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
276 }
277 switch (mMode){
278 case ViewMode.UNKNOWN:
279 if (mSearch != null){
280 mSearch.collapseActionView();
281 }
282 break;
283 case ViewMode.CONVERSATION_LIST:
284 // Show compose, search, labels, and sync based on the account
285 // The only option that needs to be disabled is search
286 setVisibility(R.id.search, mAccount.supportsCapability(
287 AccountCapabilities.FOLDER_SERVER_SEARCH));
288 break;
289 case ViewMode.CONVERSATION:
290 setVisibility(R.id.y_button, mAccount.supportsCapability(
291 AccountCapabilities.ARCHIVE));
292 setVisibility(R.id.report_spam, mAccount.supportsCapability(
293 AccountCapabilities.REPORT_SPAM));
294 setVisibility(R.id.mute, mAccount.supportsCapability(AccountCapabilities.MUTE));
295 break;
296 case ViewMode.SEARCH_RESULTS_LIST:
297 mActionBar.setDisplayHomeAsUpEnabled(true);
298 if (mSearch != null) {
299 mSearch.expandActionView();
300 }
301 break;
302 case ViewMode.SEARCH_RESULTS_CONVERSATION:
303 mActionBar.setDisplayHomeAsUpEnabled(true);
304 break;
305 case ViewMode.FOLDER_LIST:
306 break;
307 }
308 return false;
309 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800310
Mindy Pereira68f2e222012-03-07 10:36:54 -0800311 public void removeBackButton() {
312 if (mActionBar == null) {
313 return;
314 }
315 mActionBar.setDisplayOptions(
316 ActionBar.DISPLAY_SHOW_HOME,
317 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
318 mActivity.getActionBar().setHomeButtonEnabled(false);
319 }
Mindy Pereirabc57bf12012-02-29 14:39:09 -0800320
Mindy Pereira68f2e222012-03-07 10:36:54 -0800321 public void setBackButton() {
322 if (mActionBar == null){
323 return;
324 }
325 mActionBar.setDisplayOptions(
326 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
327 ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
328 mActivity.getActionBar().setHomeButtonEnabled(true);
329 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800330
Mindy Pereira68f2e222012-03-07 10:36:54 -0800331 @Override
332 public boolean onQueryTextSubmit(String query) {
333 mActivity.onSearchRequested(query);
334 return true;
335 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800336
Mindy Pereira68f2e222012-03-07 10:36:54 -0800337 @Override
338 public boolean onQueryTextChange(String newText) {
339 // TODO Auto-generated method stub
340 return false;
341 }
Vikram Aggarwal5e5ac742011-12-19 08:14:16 -0800342}