blob: 97da9b7d6c569720d92517da65a30b2b85e0855f [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.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.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.LastSyncResult;
import com.android.mail.providers.Folder;
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 {
/**
* This interface is used to send notifications back to the calling
* activity. MenuHandler takes care of updating the provider, so this
* interface should be used for notification purposes only (such as updating
* the UI).
*/
// TODO(viki): This callback is currently unused and may be entirely unnecessary in the new
// code, where the Actionbar is switched into navigation mode, relying on the framework for most
// heavy lifting. Also, we can switch ViewMode to the appropriate mode and rely on all UI
// components updating through ViewMode change listeners.
public interface Callback {
/**
* Returns the current account.
*/
Account getCurrentAccount();
/**
* Called when the TwoPaneActionBar wants to get the current conversation list context.
*/
ConversationListContext getCurrentListContext();
/**
* Invoked when the user is already viewing search results
* and enters a new query.
* @param string Query
*/
void reloadSearch(String string);
void showFolderList();
void startActionBarStatusCursorLoader(String account);
void stopActionBarStatusCursorLoader(String account);
}
private ActionBar mActionBar;
private RestrictedActivity mActivity;
private ActivityController mCallback;
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;
// TODO(viki): This is a SnippetTextView in the Gmail source code. Resolve.
private TextView mSubjectView;
private SearchView mSearchWidget;
private MenuItem mHelpItem;
private MenuItem mRefreshItem;
private View mRefreshActionView;
private boolean mRefreshInProgress;
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);
}
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);
}
}
mHelpItem = menu.findItem(R.id.help_info_menu_item);
mRefreshItem = menu.findItem(R.id.refresh);
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_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) {
mActionBar = actionBar;
mCallback = callback;
mActivity = activity;
mSpinner = new AccountSpinnerAdapter(getContext());
// 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 = mCallback.getCurrentAccount();
mSpinner.setAccounts(accounts);
mSpinner.setCurrentAccount(currentAccount);
int position = -1;
for (position = 0; position < accounts.length; position++) {
if (accounts[position].equals(currentAccount)) {
break;
}
}
if (position >= accounts.length) {
position = 0;
}
mActionBar.setSelectedNavigationItem(position);
}
/**
* Called by the owner of the ActionBar to set the
* folder that is currently being displayed.
*/
public void setFolder(Folder folder) {
mSpinner.setCurrentFolder(folder);
mSpinner.notifyDataSetChanged();
}
/**
* 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.getItemViewType(position);
switch (type) {
case AccountSpinnerAdapter.TYPE_ACCOUNT:
// Get the capabilities associated with this account.
final Object item = mSpinner.getItem(position);
assert (item instanceof Account);
mCallback.onAccountChanged((Account) mSpinner.getItem(position));
break;
case AccountSpinnerAdapter.TYPE_FOLDER:
final Object folder = mSpinner.getItem(position);
assert (folder instanceof Folder);
mCallback.onFolderChanged((Folder) folder);
break;
}
return false;
}
public void onPause() {
}
public void onResume() {
}
public void onStatusResult(String account, int status) {
// Update the inbox folder if required
mCallback.stopActionBarStatusCursorLoader(account);
}
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();
}
private void setVisibility(Menu menu, int itemId, boolean shouldShow) {
final MenuItem item = menu.findItem(itemId);
assert (item != null);
item.setVisible(shouldShow);
}
public boolean prepareOptionsMenu(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));
}
switch (mMode) {
case ViewMode.UNKNOWN:
if (mSearch != null) {
mSearch.collapseActionView();
}
break;
case ViewMode.CONVERSATION_LIST:
// Show compose, search, labels, and sync based on the account
// The only option that needs to be disabled is search
setVisibility(menu, R.id.search,
mAccount.supportsCapability(AccountCapabilities.FOLDER_SERVER_SEARCH));
break;
case ViewMode.CONVERSATION:
setVisibility(menu, R.id.y_button,
mAccount.supportsCapability(AccountCapabilities.ARCHIVE));
setVisibility(menu, R.id.report_spam,
mAccount.supportsCapability(AccountCapabilities.REPORT_SPAM));
setVisibility(menu, R.id.mute,
mAccount.supportsCapability(AccountCapabilities.MUTE));
break;
case ViewMode.SEARCH_RESULTS_LIST:
mActionBar.setDisplayHomeAsUpEnabled(true);
if (mSearch != null) {
mSearch.expandActionView();
ConversationListContext context = mCallback.getCurrentListContext();
if (context != null) {
mSearchWidget.setQuery(context.searchQuery, false);
}
}
break;
case ViewMode.SEARCH_RESULTS_CONVERSATION:
mActionBar.setDisplayHomeAsUpEnabled(true);
break;
case ViewMode.FOLDER_LIST:
break;
}
return 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) {
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;
}
}
}
}