blob: 070bd53b8f79585668f3d17df69e71a948075587 [file] [log] [blame]
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -08001/*
2 * Copyright (C) 2012 Google Inc.
3 * Licensed to The Android Open Source Project.
4 *
5 * 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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * 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 */
17
18package com.android.mail.ui;
19
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080020import android.app.Activity;
21import android.app.ListFragment;
22import android.content.res.Resources;
Mindy Pereira6d8e7fe2012-07-26 16:02:49 -070023import android.database.DataSetObserver;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080024import android.os.Bundle;
25import android.os.Handler;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080026import android.view.LayoutInflater;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080027import android.view.View;
28import android.view.ViewGroup;
29import android.view.ViewGroup.MarginLayoutParams;
30import android.widget.AdapterView;
31import android.widget.AdapterView.OnItemLongClickListener;
32import android.widget.ListView;
33import android.widget.TextView;
34
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080035import com.android.mail.ConversationListContext;
Marc Blankf3626952012-02-28 17:06:05 -080036import com.android.mail.R;
mindypc03b05a2012-09-28 14:23:48 -070037import com.android.mail.browse.ToggleableItem;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080038import com.android.mail.browse.ConversationCursor;
Vikram Aggarwald247dc92012-02-10 15:49:01 -080039import com.android.mail.browse.ConversationItemView;
Mindy Pereira12fe37a2012-08-15 10:02:57 -070040import com.android.mail.browse.ConversationItemViewModel;
Mindy Pereira6681f6b2012-03-09 13:55:54 -080041import com.android.mail.browse.ConversationListFooterView;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080042import com.android.mail.providers.Account;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -070043import com.android.mail.providers.AccountObserver;
Vikram Aggarwald247dc92012-02-10 15:49:01 -080044import com.android.mail.providers.Conversation;
Mindy Pereira4f166de2012-02-14 13:40:58 -080045import com.android.mail.providers.Folder;
Vikram Aggarwal7d816002012-04-17 17:06:41 -070046import com.android.mail.providers.Settings;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080047import com.android.mail.providers.UIProvider;
Mindy Pereira4e812f42012-07-30 16:52:49 -070048import com.android.mail.providers.UIProvider.AccountCapabilities;
49import com.android.mail.providers.UIProvider.FolderCapabilities;
mindyp77c3e1b2012-09-11 14:05:02 -070050import com.android.mail.providers.UIProvider.FolderType;
Mindy Pereirae58222b2012-07-25 14:33:18 -070051import com.android.mail.providers.UIProvider.Swipe;
mindyp9365a822012-09-12 09:09:09 -070052import com.android.mail.ui.SwipeableListView.ListItemSwipedListener;
53import com.android.mail.ui.SwipeableListView.ListItemsRemovedListener;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080054import com.android.mail.ui.ViewMode.ModeChangeListener;
Paul Westbrookb334c902012-06-25 11:42:46 -070055import com.android.mail.utils.LogTag;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080056import com.android.mail.utils.LogUtils;
Vikram Aggarwalfa131a22012-02-02 13:56:22 -080057import com.android.mail.utils.Utils;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080058
Mindy Pereiraf6a6b502012-03-15 15:24:26 -070059import java.util.Collection;
Mindy Pereirafe06bea2012-02-16 08:15:14 -080060
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080061/**
62 * The conversation list UI component.
63 */
Vikram Aggarwald247dc92012-02-10 15:49:01 -080064public final class ConversationListFragment extends ListFragment implements
mindyp9365a822012-09-12 09:09:09 -070065 OnItemLongClickListener, ModeChangeListener, ListItemSwipedListener {
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -070066 /** Key used to pass data to {@link ConversationListFragment}. */
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080067 private static final String CONVERSATION_LIST_KEY = "conversation-list";
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -070068 /** Key used to keep track of the scroll state of the list. */
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080069 private static final String LIST_STATE_KEY = "list-state";
Vikram Aggarwal649b9ea2012-08-27 12:15:20 -070070
Paul Westbrookb334c902012-06-25 11:42:46 -070071 private static final String LOG_TAG = LogTag.getLogTag();
Vikram Aggarwala91d00b2013-01-18 12:00:37 -080072 /** Key used to save the ListView choice mode, since ListView doesn't save it automatically! */
73 private static final String CHOICE_MODE_KEY = "choice-mode-key";
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080074
Vikram Aggarwald7a12cd2012-02-03 09:36:20 -080075 // True if we are on a tablet device
76 private static boolean mTabletDevice;
77
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080078 /**
mindyp9365a822012-09-12 09:09:09 -070079 * Frequency of update of timestamps. Initialized in
80 * {@link #onCreate(Bundle)} and final afterwards.
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080081 */
82 private static int TIMESTAMP_UPDATE_INTERVAL = 0;
83
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080084 private ControllableActivity mActivity;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080085
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080086 // Control state.
87 private ConversationListCallbacks mCallbacks;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080088
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080089 private final Handler mHandler = new Handler();
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080090
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080091 // The internal view objects.
Mindy Pereiraf6a6b502012-03-15 15:24:26 -070092 private SwipeableListView mListView;
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -080093
94 private TextView mSearchResultCountTextView;
95 private TextView mSearchStatusTextView;
96
97 private View mSearchStatusView;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080098
Vikram Aggarwal80aeac52012-02-07 15:27:20 -080099 /**
100 * Current Account being viewed
101 */
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800102 private Account mAccount;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800103 /**
Mindy Pereira30fd47b2012-03-09 09:24:00 -0800104 * Current folder being viewed.
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800105 */
Mindy Pereira4f166de2012-02-14 13:40:58 -0800106 private Folder mFolder;
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800107
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800108 /**
109 * A simple method to update the timestamps of conversations periodically.
110 */
111 private Runnable mUpdateTimestampsRunnable = null;
112
113 private ConversationListContext mViewContext;
114
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800115 private AnimatedAdapter mListAdapter;
Vikram Aggarwal7d602882012-02-07 15:01:20 -0800116
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800117 private ConversationListFooterView mFooterView;
Mindy Pereira6cc95532012-08-15 16:04:56 -0700118 private View mEmptyView;
Andrew Sappersteinc2c9dc12012-07-02 18:17:32 -0700119 private ErrorListener mErrorListener;
Mindy Pereirae3c7b0b2012-07-26 16:28:34 -0700120 private DataSetObserver mFolderObserver;
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800121 private DataSetObserver mConversationCursorObserver;
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800122
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700123 private ConversationSelectionSet mSelectedSet;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700124 private final AccountObserver mAccountObserver = new AccountObserver() {
125 @Override
126 public void onChanged(Account newAccount) {
127 mAccount = newAccount;
128 setSwipeAction();
129 }
130 };
mindyp9365a822012-09-12 09:09:09 -0700131 private ConversationUpdater mUpdater;
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700132 /** Hash of the Conversation Cursor we last obtained from the controller. */
133 private int mConversationCursorHash;
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700134
Vikram Aggarwal6c511582012-02-27 10:59:47 -0800135 /**
mindyp9365a822012-09-12 09:09:09 -0700136 * Constructor needs to be public to handle orientation changes and activity
137 * lifecycle events.
Vikram Aggarwal6c511582012-02-27 10:59:47 -0800138 */
Paul Westbrookefc9f122012-02-21 11:14:49 -0800139 public ConversationListFragment() {
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800140 super();
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800141 }
142
Mindy Pereira6d8e7fe2012-07-26 16:02:49 -0700143 // update the pager title strip as the Folder's conversation count changes
144 private class FolderObserver extends DataSetObserver {
145 @Override
146 public void onChanged() {
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700147 if (mActivity == null) {
148 return;
149 }
150 final FolderController controller = mActivity.getFolderController();
151 if (controller == null) {
152 return;
153 }
154 onFolderUpdated(controller.getFolder());
Mindy Pereira6d8e7fe2012-07-26 16:02:49 -0700155 }
156 }
157
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800158 private class ConversationCursorObserver extends DataSetObserver {
Mindy Pereira70a70c92012-08-02 08:39:45 -0700159 @Override
160 public void onChanged() {
Mindy Pereira70a70c92012-08-02 08:39:45 -0700161 onConversationListStatusUpdated();
162 }
163 }
164
Vikram Aggarwal7d602882012-02-07 15:01:20 -0800165 /**
mindyp9365a822012-09-12 09:09:09 -0700166 * Creates a new instance of {@link ConversationListFragment}, initialized
167 * to display conversation list context.
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800168 */
169 public static ConversationListFragment newInstance(ConversationListContext viewContext) {
170 ConversationListFragment fragment = new ConversationListFragment();
171 Bundle args = new Bundle();
172 args.putBundle(CONVERSATION_LIST_KEY, viewContext.toBundle());
173 fragment.setArguments(args);
174 return fragment;
175 }
176
177 /**
mindyp9365a822012-09-12 09:09:09 -0700178 * Show the header if the current conversation list is showing search
179 * results.
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800180 */
Mindy Pereira967ede62012-03-22 09:29:09 -0700181 void configureSearchResultHeader() {
Mindy Pereira755fd6e2012-03-21 15:15:44 -0700182 if (mActivity == null) {
183 return;
184 }
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800185 // Only show the header if the context is for a search result
186 final Resources res = getResources();
Vikram Aggarwalae4ea992012-08-07 09:56:02 -0700187 final boolean showHeader = ConversationListContext.isSearchResult(mViewContext);
mindyp9365a822012-09-12 09:09:09 -0700188 // TODO(viki): This code contains intimate understanding of the view.
189 // Much of this logic
190 // needs to reside in a separate class that handles the text view in
191 // isolation. Then,
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800192 // that logic can be reused in other fragments.
193 if (showHeader) {
194 mSearchStatusTextView.setText(res.getString(R.string.search_results_searching_header));
195 // Initially reset the count
196 mSearchResultCountTextView.setText("");
197 }
198 mSearchStatusView.setVisibility(showHeader ? View.VISIBLE : View.GONE);
199 int marginTop = showHeader ? (int) res.getDimension(R.dimen.notification_view_height) : 0;
200 MarginLayoutParams layoutParams = (MarginLayoutParams) mListView.getLayoutParams();
201 layoutParams.topMargin = marginTop;
202 mListView.setLayoutParams(layoutParams);
203 }
204
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800205 /**
mindyp9365a822012-09-12 09:09:09 -0700206 * Show the header if the current conversation list is showing search
207 * results.
Mindy Pereira68f2e222012-03-07 10:36:54 -0800208 */
209 private void updateSearchResultHeader(int count) {
Mindy Pereira71a8f292012-07-26 16:30:48 -0700210 if (mActivity == null) {
211 return;
212 }
Mindy Pereira68f2e222012-03-07 10:36:54 -0800213 // Only show the header if the context is for a search result
214 final Resources res = getResources();
Vikram Aggarwalae4ea992012-08-07 09:56:02 -0700215 final boolean showHeader = ConversationListContext.isSearchResult(mViewContext);
Mindy Pereira68f2e222012-03-07 10:36:54 -0800216 if (showHeader) {
217 mSearchStatusTextView.setText(res.getString(R.string.search_results_header));
218 mSearchResultCountTextView
219 .setText(res.getString(R.string.search_results_loaded, count));
220 }
221 }
222
223 /**
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800224 * Initializes all internal state for a rendering.
225 */
226 private void initializeUiForFirstDisplay() {
mindyp9365a822012-09-12 09:09:09 -0700227 // TODO(mindyp): find some way to make the notification container more
228 // re-usable.
229 // TODO(viki): refactor according to comment in
230 // configureSearchResultHandler()
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800231 mSearchStatusView = mActivity.findViewById(R.id.search_status_view);
232 mSearchStatusTextView = (TextView) mActivity.findViewById(R.id.search_status_text_view);
mindyp9365a822012-09-12 09:09:09 -0700233 mSearchResultCountTextView = (TextView) mActivity
234 .findViewById(R.id.search_result_count_view);
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800235 }
236
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800237 @Override
238 public void onActivityCreated(Bundle savedInstanceState) {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800239 super.onActivityCreated(savedInstanceState);
mindyp9365a822012-09-12 09:09:09 -0700240 // Strictly speaking, we get back an android.app.Activity from
241 // getActivity. However, the
242 // only activity creating a ConversationListContext is a MailActivity
243 // which is of type
244 // ControllableActivity, so this cast should be safe. If this cast
245 // fails, some other
246 // activity is creating ConversationListFragments. This activity must be
247 // of type
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800248 // ControllableActivity.
249 final Activity activity = getActivity();
mindyp9365a822012-09-12 09:09:09 -0700250 if (!(activity instanceof ControllableActivity)) {
251 LogUtils.e(LOG_TAG, "ConversationListFragment expects only a ControllableActivity to"
252 + "create it. Cannot proceed.");
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800253 }
254 mActivity = (ControllableActivity) activity;
mindyp9365a822012-09-12 09:09:09 -0700255 // Since we now have a controllable activity, load the account from it,
256 // and register for
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700257 // future account changes.
258 mAccount = mAccountObserver.initialize(mActivity.getAccountController());
Vikram Aggarwal7d602882012-02-07 15:01:20 -0800259 mCallbacks = mActivity.getListHandler();
Andrew Sappersteinc2c9dc12012-07-02 18:17:32 -0700260 mErrorListener = mActivity.getErrorListener();
Mindy Pereira278fd222012-07-26 15:23:10 -0700261 // Start off with the current state of the folder being viewed.
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800262 mFooterView = (ConversationListFooterView) LayoutInflater.from(
263 mActivity.getActivityContext()).inflate(R.layout.conversation_list_footer_view,
264 null);
Paul Westbrook4969e0c2012-08-20 14:38:39 -0700265 mFooterView.setClickListener(mActivity);
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700266 final ConversationCursor conversationCursor = getConversationListCursor();
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800267 mListAdapter = new AnimatedAdapter(mActivity.getApplicationContext(),
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700268 conversationCursor, mActivity.getSelectedSet(), mActivity, mListView);
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800269 mListAdapter.addFooter(mFooterView);
Mindy Pereira6f4a6af2012-02-29 11:48:52 -0800270 mListView.setAdapter(mListAdapter);
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700271 mSelectedSet = mActivity.getSelectedSet();
272 mListView.setSelectionSet(mSelectedSet);
Mindy Pereiradc8963b2012-03-28 17:51:05 -0700273 mListAdapter.hideFooter();
Mindy Pereirae3c7b0b2012-07-26 16:28:34 -0700274 mFolderObserver = new FolderObserver();
Andy Huang7591d2f2012-07-26 16:48:06 -0700275 mActivity.getFolderController().registerFolderObserver(mFolderObserver);
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800276 mConversationCursorObserver = new ConversationCursorObserver();
mindyp9365a822012-09-12 09:09:09 -0700277 mUpdater = mActivity.getConversationUpdater();
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800278 mUpdater.registerConversationListObserver(mConversationCursorObserver);
Vikram Aggarwalbcb16b92013-01-28 18:05:03 -0800279 mTabletDevice = Utils.useTabletUI(mActivity.getApplicationContext().getResources());
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800280 initializeUiForFirstDisplay();
Mindy Pereiradc8963b2012-03-28 17:51:05 -0700281 configureSearchResultHeader();
mindyp9365a822012-09-12 09:09:09 -0700282 // The onViewModeChanged callback doesn't get called when the mode
283 // object is created, so
Vikram Aggarwalfa131a22012-02-02 13:56:22 -0800284 // force setting the mode manually this time around.
Mindy Pereiraf96ec322012-03-02 14:06:33 -0800285 onViewModeChanged(mActivity.getViewMode().getMode());
Mindy Pereirab5901be2012-08-09 17:21:53 -0700286 mActivity.getViewMode().addListener(this);
Paul Westbrook0e3fd9d2012-04-20 02:02:23 -0700287
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800288 if (mActivity.isFinishing()) {
289 // Activity is finishing, just bail.
290 return;
291 }
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700292 mConversationCursorHash = (conversationCursor == null) ? 0 : conversationCursor.hashCode();
293 // Belt and suspenders here; make sure we do any necessary sync of the
294 // ConversationCursor
295 if (conversationCursor != null && conversationCursor.isRefreshReady()) {
296 conversationCursor.sync();
297 }
298
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800299 // Show list and start loading list.
300 showList();
Mindy Pereira4765c5c2012-07-19 11:58:22 -0700301 ToastBarOperation pendingOp = mActivity.getPendingToastOperation();
302 if (pendingOp != null) {
303 // Clear the pending operation
304 mActivity.setPendingToastOperation(null);
305 mActivity.onUndoAvailable(pendingOp);
306 }
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800307 }
308
Mindy Pereira967ede62012-03-22 09:29:09 -0700309 public AnimatedAdapter getAnimatedAdapter() {
310 return mListAdapter;
311 }
312
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800313 @Override
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800314 public void onCreate(Bundle savedState) {
Vikram Aggarwald247dc92012-02-10 15:49:01 -0800315 super.onCreate(savedState);
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800316
317 // Initialize fragment constants from resources
Vikram Aggarwal6c511582012-02-27 10:59:47 -0800318 final Resources res = getResources();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800319 TIMESTAMP_UPDATE_INTERVAL = res.getInteger(R.integer.timestamp_update_interval);
mindyp9365a822012-09-12 09:09:09 -0700320 mUpdateTimestampsRunnable = new Runnable() {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800321 @Override
322 public void run() {
323 mListView.invalidateViews();
324 mHandler.postDelayed(mUpdateTimestampsRunnable, TIMESTAMP_UPDATE_INTERVAL);
325 }
326 };
327
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800328 // Get the context from the arguments
Vikram Aggarwal6c511582012-02-27 10:59:47 -0800329 final Bundle args = getArguments();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800330 mViewContext = ConversationListContext.forBundle(args.getBundle(CONVERSATION_LIST_KEY));
Mindy Pereira3982e232012-02-29 15:00:34 -0800331 mAccount = mViewContext.account;
Paul Westbrook80ecd892012-08-16 13:37:39 -0700332
Vikram Aggarwal9a49c9b2012-08-31 10:49:33 -0700333 setRetainInstance(false);
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800334 }
335
336 @Override
Vikram Aggarwal9a49c9b2012-08-31 10:49:33 -0700337 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800338 View rootView = inflater.inflate(R.layout.conversation_list, null);
Mindy Pereira6cc95532012-08-15 16:04:56 -0700339 mEmptyView = rootView.findViewById(R.id.empty_view);
Mindy Pereiraf6a6b502012-03-15 15:24:26 -0700340 mListView = (SwipeableListView) rootView.findViewById(android.R.id.list);
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800341 mListView.setHeaderDividersEnabled(false);
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800342 mListView.setOnItemLongClickListener(this);
Mindy Pereira4e812f42012-07-30 16:52:49 -0700343 mListView.enableSwipe(mAccount.supportsCapability(AccountCapabilities.UNDO));
mindyp9365a822012-09-12 09:09:09 -0700344 mListView.setSwipedListener(this);
Marc Blank2af0cf32012-03-01 19:24:13 -0800345
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800346 final int choiceMode;
347 if (savedState != null) {
348 // Restore the choice mode if it was set earlier, or SINGLE if creating a fresh view.
349 // Choice mode here represents the current conversation only. CAB mode does not rely on
350 // the platform: it is a local variable within conversation items.
351 choiceMode = savedState.getInt(CHOICE_MODE_KEY, ListView.CHOICE_MODE_SINGLE);
352 if (savedState.containsKey(LIST_STATE_KEY)) {
353 mListView.onRestoreInstanceState(savedState.getParcelable(LIST_STATE_KEY));
354 // TODO: find a better way to unset the selected item when restoring
355 mListView.clearChoices();
356 }
357 } else {
358 choiceMode = ListView.CHOICE_MODE_SINGLE;
Vikram Aggarwal9a49c9b2012-08-31 10:49:33 -0700359 }
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800360 setChoiceMode(choiceMode);
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800361 return rootView;
362 }
363
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800364 /**
365 * Sets the choice mode of the list view
366 * @param choiceMode ListView#
367 */
368 private final void setChoiceMode(int choiceMode) {
369 mListView.setChoiceMode(choiceMode);
370 }
371
372 /**
373 * Tell the list to select nothing.
374 */
375 public final void setChoiceNone() {
376 final int currentSelected = mListView.getCheckedItemPosition();
377 mListView.clearChoices();
378 // We use the activated state to show the blue highlight on tablet. Clearing the choices
379 // removes the checked state, but doesn't do anything to the activated state. We must
380 // manually clear that.
381 if (currentSelected != ListView.INVALID_POSITION) {
382 final View v = mListView.getChildAt(currentSelected);
383 if (v != null) {
384 v.setActivated(false);
385 }
386 }
387 setChoiceMode(ListView.CHOICE_MODE_NONE);
388 }
389
390 /**
391 * Tell the list to get out of selecting none.
392 */
393 public final void revertChoiceMode() {
394 setChoiceMode(ListView.CHOICE_MODE_SINGLE);
395 }
396
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800397 @Override
Andy Huang7517e3b2012-08-20 12:30:08 -0700398 public void onDestroy() {
Andy Huang7517e3b2012-08-20 12:30:08 -0700399 super.onDestroy();
400 }
401
402 @Override
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800403 public void onDestroyView() {
Andy Huang7517e3b2012-08-20 12:30:08 -0700404
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700405 // Clear the list's adapter
406 mListAdapter.destroy();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800407 mListView.setAdapter(null);
408
Vikram Aggarwald7a12cd2012-02-03 09:36:20 -0800409 mActivity.unsetViewModeListener(this);
Mindy Pereira71a8f292012-07-26 16:30:48 -0700410 if (mFolderObserver != null) {
Andy Huang7591d2f2012-07-26 16:48:06 -0700411 mActivity.getFolderController().unregisterFolderObserver(mFolderObserver);
Mindy Pereira71a8f292012-07-26 16:30:48 -0700412 mFolderObserver = null;
413 }
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800414 if (mConversationCursorObserver != null) {
415 mUpdater.unregisterConversationListObserver(mConversationCursorObserver);
416 mConversationCursorObserver = null;
Mindy Pereira70a70c92012-08-02 08:39:45 -0700417 }
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700418 mAccountObserver.unregisterAndDestroy();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800419 super.onDestroyView();
420 }
421
Vikram Aggarwal9730ea02012-08-02 12:46:19 -0700422 /**
mindyp9365a822012-09-12 09:09:09 -0700423 * There are three binary variables, which determine what we do with a
424 * message. checkbEnabled: Whether check boxes are enabled or not (forced
425 * true on tablet) cabModeOn: Whether CAB mode is currently on or not.
426 * pressType: long or short tap (There is a third possibility: phone or
427 * tablet, but they have <em>identical</em> behavior) The matrix of
428 * possibilities is:
429 * <p>
430 * Long tap: Always toggle selection of conversation. If CAB mode is not
431 * started, then start it.
Vikram Aggarwal9730ea02012-08-02 12:46:19 -0700432 * <pre>
433 * | Checkboxes | No Checkboxes
434 * ----------+------------+---------------
435 * CAB mode | Select | Select
436 * List mode | Select | Select
437 *
Vikram Aggarwal9730ea02012-08-02 12:46:19 -0700438 * </pre>
mindyp9365a822012-09-12 09:09:09 -0700439 *
Vikram Aggarwal9730ea02012-08-02 12:46:19 -0700440 * Reference: http://b/issue?id=6392199
441 * <p>
442 * {@inheritDoc}
443 */
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800444 @Override
445 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Mindy Pereira1e231a62012-03-23 12:42:15 -0700446 // Ignore anything that is not a conversation item. Could be a footer.
447 if (!(view instanceof ConversationItemView)) {
448 return true;
449 }
mindypbad1a932012-08-23 10:25:22 -0700450 ((ConversationItemView) view).toggleCheckMarkOrBeginDrag();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800451 return true;
452 }
453
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700454 /**
mindyp9365a822012-09-12 09:09:09 -0700455 * See the comment for
456 * {@link #onItemLongClick(AdapterView, View, int, long)}.
457 * <p>
458 * Short tap behavior:
459 *
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700460 * <pre>
461 * | Checkboxes | No Checkboxes
462 * ----------+------------+---------------
463 * CAB mode | Peek | Select
464 * List mode | Peek | Peek
465 * </pre>
mindyp9365a822012-09-12 09:09:09 -0700466 *
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700467 * Reference: http://b/issue?id=6392199
468 * <p>
469 * {@inheritDoc}
470 */
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800471 @Override
Vikram Aggarwal54452ae2012-03-13 15:29:00 -0700472 public void onListItemClick(ListView l, View view, int position, long id) {
Mindy Pereira1e231a62012-03-23 12:42:15 -0700473 // Ignore anything that is not a conversation item. Could be a footer.
mindyp8694fe92012-09-25 11:07:16 -0700474 // If we are using a keyboard, the highlighted item is the parent;
475 // otherwise, this is a direct call from the ConverationItemView
mindypc03b05a2012-09-28 14:23:48 -0700476 if (!(view instanceof ToggleableItem)) {
Mindy Pereira1e231a62012-03-23 12:42:15 -0700477 return;
478 }
Paul Westbrook7ed53772013-01-23 10:19:55 -0800479 if (mAccount.settings.hideCheckboxes && !mSelectedSet.isEmpty()) {
mindypc03b05a2012-09-28 14:23:48 -0700480 ToggleableItem v = (ToggleableItem) view;
481 v.toggleCheckMarkOrBeginDrag();
Vikram Aggarwal4f1cc0b2012-08-02 15:16:30 -0700482 } else {
483 viewConversation(position);
484 }
mindyp9365a822012-09-12 09:09:09 -0700485 // When a new list item is clicked, commit any existing leave behind
mindyp8694fe92012-09-25 11:07:16 -0700486 // items. Wait until we have opened the desired conversation to cause
487 // any position changes.
Vikram Aggarwalbcb16b92013-01-28 18:05:03 -0800488 commitDestructiveActions(Utils.useTabletUI(mActivity.getActivityContext().getResources()));
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800489 }
490
491 @Override
492 public void onPause() {
493 super.onPause();
494 }
495
496 @Override
497 public void onSaveInstanceState(Bundle outState) {
498 super.onSaveInstanceState(outState);
499 if (mListView != null) {
500 outState.putParcelable(LIST_STATE_KEY, mListView.onSaveInstanceState());
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800501 outState.putInt(CHOICE_MODE_KEY, mListView.getChoiceMode());
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800502 }
503 }
504
505 @Override
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800506 public void onStart() {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800507 super.onStart();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800508 mHandler.postDelayed(mUpdateTimestampsRunnable, TIMESTAMP_UPDATE_INTERVAL);
509 }
510
511 @Override
512 public void onStop() {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800513 super.onStop();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800514 mHandler.removeCallbacks(mUpdateTimestampsRunnable);
515 }
516
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800517 @Override
Vikram Aggarwalfa131a22012-02-02 13:56:22 -0800518 public void onViewModeChanged(int newMode) {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800519 // Change the divider based on view mode.
Vikram Aggarwalfa131a22012-02-02 13:56:22 -0800520 if (mTabletDevice) {
521 if (newMode == ViewMode.CONVERSATION) {
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800522 mListView.setBackgroundResource(R.drawable.panel_conversation_leftstroke);
Mindy Pereirade1c8592012-08-10 14:54:31 -0700523 } else if (newMode == ViewMode.CONVERSATION_LIST
524 || newMode == ViewMode.SEARCH_RESULTS_LIST) {
Mindy Pereirab5901be2012-08-09 17:21:53 -0700525 // There are no selected conversations when in conversation
526 // list mode.
Mindy Pereira62c5af82012-03-05 10:08:38 -0800527 mListView.clearChoices();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800528 mListView.setBackgroundDrawable(null);
529 }
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800530 } else {
531 mListView.setBackgroundDrawable(null);
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800532 }
Mindy Pereirab5901be2012-08-09 17:21:53 -0700533 if (mFooterView != null) {
534 mFooterView.onViewModeChanged(newMode);
535 }
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800536 }
Mindy Pereirab5901be2012-08-09 17:21:53 -0700537
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800538 /**
mindyp9365a822012-09-12 09:09:09 -0700539 * Handles a request to show a new conversation list, either from a search
540 * query or for viewing a folder. This will initiate a data load, and hence
541 * must be called on the UI thread.
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800542 */
543 private void showList() {
Vikram Aggarwal80aeac52012-02-07 15:27:20 -0800544 mListView.setEmptyView(null);
Andy Huang7591d2f2012-07-26 16:48:06 -0700545 onFolderUpdated(mActivity.getFolderController().getFolder());
mindypca8ca2d2012-09-11 17:38:34 -0700546 onConversationListStatusUpdated();
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800547 }
548
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800549 /**
550 * View the message at the given position.
551 * @param position
552 */
Mindy Pereirafbe40192012-03-20 10:40:45 -0700553 protected void viewConversation(int position) {
Vikram Aggarwalc7694222012-04-23 13:37:01 -0700554 LogUtils.d(LOG_TAG, "ConversationListFragment.viewConversation(%d)", position);
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800555 setSelected(position, true);
Vikram Aggarwal3d7ca9d2012-05-11 14:40:36 -0700556 final ConversationCursor cursor = getConversationListCursor();
557 if (cursor != null && cursor.moveToPosition(position)) {
558 final Conversation conv = new Conversation(cursor);
559 conv.position = position;
Andy Huang1ee96b22012-08-24 20:19:53 -0700560 mCallbacks.onConversationSelected(conv, false /* inLoaderCallbacks */);
Vikram Aggarwal3d7ca9d2012-05-11 14:40:36 -0700561 }
562 }
563
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800564 /**
565 * Sets the selected conversation to the position given here.
566 * @param position
567 * @param different if the currently selected conversation is different from the one provided
568 * here. This is a difference in conversations, not a difference in positions. For example, a
569 * conversation at position 2 can move to position 4 as a result of new mail.
570 */
mindype21f8862012-10-01 09:32:03 -0700571 public void setSelected(int position, boolean different) {
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800572 if (mListView.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
573 return;
574 }
mindype21f8862012-10-01 09:32:03 -0700575 if (different) {
576 mListView.smoothScrollToPosition(position);
577 }
578 mListView.setItemChecked(position, true);
579 }
580
Vikram Aggarwal3d7ca9d2012-05-11 14:40:36 -0700581 /**
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800582 * Returns the cursor associated with the conversation list.
583 * @return
Vikram Aggarwal3d7ca9d2012-05-11 14:40:36 -0700584 */
Mindy Pereira967ede62012-03-22 09:29:09 -0700585 private ConversationCursor getConversationListCursor() {
586 return mCallbacks != null ? mCallbacks.getConversationListCursor() : null;
Mindy Pereirafe06bea2012-02-16 08:15:14 -0800587 }
588
589 /**
mindyp9365a822012-09-12 09:09:09 -0700590 * Request a refresh of the list. No sync is carried out and none is
591 * promised.
Vikram Aggarwal54452ae2012-03-13 15:29:00 -0700592 */
593 public void requestListRefresh() {
594 mListAdapter.notifyDataSetChanged();
595 }
596
Vikram Aggarwal75daee52012-04-30 11:13:09 -0700597 /**
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700598 * Change the UI to delete the conversations provided and then call the
mindyp9365a822012-09-12 09:09:09 -0700599 * {@link DestructiveAction} provided here <b>after</b> the UI has been
600 * updated.
Vikram Aggarwal7f602f72012-04-30 16:04:06 -0700601 * @param conversations
Vikram Aggarwal75daee52012-04-30 11:13:09 -0700602 * @param action
603 */
Vikram Aggarwala8e43182012-09-13 12:55:10 -0700604 public void requestDelete(int actionId, final Collection<Conversation> conversations,
Vikram Aggarwal669947b2013-01-10 17:05:56 -0800605 final DestructiveAction action) {
Mindy Pereiraacf60392012-04-06 09:11:00 -0700606 for (Conversation conv : conversations) {
607 conv.localDeleteOnUpdate = true;
608 }
Vikram Aggarwala8e43182012-09-13 12:55:10 -0700609 final ListItemsRemovedListener listener = new ListItemsRemovedListener() {
mindyp9365a822012-09-12 09:09:09 -0700610 @Override
611 public void onListItemsRemoved() {
612 action.performAction();
613 }
Vikram Aggarwala8e43182012-09-13 12:55:10 -0700614 };
615 final SwipeableListView listView = (SwipeableListView) getListView();
616 if (listView.getSwipeAction() == actionId) {
mindyp4e77a7d2012-11-27 09:03:32 -0800617 listView.destroyItems(conversations, listener);
Vikram Aggarwala8e43182012-09-13 12:55:10 -0700618 return;
619 }
620 // Delete the local delete items (all for now) and when done,
621 // update...
622 mListAdapter.delete(conversations, listener);
Mindy Pereiraacf60392012-04-06 09:11:00 -0700623 }
Mindy Pereiraa3911aa2012-03-09 13:26:26 -0800624
Mindy Pereira11dd5ef2012-03-10 15:10:18 -0800625 public void onFolderUpdated(Folder folder) {
Mindy Pereiradc8963b2012-03-28 17:51:05 -0700626 mFolder = folder;
Mindy Pereira06642fa2012-07-12 16:23:27 -0700627 setSwipeAction();
Mindy Pereira82cea482012-03-27 16:45:00 -0700628 if (mFolder == null) {
629 return;
630 }
Mindy Pereira4584a0d2012-03-13 14:42:14 -0700631 mListAdapter.setFolder(mFolder);
Mindy Pereira70a70c92012-08-02 08:39:45 -0700632 mFooterView.setFolder(mFolder);
Vikram Aggarwal41b9e8f2012-09-25 10:15:04 -0700633 if (!mFolder.wasSyncSuccessful()) {
Mindy Pereira70a70c92012-08-02 08:39:45 -0700634 mErrorListener.onError(mFolder, false);
635 }
Paul Westbrookc01f5d92012-09-25 17:22:25 -0700636
637 // Notify of changes to the Folder.
638 onFolderStatusUpdated();
639
Mindy Pereira12fe37a2012-08-15 10:02:57 -0700640 // Blow away conversation items cache.
641 ConversationItemViewModel.onFolderUpdated(mFolder);
Mindy Pereira70a70c92012-08-02 08:39:45 -0700642 }
643
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700644 /**
645 * Updates the footer visibility and updates the conversation cursor
646 */
Mindy Pereira70a70c92012-08-02 08:39:45 -0700647 public void onConversationListStatusUpdated() {
Paul Westbrook9a70e912012-08-17 15:53:20 -0700648 final ConversationCursor cursor = getConversationListCursor();
649 final boolean showFooter = cursor != null && mFooterView.updateStatus(cursor);
Paul Westbrookc01f5d92012-09-25 17:22:25 -0700650 // Update the folder status, in case the cursor could affect it.
651 onFolderStatusUpdated();
652 mListAdapter.setFooterVisibility(showFooter);
653
654 // Also change the cursor here.
655 onCursorUpdated();
656 }
657
658 private void onFolderStatusUpdated() {
659 final ConversationCursor cursor = getConversationListCursor();
Paul Westbrook9a70e912012-08-17 15:53:20 -0700660 Bundle extras = cursor != null ? cursor.getExtras() : Bundle.EMPTY;
Mindy Pereira70a70c92012-08-02 08:39:45 -0700661 int error = extras.containsKey(UIProvider.CursorExtraKeys.EXTRA_ERROR) ?
662 extras.getInt(UIProvider.CursorExtraKeys.EXTRA_ERROR)
663 : UIProvider.LastSyncResult.SUCCESS;
Mindy Pereira6cc95532012-08-15 16:04:56 -0700664 int status = extras.getInt(UIProvider.CursorExtraKeys.EXTRA_STATUS);
Paul Westbrookc01f5d92012-09-25 17:22:25 -0700665 // We want to update the UI with this informaion if either we are loaded or complete, or
666 // we have a folder with a non-0 count.
667 final int folderCount = mFolder != null ? mFolder.totalCount : 0;
Mindy Pereira6cc95532012-08-15 16:04:56 -0700668 if (error == UIProvider.LastSyncResult.SUCCESS
669 && (status == UIProvider.CursorStatus.LOADED
Paul Westbrookc01f5d92012-09-25 17:22:25 -0700670 || status == UIProvider.CursorStatus.COMPLETE) || folderCount > 0) {
671 updateSearchResultHeader(folderCount);
672 if (folderCount == 0) {
Mindy Pereira6cc95532012-08-15 16:04:56 -0700673 mListView.setEmptyView(mEmptyView);
674 }
Mindy Pereira70a70c92012-08-02 08:39:45 -0700675 }
Mindy Pereiraa3911aa2012-03-09 13:26:26 -0800676 }
Mindy Pereiraf6a6b502012-03-15 15:24:26 -0700677
Mindy Pereira06642fa2012-07-12 16:23:27 -0700678 private void setSwipeAction() {
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700679 int swipeSetting = Settings.getSwipeSetting(mAccount.settings);
Mindy Pereirae58222b2012-07-25 14:33:18 -0700680 if (swipeSetting == Swipe.DISABLED
Mindy Pereirab8073372012-08-09 14:00:10 -0700681 || !mAccount.supportsCapability(AccountCapabilities.UNDO)
682 || (mFolder != null && mFolder.isTrash())) {
Mindy Pereirae58222b2012-07-25 14:33:18 -0700683 mListView.enableSwipe(false);
684 } else {
685 int action;
mindyp77c3e1b2012-09-11 14:05:02 -0700686 if (ConversationListContext.isSearchResult(mViewContext)
687 || (mFolder != null && mFolder.type == FolderType.SPAM)) {
Mindy Pereirae58222b2012-07-25 14:33:18 -0700688 action = R.id.delete;
Mindy Pereira4e812f42012-07-30 16:52:49 -0700689 } else if (mFolder == null) {
Mindy Pereira01f30502012-08-14 10:30:51 -0700690 action = R.id.remove_folder;
Mindy Pereira4e812f42012-07-30 16:52:49 -0700691 } else {
692 // We have enough information to respect user settings.
693 switch (swipeSetting) {
694 case Swipe.ARCHIVE:
695 if (mAccount.supportsCapability(AccountCapabilities.ARCHIVE)) {
696 if (mFolder.supportsCapability(FolderCapabilities.ARCHIVE)) {
697 action = R.id.archive;
698 break;
699 } else if (mFolder.supportsCapability
700 (FolderCapabilities.CAN_ACCEPT_MOVED_MESSAGES)) {
Mindy Pereira01f30502012-08-14 10:30:51 -0700701 action = R.id.remove_folder;
Mindy Pereira4e812f42012-07-30 16:52:49 -0700702 break;
703 }
704 }
705 case Swipe.DELETE:
706 default:
707 action = R.id.delete;
708 break;
709 }
Mindy Pereirae58222b2012-07-25 14:33:18 -0700710 }
711 mListView.setSwipeAction(action);
712 }
Mindy Pereira06642fa2012-07-12 16:23:27 -0700713 mListView.setCurrentFolder(mFolder);
714 }
715
Vikram Aggarwal17f373e2012-09-17 15:49:32 -0700716 /**
717 * Changes the conversation cursor in the list and sets selected position if none is set.
718 */
719 private void onCursorUpdated() {
720 if (mCallbacks == null || mListAdapter == null) {
721 return;
722 }
Vikram Aggarwal81a4f082012-09-28 09:19:04 -0700723 // Check against the previous cursor here and see if they are the same. If they are, then
724 // do a notifyDataSetChanged.
725 final ConversationCursor newCursor = mCallbacks.getConversationListCursor();
726 mListAdapter.swapCursor(newCursor);
727 // When the conversation cursor is *updated*, we get back the same instance. In that
728 // situation, CursorAdapter.swapCursor() silently returns, without forcing a
729 // notifyDataSetChanged(). So let's force a call to notifyDataSetChanged, since an updated
730 // cursor means that the dataset has changed.
731 final int newCursorHash = (newCursor == null) ? 0 : newCursor.hashCode();
732 if (mConversationCursorHash == newCursorHash && mConversationCursorHash != 0) {
733 mListAdapter.notifyDataSetChanged();
734 }
735 mConversationCursorHash = newCursorHash;
Vikram Aggarwal17f373e2012-09-17 15:49:32 -0700736 // If a current conversation is available, and none is selected in the list, then ask
737 // the list to select the current conversation.
738 final Conversation conv = mCallbacks.getCurrentConversation();
739 if (conv == null) {
740 return;
741 }
Vikram Aggarwala91d00b2013-01-18 12:00:37 -0800742 if (mListView.getChoiceMode() != ListView.CHOICE_MODE_NONE
743 && mListView.getCheckedItemPosition() == -1) {
744 setSelected(conv.position, true);
Mindy Pereira967ede62012-03-22 09:29:09 -0700745 }
Mindy Pereira21ab4902012-03-19 18:48:03 -0700746 }
Mindy Pereira1e2573b2012-04-17 14:34:36 -0700747
mindypc6adce32012-08-22 18:46:42 -0700748 public void commitDestructiveActions(boolean animate) {
Mindy Pereira8937bf12012-07-23 14:05:02 -0700749 if (mListView != null) {
mindypc6adce32012-08-22 18:46:42 -0700750 mListView.commitDestructiveActions(animate);
Vikram Aggarwal7d816002012-04-17 17:06:41 -0700751
752 }
753 }
754
mindyp9365a822012-09-12 09:09:09 -0700755 @Override
756 public void onListItemSwiped(Collection<Conversation> conversations) {
757 mUpdater.showNextConversation(conversations);
758 }
Vikram Aggarwalb9e1a352012-01-24 15:23:38 -0800759}