blob: da55a07f97cca6828f76595046f52c9ec3196737 [file] [log] [blame]
/*
* Copyright (C) 2012 Google Inc.
* Licensed to 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.mail.ui;
import android.app.ActionBar;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.app.ActionBar.OnNavigationListener;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.SearchView;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.SearchView.OnSuggestionListener;
import android.widget.TextView;
import android.widget.Toast;
import com.android.mail.R;
import com.android.mail.AccountSpinnerAdapter;
import com.android.mail.ConversationListContext;
import com.android.mail.providers.Account;
import com.android.mail.providers.UIProvider.AccountCapabilities;
import com.android.mail.providers.UIProvider.FolderCapabilities;
import com.android.mail.providers.UIProvider.LastSyncResult;
import com.android.mail.providers.Folder;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.Utils;
/**
* View to manage the various states of the Mail Action Bar
*
* TODO(viki): Include ConversationSubjectDisplayer here as well.
*/
public final class ActionBarView extends LinearLayout implements OnNavigationListener,
ViewMode.ModeChangeListener, OnQueryTextListener, OnSuggestionListener {
private ActionBar mActionBar;
private RestrictedActivity mActivity;
private ActivityController mController;
private View mFolderView;
/**
* The current mode of the ActionBar. This references constants in {@link ViewMode}
*/
private int mMode = ViewMode.UNKNOWN;
private MenuItem mSearch;
AccountSpinnerAdapter mSpinner;
/**
* The account currently being shown
*/
private Account mAccount;
/**
* The folder currently being shown
*/
private Folder mFolder;
// TODO(viki): This is a SnippetTextView in the Gmail source code. Resolve.
private TextView mSubjectView;
private SearchView mSearchWidget;
private MenuItem mHelpItem;
private MenuItem mSendFeedbackItem;
private MenuItem mRefreshItem;
private MenuItem mFolderSettingsItem;
private View mRefreshActionView;
private boolean mRefreshInProgress;
public static final String LOG_TAG = new LogUtils().getLogTag();
private final Handler mHandler = new Handler();
private final Runnable mInvalidateMenu = new Runnable() {
@Override
public void run() {
mActivity.invalidateOptionsMenu();
}
};
public ActionBarView(Context context) {
this(context, null);
}
public ActionBarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ActionBarView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Collapses the search action view.
*/
public void collapseSearch() {
if (mSearch != null) {
mSearch.collapseActionView();
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// If the mode is valid, then set the initial menu
if (mMode == ViewMode.UNKNOWN) {
return false;
}
mSearch = menu.findItem(R.id.search);
if (mSearch != null) {
mSearchWidget = (SearchView) mSearch.getActionView();
SearchManager searchManager = (SearchManager) mActivity.getActivityContext()
.getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null && mSearchWidget != null) {
SearchableInfo info = searchManager.getSearchableInfo(mActivity.getComponentName());
mSearchWidget.setSearchableInfo(info);
mSearchWidget.setOnQueryTextListener(this);
mSearchWidget.setOnSuggestionListener(this);
}
}
mHelpItem = menu.findItem(R.id.help_info_menu_item);
mSendFeedbackItem = menu.findItem(R.id.feedback_menu_item);
mRefreshItem = menu.findItem(R.id.refresh);
mFolderSettingsItem = menu.findItem(R.id.folder_options);
return true;
}
public int getOptionsMenuId() {
// Relies on the ordering of the view modes, since they are integer constants.
final int[] modeMenu = {
// 0: UNKNOWN
R.menu.conversation_list_menu,
// 1: CONVERSATION
R.menu.conversation_actions,
// 2: CONVERSATION_LIST
R.menu.conversation_list_menu,
// 3: FOLDER_LIST
R.menu.folder_list_menu,
// 4: SEARCH_RESULTS_LIST
R.menu.conversation_list_search_results_actions,
// 5: SEARCH_RESULTS_CONVERSATION
R.menu.conversation_search_results_actions
};
return modeMenu[mMode];
}
public void handleRestore(Bundle savedInstanceState) {
}
public void handleSaveInstanceState(Bundle outState) {
}
public void initialize(RestrictedActivity activity, ActivityController callback,
ViewMode viewMode, ActionBar actionBar, RecentFolderList recentFolders) {
mActionBar = actionBar;
mController = callback;
mActivity = activity;
mSpinner = new AccountSpinnerAdapter(getContext(), recentFolders);
// Set the mode to Navigation mode and listen on navigation changes.
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
mActionBar.setListNavigationCallbacks(mSpinner, this);
}
public void setAccounts(Account[] accounts) {
Account currentAccount = mController.getCurrentAccount();
mSpinner.setAccounts(accounts);
int position;
for (position = 0; position < accounts.length; position++) {
if (accounts[position].equals(currentAccount)) {
break;
}
}
if (position >= accounts.length) {
position = 0;
LogUtils.w(LOG_TAG, "IN actionbarview setAccounts, account not found, using first.");
}
setSelectedPosition(position);
}
/**
* Sets the selected navigation position in the spinner to the position given here.
* @param position
*/
private void setSelectedPosition(int position) {
// Only change the position if we are in the correct mode.
if (mActionBar.getNavigationMode() != ActionBar.NAVIGATION_MODE_LIST)
return;
mActionBar.setSelectedNavigationItem(position);
}
/**
* Called by the owner of the ActionBar to set the
* folder that is currently being displayed.
*/
public void setFolder(Folder folder) {
// Change the currently selected item to an element which is a spacer: valid but not useful
// This allows us to receive a tap on the account name when the user taps on it, and we can
// take the user to the default inbox.
setSelectedPosition(mSpinner.getSpacerPosition());
mSpinner.setCurrentFolder(folder);
mSpinner.notifyDataSetChanged();
mFolder = folder;
}
/**
* Called by the owner of the ActionBar to set the
* account that is currently being displayed.
*/
public void setAccount(Account account) {
mAccount = account;
mSpinner.setCurrentAccount(account);
mSpinner.notifyDataSetChanged();
}
@Override
public boolean onNavigationItemSelected(int position, long id) {
final int type = mSpinner.getType(position);
switch (type) {
case AccountSpinnerAdapter.TYPE_ACCOUNT:
// Get the capabilities associated with this account.
final Object account = mSpinner.getItem(position);
assert (account instanceof Account);
mController.onAccountChanged((Account) account);
break;
case AccountSpinnerAdapter.TYPE_FOLDER:
final Object folder = mSpinner.getItem(position);
assert (folder instanceof Folder);
mController.onFolderChanged((Folder) folder);
break;
}
return false;
}
public void onPause() {
}
public void onResume() {
}
@Override
public void onViewModeChanged(int newMode) {
mMode = newMode;
// Always update the options menu and redraw. This will read the new mode and redraw
// the options menu.
mActivity.invalidateOptionsMenu();
}
public boolean onPrepareOptionsMenu(Menu menu) {
// We start out with every option enabled. Based on the current view, we disable actions
// that are possible.
if (mSubjectView != null){
mSubjectView.setVisibility(GONE);
}
if (mFolderView != null){
mFolderView.setVisibility(GONE);
}
if (mRefreshInProgress) {
if (mRefreshItem != null) {
if (mRefreshActionView == null) {
mRefreshItem.setActionView(R.layout.action_bar_indeterminate_progress);
mRefreshActionView = mRefreshItem.getActionView();
} else {
mRefreshItem.setActionView(mRefreshActionView);
}
}
} else {
if (mRefreshItem != null) {
mRefreshItem.setActionView(null);
}
}
if (mHelpItem != null) {
mHelpItem.setVisible(mAccount != null
&& mAccount.supportsCapability(AccountCapabilities.HELP_CONTENT));
}
if (mSendFeedbackItem != null) {
mSendFeedbackItem.setVisible(mAccount != null
&& mAccount.supportsCapability(AccountCapabilities.SEND_FEEDBACK));
}
if (mFolderSettingsItem != null) {
mFolderSettingsItem.setVisible(mFolder != null
&& mFolder.supportsCapability(FolderCapabilities.SUPPORTS_SETTINGS));
}
switch (mMode) {
case ViewMode.UNKNOWN:
if (mSearch != null) {
mSearch.collapseActionView();
}
break;
case ViewMode.CONVERSATION_LIST:
// Show compose, search, folders, and sync based on the account
// The only option that needs to be disabled is search
showNavList();
Utils.setMenuItemVisibility(menu, R.id.search,
mAccount.supportsCapability(AccountCapabilities.FOLDER_SERVER_SEARCH));
break;
case ViewMode.CONVERSATION:
mActionBar.setDisplayHomeAsUpEnabled(true);
showNavList();
break;
case ViewMode.SEARCH_RESULTS_LIST:
showNavList();
setPopulatedSearchView();
break;
case ViewMode.SEARCH_RESULTS_CONVERSATION:
mActionBar.setDisplayHomeAsUpEnabled(true);
showNavList();
if (Utils.useTabletUI(mActivity.getActivityContext())) {
setPopulatedSearchView();
}
break;
case ViewMode.FOLDER_LIST:
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE,
ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
mActionBar.setTitle(R.string.folder_list_title);
break;
}
return false;
}
private void showNavList() {
mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_CUSTOM);
}
private void setPopulatedSearchView() {
if (mSearch != null) {
mSearch.expandActionView();
ConversationListContext context = mController.getCurrentListContext();
if (context != null) {
mSearchWidget.setQuery(context.searchQuery, false);
}
}
}
public void removeBackButton() {
if (mActionBar == null) {
return;
}
mActionBar.setDisplayOptions(
ActionBar.DISPLAY_SHOW_HOME,
ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
mActivity.getActionBar().setHomeButtonEnabled(false);
}
public void setBackButton() {
if (mActionBar == null){
return;
}
mActionBar.setDisplayOptions(
ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
mActivity.getActionBar().setHomeButtonEnabled(true);
}
@Override
public boolean onQueryTextSubmit(String query) {
if (mSearch != null) {
mSearch.collapseActionView();
mSearchWidget.setQuery("", false);
}
mActivity.onSearchRequested(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
// TODO Auto-generated method stub
return false;
}
public boolean setRefreshInProgress(boolean inProgress) {
if (inProgress != mRefreshInProgress) {
mRefreshInProgress = inProgress;
if (mSearch == null || !mSearch.isActionViewExpanded()) {
mHandler.post(mInvalidateMenu);
}
return true;
}
return false;
}
public void onRefreshStarted() {
setRefreshInProgress(true);
}
public void onRefreshStopped(int status) {
if (setRefreshInProgress(false)) {
switch (status) {
case LastSyncResult.SUCCESS:
break;
default:
Context context = mActivity.getActivityContext();
Toast.makeText(context, Utils.getSyncStatusText(context, status),
Toast.LENGTH_LONG).show();
break;
}
}
}
/**
* Get the query text the user entered in the search widget, or empty string
* if there is none.
*/
public String getQuery() {
return mSearchWidget != null ? mSearchWidget.getQuery().toString() : "";
}
// Next two methods are called when search suggestions are clicked.
@Override
public boolean onSuggestionSelect(int position) {
return onSuggestionClick(position);
}
@Override
public boolean onSuggestionClick(int position) {
final Cursor c = mSearchWidget.getSuggestionsAdapter().getCursor();
final boolean haveValidQuery = (c != null) && c.moveToPosition(position);
if (!haveValidQuery) {
LogUtils.d(LOG_TAG, "onSuggestionClick: Couldn't get a search query");
// We haven't handled this query, but the default behavior will leave EXTRA_ACCOUNT
// un-populated, leading to a crash. So claim that we have handled the event.
return true;
}
final String query = c.getString(c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY));
mController.onSearchRequested(query);
return true;
}
/**
* Notify that the folder has changed.
*/
public void onFolderUpdated(Folder folder) {
mSpinner.onFolderUpdated(folder);
}
}