blob: d45678308bff7f62ece32039c2ae1d1ef4e16d4a [file] [log] [blame]
Mindy Pereira9879d4c2012-01-31 09:34:18 -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
20import android.animation.Animator;
Mindy Pereira067ef972012-08-08 14:04:06 -070021import android.animation.AnimatorSet;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080022import android.animation.ObjectAnimator;
23import android.content.Context;
24import android.database.Cursor;
Mindy Pereirad33674992012-06-25 16:26:30 -070025import android.os.Bundle;
mindyp6a6deb22012-11-26 11:40:15 -080026import android.os.Handler;
Mindy Pereira6c72a782012-04-07 14:29:15 -070027import android.view.LayoutInflater;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080028import android.view.View;
29import android.view.ViewGroup;
30import android.widget.SimpleCursorAdapter;
31
Mindy Pereira6c72a782012-04-07 14:29:15 -070032import com.android.mail.R;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080033import com.android.mail.browse.ConversationCursor;
34import com.android.mail.browse.ConversationItemView;
mindypb02ec692012-09-12 09:43:20 -070035import com.android.mail.browse.ConversationItemViewCoordinates;
Mindy Pereira1ef988f2012-07-24 12:06:03 -070036import com.android.mail.browse.SwipeableConversationItemView;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080037import com.android.mail.providers.Account;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -070038import com.android.mail.providers.AccountObserver;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080039import com.android.mail.providers.Conversation;
Mindy Pereira4584a0d2012-03-13 14:42:14 -070040import com.android.mail.providers.Folder;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080041import com.android.mail.providers.UIProvider;
mindyp9365a822012-09-12 09:09:09 -070042import com.android.mail.ui.SwipeableListView.ListItemsRemovedListener;
Paul Westbrookb334c902012-06-25 11:42:46 -070043import com.android.mail.utils.LogTag;
Vikram Aggarwal2ae81262012-03-27 15:43:57 -070044import com.android.mail.utils.LogUtils;
mindyp6a6deb22012-11-26 11:40:15 -080045import com.google.common.collect.Maps;
Marc Blank2596f002012-03-22 10:26:26 -070046
Mindy Pereira9879d4c2012-01-31 09:34:18 -080047import java.util.ArrayList;
Mindy Pereirafac92d72012-02-01 10:58:33 -080048import java.util.Collection;
Mindy Pereira067ef972012-08-08 14:04:06 -070049import java.util.HashMap;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080050import java.util.HashSet;
mindyp6a6deb22012-11-26 11:40:15 -080051import java.util.Iterator;
52import java.util.Map.Entry;
Mindy Pereira9879d4c2012-01-31 09:34:18 -080053
54public class AnimatedAdapter extends SimpleCursorAdapter implements
Vikram Aggarwal7c401b72012-08-13 16:43:47 -070055 android.animation.Animator.AnimatorListener {
mindypa44babd2013-01-17 09:59:25 -080056 private static int sDismissAllShortDelay = -1;
57 private static int sDismissAllLongDelay = -1;
Mindy Pereira79e6a082012-07-25 13:36:53 -070058 private static final String LAST_DELETING_ITEMS = "last_deleting_items";
mindyp6a6deb22012-11-26 11:40:15 -080059 private static final String LEAVE_BEHIND_ITEM_DATA = "leave_behind_item_data";
60 private static final String LEAVE_BEHIND_ITEM_ID = "leave_behind_item_id";
Vikram Aggarwalb54a4672012-04-11 11:32:44 -070061 private final static int TYPE_VIEW_CONVERSATION = 0;
mindyp9365a822012-09-12 09:09:09 -070062 private final static int TYPE_VIEW_FOOTER = 1;
mindypd0f95782012-10-09 13:51:40 -070063 private final static int TYPE_VIEW_DONT_RECYCLE = -1;
mindype85b8cd2012-08-23 11:32:26 -070064 private final HashSet<Long> mDeletingItems = new HashSet<Long>();
65 private final ArrayList<Long> mLastDeletingItems = new ArrayList<Long>();
66 private final HashSet<Long> mUndoingItems = new HashSet<Long>();
67 private final HashSet<Long> mSwipeDeletingItems = new HashSet<Long>();
68 private final HashSet<Long> mSwipeUndoingItems = new HashSet<Long>();
Mindy Pereira067ef972012-08-08 14:04:06 -070069 private final HashMap<Long, SwipeableConversationItemView> mAnimatingViews =
70 new HashMap<Long, SwipeableConversationItemView>();
Mindy Pereira1e946db2012-08-12 12:05:06 -070071 private final HashMap<Long, LeaveBehindItem> mFadeLeaveBehindItems =
Mindy Pereira8f397022012-08-12 11:19:15 -070072 new HashMap<Long, LeaveBehindItem>();
Vikram Aggarwal33519c02012-07-31 16:45:31 -070073 /** The current account */
Vikram Aggarwal7c401b72012-08-13 16:43:47 -070074 private Account mAccount;
Vikram Aggarwal33519c02012-07-31 16:45:31 -070075 private final Context mContext;
76 private final ConversationSelectionSet mBatchConversations;
mindyp6a6deb22012-11-26 11:40:15 -080077 private Runnable mCountDown;
78 private Handler mHandler;
79 protected long mLastLeaveBehind = -1;
80
Vikram Aggarwalc30fe412012-05-18 11:58:58 -070081 /**
82 * The next action to perform. Do not read or write this. All accesses should
83 * be in {@link #performAndSetNextAction(DestructiveAction)} which commits the
84 * previous action, if any.
85 */
mindyp9365a822012-09-12 09:09:09 -070086 private ListItemsRemovedListener mPendingDestruction;
Vikram Aggarwalc30fe412012-05-18 11:58:58 -070087 /**
88 * A destructive action that refreshes the list and performs no other action.
89 */
mindyp9365a822012-09-12 09:09:09 -070090 private final ListItemsRemovedListener mRefreshAction = new ListItemsRemovedListener() {
Vikram Aggarwalc30fe412012-05-18 11:58:58 -070091 @Override
mindyp9365a822012-09-12 09:09:09 -070092 public void onListItemsRemoved() {
Vikram Aggarwalc30fe412012-05-18 11:58:58 -070093 notifyDataSetChanged();
94 }
95 };
96
Paul Westbrookcff1aea2012-08-10 11:51:00 -070097 public interface Listener {
98 void onAnimationEnd(AnimatedAdapter adapter);
99 }
100
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800101 private View mFooter;
102 private boolean mShowFooter;
Mindy Pereira4584a0d2012-03-13 14:42:14 -0700103 private Folder mFolder;
Mindy Pereira07118a02012-04-02 16:35:01 -0700104 private final SwipeableListView mListView;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700105 private boolean mSwipeEnabled;
mindyp6a6deb22012-11-26 11:40:15 -0800106 private final HashMap<Long, LeaveBehindItem> mLeaveBehindItems = Maps.newHashMap();
Vikram Aggarwal33519c02012-07-31 16:45:31 -0700107 /** True if priority inbox markers are enabled, false otherwise. */
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700108 private boolean mPriorityMarkersEnabled;
Mindy Pereirae7d783d2012-08-07 14:06:34 -0700109 private ControllableActivity mActivity;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700110 private final AccountObserver mAccountListener = new AccountObserver() {
111 @Override
112 public void onChanged(Account newAccount) {
113 setAccount(newAccount);
114 notifyDataSetChanged();
115 }
116 };
117
118 private final void setAccount(Account newAccount) {
119 mAccount = newAccount;
120 mPriorityMarkersEnabled = mAccount.settings.priorityArrowsEnabled;
121 mSwipeEnabled = mAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO);
122 }
123
Vikram Aggarwal2ae81262012-03-27 15:43:57 -0700124 /**
125 * Used only for debugging.
126 */
Paul Westbrookb334c902012-06-25 11:42:46 -0700127 private static final String LOG_TAG = LogTag.getLogTag();
mindypa44babd2013-01-17 09:59:25 -0800128 private static final int INCREASE_WAIT_COUNT = 2;
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800129
130 public AnimatedAdapter(Context context, int textViewResourceId, ConversationCursor cursor,
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700131 ConversationSelectionSet batch,
Mindy Pereirae7d783d2012-08-07 14:06:34 -0700132 ControllableActivity activity, SwipeableListView listView) {
Andy Huang2c4e6dc2012-07-25 18:02:59 -0700133 super(context, textViewResourceId, cursor, UIProvider.CONVERSATION_PROJECTION, null, 0);
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800134 mContext = context;
135 mBatchConversations = batch;
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700136 setAccount(mAccountListener.initialize(activity.getAccountController()));
Mindy Pereirae7d783d2012-08-07 14:06:34 -0700137 mActivity = activity;
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800138 mShowFooter = false;
Marc Blank66bee6e2012-04-01 15:02:24 -0700139 mListView = listView;
mindyp6a6deb22012-11-26 11:40:15 -0800140 mHandler = new Handler();
mindypa44babd2013-01-17 09:59:25 -0800141 if (sDismissAllShortDelay == -1) {
142 sDismissAllShortDelay =
143 context.getResources()
144 .getInteger(R.integer.dismiss_all_leavebehinds_short_delay);
145 sDismissAllLongDelay =
146 context.getResources()
147 .getInteger(R.integer.dismiss_all_leavebehinds_long_delay);
mindyp6a6deb22012-11-26 11:40:15 -0800148 }
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700149 }
150
mindyp3b5e82b2012-12-18 14:23:20 -0800151 public void cancelDismissCounter() {
mindyp4d4531a2013-01-16 15:39:53 -0800152 cancelLeaveBehindFadeInAnimation();
mindyp3b5e82b2012-12-18 14:23:20 -0800153 mHandler.removeCallbacks(mCountDown);
154 }
155
156 public void startDismissCounter() {
mindypa44babd2013-01-17 09:59:25 -0800157 if (mLeaveBehindItems.size() > INCREASE_WAIT_COUNT) {
158 mHandler.postDelayed(mCountDown, sDismissAllLongDelay);
159 } else {
160 mHandler.postDelayed(mCountDown, sDismissAllShortDelay);
161 }
mindyp3b5e82b2012-12-18 14:23:20 -0800162 }
163
Vikram Aggarwal7c401b72012-08-13 16:43:47 -0700164 public final void destroy() {
165 // Set a null cursor in the adapter
166 swapCursor(null);
167 mAccountListener.unregisterAndDestroy();
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800168 }
169
170 @Override
171 public int getCount() {
Vikram Aggarwalb54a4672012-04-11 11:32:44 -0700172 final int count = super.getCount();
Marc Blank66bee6e2012-04-01 15:02:24 -0700173 return mShowFooter ? count + 1 : count;
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800174 }
175
Mindy Pereira6c72a782012-04-07 14:29:15 -0700176 public void setUndo(boolean undo) {
mindyp3b5e82b2012-12-18 14:23:20 -0800177 if (undo) {
178 if (!mLastDeletingItems.isEmpty()) {
179 mUndoingItems.addAll(mLastDeletingItems);
180 mLastDeletingItems.clear();
181 }
182 if (mLastLeaveBehind != -1) {
183 mUndoingItems.add(mLastLeaveBehind);
184 mLastLeaveBehind = -1;
185 }
Marc Blank2596f002012-03-22 10:26:26 -0700186 // Start animation
187 notifyDataSetChanged();
Vikram Aggarwalc30fe412012-05-18 11:58:58 -0700188 performAndSetNextAction(mRefreshAction);
Marc Blank3b2d9132012-02-05 12:21:10 -0800189 }
190 }
191
Mindy Pereirabdb43d52012-07-25 17:46:00 -0700192 public void setSwipeUndo(boolean undo) {
mindyp3b5e82b2012-12-18 14:23:20 -0800193 if (undo) {
194 if (!mLastDeletingItems.isEmpty()) {
195 mSwipeUndoingItems.addAll(mLastDeletingItems);
196 mLastDeletingItems.clear();
197 }
198 if (mLastLeaveBehind != -1) {
199 mSwipeUndoingItems.add(mLastLeaveBehind);
200 mLastLeaveBehind = -1;
201 }
Mindy Pereirabdb43d52012-07-25 17:46:00 -0700202 // Start animation
203 notifyDataSetChanged();
204 performAndSetNextAction(mRefreshAction);
205 }
206 }
207
mindyp0abee552012-08-30 12:34:22 -0700208 public View createConversationItemView(SwipeableConversationItemView view, Context context,
209 Conversation conv) {
210 if (view == null) {
211 view = new SwipeableConversationItemView(context, mAccount.name);
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800212 }
Marc Blank87557c12012-09-23 12:44:59 -0700213 view.bind(conv, mActivity, mBatchConversations, mFolder,
Paul Westbrook7ed53772013-01-23 10:19:55 -0800214 mAccount != null ? mAccount.settings.hideCheckboxes : false, mSwipeEnabled,
mindyp0abee552012-08-30 12:34:22 -0700215 mPriorityMarkersEnabled, this);
216 return view;
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800217 }
218
Marc Blankdd10bc82012-02-01 19:10:46 -0800219 @Override
220 public boolean hasStableIds() {
221 return true;
222 }
223
224 @Override
225 public int getViewTypeCount() {
Mindy Pereira46493942012-04-13 09:09:52 -0700226 // TYPE_VIEW_CONVERSATION, TYPE_VIEW_DELETING, TYPE_VIEW_UNDOING, and
Mindy Pereira6c72a782012-04-07 14:29:15 -0700227 // TYPE_VIEW_FOOTER, TYPE_VIEW_LEAVEBEHIND.
228 return 5;
Marc Blankdd10bc82012-02-01 19:10:46 -0800229 }
230
231 @Override
232 public int getItemViewType(int position) {
Vikram Aggarwalb54a4672012-04-11 11:32:44 -0700233 // Try to recycle views.
Vikram Aggarwalb54a4672012-04-11 11:32:44 -0700234 if (mShowFooter && position == super.getCount()) {
235 return TYPE_VIEW_FOOTER;
mindypd0f95782012-10-09 13:51:40 -0700236 } else if (hasLeaveBehinds() || isAnimating()) {
237 // Setting as type -1 means the recycler won't take this view and
238 // return it in get view. This is a bit of a "hammer" in that it
239 // won't let even safe views be recycled here,
240 // but its safer and cheaper than trying to determine individual
241 // types. In a future release, use position/id map to try to make
242 // this cleaner / faster to determine if the view is animating.
243 return TYPE_VIEW_DONT_RECYCLE;
Vikram Aggarwalb54a4672012-04-11 11:32:44 -0700244 }
245 return TYPE_VIEW_CONVERSATION;
Marc Blankdd10bc82012-02-01 19:10:46 -0800246 }
247
Vikram Aggarwal54452ae2012-03-13 15:29:00 -0700248 /**
Mindy Pereira067ef972012-08-08 14:04:06 -0700249 * Deletes the selected conversations from the conversation list view with a
250 * translation and then a shrink. These conversations <b>must</b> have their
251 * {@link Conversation#position} set to the position of these conversations
252 * among the list. This will only remove the element from the list. The job
253 * of deleting the actual element is left to the the listener. This listener
254 * will be called when the animations are complete and is required to delete
255 * the conversation.
256 * @param conversations
257 * @param listener
258 */
mindyp9365a822012-09-12 09:09:09 -0700259 public void swipeDelete(Collection<Conversation> conversations,
260 ListItemsRemovedListener listener) {
Mindy Pereira067ef972012-08-08 14:04:06 -0700261 delete(conversations, listener, mSwipeDeletingItems);
262 }
263
264
265 /**
266 * Deletes the selected conversations from the conversation list view by
267 * shrinking them away. These conversations <b>must</b> have their
268 * {@link Conversation#position} set to the position of these conversations
269 * among the list. This will only remove the element from the list. The job
270 * of deleting the actual element is left to the the listener. This listener
271 * will be called when the animations are complete and is required to delete
272 * the conversation.
Vikram Aggarwal54452ae2012-03-13 15:29:00 -0700273 * @param conversations
274 * @param listener
275 */
mindyp9365a822012-09-12 09:09:09 -0700276 public void delete(Collection<Conversation> conversations, ListItemsRemovedListener listener) {
Mindy Pereira067ef972012-08-08 14:04:06 -0700277 delete(conversations, listener, mDeletingItems);
Mindy Pereirafac92d72012-02-01 10:58:33 -0800278 }
279
mindyp9365a822012-09-12 09:09:09 -0700280 private void delete(Collection<Conversation> conversations, ListItemsRemovedListener listener,
mindype85b8cd2012-08-23 11:32:26 -0700281 HashSet<Long> list) {
Marc Blank3b2d9132012-02-05 12:21:10 -0800282 // Clear out any remaining items and add the new ones
283 mLastDeletingItems.clear();
Paul Westbrooke4abda72012-10-15 18:23:46 -0700284 // Since we are deleting new items, clear any remaining undo items
285 mUndoingItems.clear();
Marc Blank66bee6e2012-04-01 15:02:24 -0700286
Vikram Aggarwalb54a4672012-04-11 11:32:44 -0700287 final int startPosition = mListView.getFirstVisiblePosition();
288 final int endPosition = mListView.getLastVisiblePosition();
Marc Blank66bee6e2012-04-01 15:02:24 -0700289
290 // Only animate visible items
mindype85b8cd2012-08-23 11:32:26 -0700291 for (Conversation c: conversations) {
292 if (c.position >= startPosition && c.position <= endPosition) {
293 mLastDeletingItems.add(c.id);
294 list.add(c.id);
Marc Blank66bee6e2012-04-01 15:02:24 -0700295 }
296 }
297
Mindy Pereira067ef972012-08-08 14:04:06 -0700298 if (list.isEmpty()) {
Marc Blank66bee6e2012-04-01 15:02:24 -0700299 // If we have no deleted items on screen, skip the animation
mindyp9365a822012-09-12 09:09:09 -0700300 listener.onListItemsRemoved();
Marc Blank66bee6e2012-04-01 15:02:24 -0700301 } else {
mindyp9365a822012-09-12 09:09:09 -0700302 performAndSetNextAction(listener);
Marc Blank66bee6e2012-04-01 15:02:24 -0700303 }
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800304 notifyDataSetChanged();
305 }
306
307 @Override
308 public View getView(int position, View convertView, ViewGroup parent) {
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800309 if (mShowFooter && position == super.getCount()) {
310 return mFooter;
311 }
mindyp0abee552012-08-30 12:34:22 -0700312 ConversationCursor cursor = (ConversationCursor) getItem(position);
313 Conversation conv = new Conversation(cursor);
mindype85b8cd2012-08-23 11:32:26 -0700314 if (isPositionUndoing(conv.id)) {
315 return getUndoingView(position, conv, parent, false /* don't show swipe background */);
316 } if (isPositionUndoingSwipe(conv.id)) {
317 return getUndoingView(position, conv, parent, true /* show swipe background */);
318 } else if (isPositionDeleting(conv.id)) {
319 return getDeletingView(position, conv, parent, false);
320 } else if (isPositionSwipeDeleting(conv.id)) {
321 return getDeletingView(position, conv, parent, true);
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800322 }
Andy Huang62d79622012-07-24 18:50:34 -0700323 if (hasFadeLeaveBehinds()) {
Andy Huang62d79622012-07-24 18:50:34 -0700324 if(isPositionFadeLeaveBehind(conv)) {
325 LeaveBehindItem fade = getFadeLeaveBehindItem(position, conv);
mindyp4d4531a2013-01-16 15:39:53 -0800326 fade.startShrinkAnimation(mActivity.getViewMode(), this);
Andy Huang62d79622012-07-24 18:50:34 -0700327 return fade;
328 }
329 }
Mindy Pereira6c72a782012-04-07 14:29:15 -0700330 if (hasLeaveBehinds()) {
mindype358ed52012-11-26 09:25:25 -0800331 if (isPositionLeaveBehind(conv)) {
Mindy Pereira84f9b5c2012-08-16 10:40:47 -0700332 LeaveBehindItem fadeIn = getLeaveBehindItem(conv);
mindyp4d4531a2013-01-16 15:39:53 -0800333 if (conv.id == mLastLeaveBehind) {
mindypa44babd2013-01-17 09:59:25 -0800334 // If it looks like the person is doing a lot of rapid
335 // swipes, wait patiently before animating
336 if (mLeaveBehindItems.size() > INCREASE_WAIT_COUNT) {
337 if (fadeIn.isAnimating()) {
338 fadeIn.increaseFadeInDelay(sDismissAllLongDelay);
339 } else {
340 fadeIn.startFadeInTextAnimation(sDismissAllLongDelay);
341 }
342 } else {
343 // Otherwise, assume they are just doing 1 and wait less time
344 fadeIn.startFadeInTextAnimation(sDismissAllShortDelay /* delay start */);
345 }
mindyp4d4531a2013-01-16 15:39:53 -0800346 }
Mindy Pereira84f9b5c2012-08-16 10:40:47 -0700347 return fadeIn;
Mindy Pereira6c72a782012-04-07 14:29:15 -0700348 }
349 }
Mindy Pereira067ef972012-08-08 14:04:06 -0700350 if (convertView != null && !(convertView instanceof SwipeableConversationItemView)) {
351 LogUtils.w(LOG_TAG, "Incorrect convert view received; nulling it out");
mindypeb88ece2012-10-09 11:54:09 -0700352 convertView = newView(mContext, cursor, parent);
Mindy Pereirac79aec72012-08-08 14:04:06 -0700353 } else if (convertView != null) {
354 ((SwipeableConversationItemView) convertView).reset();
Mindy Pereiraafd6f922012-03-16 15:21:33 -0700355 }
mindyp0abee552012-08-30 12:34:22 -0700356 return createConversationItemView((SwipeableConversationItemView) convertView, mContext,
357 conv);
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800358 }
359
Mindy Pereira6c72a782012-04-07 14:29:15 -0700360 private boolean hasLeaveBehinds() {
mindyp6a6deb22012-11-26 11:40:15 -0800361 return !mLeaveBehindItems.isEmpty();
Mindy Pereira6c72a782012-04-07 14:29:15 -0700362 }
363
Andy Huang62d79622012-07-24 18:50:34 -0700364 private boolean hasFadeLeaveBehinds() {
Mindy Pereira8f397022012-08-12 11:19:15 -0700365 return !mFadeLeaveBehindItems.isEmpty();
Andy Huang62d79622012-07-24 18:50:34 -0700366 }
367
Mindy Pereira79e6a082012-07-25 13:36:53 -0700368 public LeaveBehindItem setupLeaveBehind(Conversation target, ToastBarOperation undoOp,
369 int deletedRow) {
mindyp4d4531a2013-01-16 15:39:53 -0800370 cancelLeaveBehindFadeInAnimation();
mindyp6a6deb22012-11-26 11:40:15 -0800371 mLastLeaveBehind = target.id;
Andy Huang62d79622012-07-24 18:50:34 -0700372 fadeOutLeaveBehindItems();
mindypb02ec692012-09-12 09:43:20 -0700373 boolean isWide = ConversationItemViewCoordinates.isWideMode(ConversationItemViewCoordinates
374 .getMode(mContext, mActivity.getViewMode()));
Mindy Pereiradea5d772012-04-17 08:13:39 -0700375 LeaveBehindItem leaveBehind = (LeaveBehindItem) LayoutInflater.from(mContext).inflate(
mindypb02ec692012-09-12 09:43:20 -0700376 isWide? R.layout.swipe_leavebehind_wide : R.layout.swipe_leavebehind, null);
Mindy Pereirabcd784c2012-08-10 09:53:24 -0700377 leaveBehind.bindOperations(deletedRow, mAccount, this, undoOp, target, mFolder);
mindyp6a6deb22012-11-26 11:40:15 -0800378 mLeaveBehindItems.put(target.id, leaveBehind);
mindype85b8cd2012-08-23 11:32:26 -0700379 mLastDeletingItems.add(target.id);
Mindy Pereira79e6a082012-07-25 13:36:53 -0700380 return leaveBehind;
Mindy Pereira6c72a782012-04-07 14:29:15 -0700381 }
382
mindyp6a6deb22012-11-26 11:40:15 -0800383 public void fadeOutSpecificLeaveBehindItem(long id) {
384 if (mLastLeaveBehind == id) {
385 mLastLeaveBehind = -1;
386 }
387 startFadeOutLeaveBehindItemsAnimations();
388 }
389
390 // This should kick off a timer such that there is a minimum time each item
391 // shows up before being dismissed. That way if the user is swiping away
392 // items in rapid succession, their finger position is maintained.
Andy Huang62d79622012-07-24 18:50:34 -0700393 public void fadeOutLeaveBehindItems() {
mindyp6a6deb22012-11-26 11:40:15 -0800394 if (mCountDown == null) {
395 mCountDown = new Runnable() {
396 @Override
397 public void run() {
398 startFadeOutLeaveBehindItemsAnimations();
399 }
400 };
401 } else {
402 mHandler.removeCallbacks(mCountDown);
403 }
404 // Clear all the text since these are no longer clickable
405 Iterator<Entry<Long, LeaveBehindItem>> i = mLeaveBehindItems.entrySet().iterator();
406 LeaveBehindItem item;
407 while (i.hasNext()) {
408 item = i.next().getValue();
409 Conversation conv = item.getData();
410 if (mLastLeaveBehind == -1 || conv.id != mLastLeaveBehind) {
mindypa44babd2013-01-17 09:59:25 -0800411 item.cancelFadeInTextAnimation();
mindyp6a6deb22012-11-26 11:40:15 -0800412 item.makeInert();
413 }
414 }
mindyp3b5e82b2012-12-18 14:23:20 -0800415 startDismissCounter();
mindyp6a6deb22012-11-26 11:40:15 -0800416 }
417
418 protected void startFadeOutLeaveBehindItemsAnimations() {
Andy Huang62d79622012-07-24 18:50:34 -0700419 final int startPosition = mListView.getFirstVisiblePosition();
420 final int endPosition = mListView.getLastVisiblePosition();
421
Mindy Pereira79e6a082012-07-25 13:36:53 -0700422 if (hasLeaveBehinds()) {
423 // If the item is visible, fade it out. Otherwise, just remove
424 // it.
mindyp6a6deb22012-11-26 11:40:15 -0800425 Iterator<Entry<Long, LeaveBehindItem>> i = mLeaveBehindItems.entrySet().iterator();
426 LeaveBehindItem item;
427 while (i.hasNext()) {
428 item = i.next().getValue();
429 Conversation conv = item.getData();
430 if (mLastLeaveBehind == -1 || conv.id != mLastLeaveBehind) {
431 if (conv.position >= startPosition && conv.position <= endPosition) {
432 mFadeLeaveBehindItems.put(conv.id, item);
433 } else {
434 item.commit();
435 }
436 i.remove();
437 }
Mindy Pereiradea5d772012-04-17 08:13:39 -0700438 }
mindyp4d4531a2013-01-16 15:39:53 -0800439 cancelLeaveBehindFadeInAnimation();
Mindy Pereiradea5d772012-04-17 08:13:39 -0700440 }
Mindy Pereira06b62382012-07-24 14:31:20 -0700441 if (!mLastDeletingItems.isEmpty()) {
442 mLastDeletingItems.clear();
443 }
Mindy Pereira1e2573b2012-04-17 14:34:36 -0700444 notifyDataSetChanged();
Mindy Pereiradea5d772012-04-17 08:13:39 -0700445 }
446
mindyp4d4531a2013-01-16 15:39:53 -0800447 private void cancelLeaveBehindFadeInAnimation() {
448 LeaveBehindItem leaveBehind = getLastLeaveBehindItem();
449 if (leaveBehind != null) {
450 leaveBehind.cancelFadeInTextAnimation();
451 }
452 }
453
mindyp52544862012-08-20 12:05:36 -0700454 public SwipeableListView getListView() {
455 return mListView;
456 }
457
mindypc6adce32012-08-22 18:46:42 -0700458 public void commitLeaveBehindItems(boolean animate) {
Andy Huang62d79622012-07-24 18:50:34 -0700459 // Remove any previously existing leave behinds.
mindyp52544862012-08-20 12:05:36 -0700460 boolean changed = false;
Mindy Pereira79e6a082012-07-25 13:36:53 -0700461 if (hasLeaveBehinds()) {
mindyp6a6deb22012-11-26 11:40:15 -0800462 for (LeaveBehindItem item : mLeaveBehindItems.values()) {
463 if (animate) {
mindypdcb26ae2012-11-26 13:25:05 -0800464 mFadeLeaveBehindItems.put(item.getConversationId(), item);
mindyp6a6deb22012-11-26 11:40:15 -0800465 } else {
466 item.commit();
467 }
mindypc6adce32012-08-22 18:46:42 -0700468 }
mindyp52544862012-08-20 12:05:36 -0700469 changed = true;
mindyp6a6deb22012-11-26 11:40:15 -0800470 mLastLeaveBehind = -1;
471 mLeaveBehindItems.clear();
Mindy Pereira79e6a082012-07-25 13:36:53 -0700472 }
mindypaa55bc92012-08-24 09:49:56 -0700473 if (hasFadeLeaveBehinds() && !animate) {
474 // Find any fading leave behind items and commit them all, too.
475 for (LeaveBehindItem item : mFadeLeaveBehindItems.values()) {
476 item.commit();
477 }
478 mFadeLeaveBehindItems.clear();
479 changed = true;
480 }
Andy Huang62d79622012-07-24 18:50:34 -0700481 if (!mLastDeletingItems.isEmpty()) {
482 mLastDeletingItems.clear();
mindyp52544862012-08-20 12:05:36 -0700483 changed = true;
Andy Huang62d79622012-07-24 18:50:34 -0700484 }
mindyp52544862012-08-20 12:05:36 -0700485 if (changed) {
486 notifyDataSetChanged();
487 }
Andy Huang62d79622012-07-24 18:50:34 -0700488 }
489
Mindy Pereira79e6a082012-07-25 13:36:53 -0700490 private LeaveBehindItem getLeaveBehindItem(Conversation target) {
mindyp6a6deb22012-11-26 11:40:15 -0800491 return mLeaveBehindItems.get(target.id);
Mindy Pereira6c72a782012-04-07 14:29:15 -0700492 }
493
Andy Huang62d79622012-07-24 18:50:34 -0700494 private LeaveBehindItem getFadeLeaveBehindItem(int position, Conversation target) {
Mindy Pereira8f397022012-08-12 11:19:15 -0700495 return mFadeLeaveBehindItems.get(target.id);
Andy Huang62d79622012-07-24 18:50:34 -0700496 }
497
Mindy Pereirad3651a62012-04-04 12:23:40 -0700498 @Override
499 public long getItemId(int position) {
500 if (mShowFooter && position == super.getCount()) {
501 return -1;
502 }
503 return super.getItemId(position);
504 }
505
mindype85b8cd2012-08-23 11:32:26 -0700506 private View getDeletingView(int position, Conversation conversation, ViewGroup parent,
507 boolean swipe) {
Vikram Aggarwalc7d201d2012-02-15 13:21:10 -0800508 conversation.position = position;
Mindy Pereira067ef972012-08-08 14:04:06 -0700509 SwipeableConversationItemView deletingView = mAnimatingViews.get(conversation.id);
510 if (deletingView == null) {
511 // The undo animation consists of fading in the conversation that
512 // had been destroyed.
513 deletingView = newConversationItemView(position, parent, conversation);
514 deletingView.startDeleteAnimation(this, swipe);
515 }
516 return deletingView;
Mindy Pereiraa41baad2012-04-13 08:30:54 -0700517 }
518
mindype85b8cd2012-08-23 11:32:26 -0700519 private View getUndoingView(int position, Conversation conv, ViewGroup parent, boolean swipe) {
520 conv.position = position;
521 SwipeableConversationItemView undoView = mAnimatingViews.get(conv.id);
Mindy Pereira067ef972012-08-08 14:04:06 -0700522 if (undoView == null) {
523 // The undo animation consists of fading in the conversation that
524 // had been destroyed.
mindype85b8cd2012-08-23 11:32:26 -0700525 undoView = newConversationItemView(position, parent, conv);
Mindy Pereira84f9b5c2012-08-16 10:40:47 -0700526 undoView.startUndoAnimation(mActivity.getViewMode(), this, swipe);
Mindy Pereira067ef972012-08-08 14:04:06 -0700527 }
528 return undoView;
529 }
530
mindyp5ceab3b2012-08-30 16:41:59 -0700531 @Override
532 public View newView(Context context, Cursor cursor, ViewGroup parent) {
533 SwipeableConversationItemView view = new SwipeableConversationItemView(context,
534 mAccount.name);
535 return view;
536 }
537
538 @Override
539 public void bindView(View view, Context context, Cursor cursor) {
540 if (! (view instanceof SwipeableConversationItemView)) {
541 return;
542 }
543 ((SwipeableConversationItemView) view).bind(cursor, mActivity, mBatchConversations, mFolder,
Paul Westbrook7ed53772013-01-23 10:19:55 -0800544 mAccount != null ? mAccount.settings.hideCheckboxes : false,
mindyp5ceab3b2012-08-30 16:41:59 -0700545 mSwipeEnabled, mPriorityMarkersEnabled, this);
546 }
547
Mindy Pereira067ef972012-08-08 14:04:06 -0700548 private SwipeableConversationItemView newConversationItemView(int position, ViewGroup parent,
549 Conversation conversation) {
550 SwipeableConversationItemView view = (SwipeableConversationItemView) super.getView(
551 position, null, parent);
mindypdc0617f2012-08-31 14:30:18 -0700552 view.reset();
Mindy Pereira067ef972012-08-08 14:04:06 -0700553 view.bind(conversation, mActivity, mBatchConversations, mFolder,
Paul Westbrook7ed53772013-01-23 10:19:55 -0800554 mAccount != null ? mAccount.settings.hideCheckboxes : false, mSwipeEnabled,
Vikram Aggarwal33519c02012-07-31 16:45:31 -0700555 mPriorityMarkersEnabled, this);
Mindy Pereira067ef972012-08-08 14:04:06 -0700556 mAnimatingViews.put(conversation.id, view);
557 return view;
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800558 }
559
Mindy Pereirad3651a62012-04-04 12:23:40 -0700560 @Override
561 public Object getItem(int position) {
562 if (mShowFooter && position == super.getCount()) {
563 return mFooter;
564 }
565 return super.getItem(position);
566 }
567
mindype85b8cd2012-08-23 11:32:26 -0700568 private boolean isPositionDeleting(long id) {
569 return mDeletingItems.contains(id);
Mindy Pereiraa41baad2012-04-13 08:30:54 -0700570 }
571
mindype85b8cd2012-08-23 11:32:26 -0700572 private boolean isPositionSwipeDeleting(long id) {
573 return mSwipeDeletingItems.contains(id);
Mindy Pereira067ef972012-08-08 14:04:06 -0700574 }
575
mindype85b8cd2012-08-23 11:32:26 -0700576 private boolean isPositionUndoing(long id) {
577 return mUndoingItems.contains(id);
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800578 }
579
mindype85b8cd2012-08-23 11:32:26 -0700580 private boolean isPositionUndoingSwipe(long id) {
581 return mSwipeUndoingItems.contains(id);
Mindy Pereirabdb43d52012-07-25 17:46:00 -0700582 }
583
Mindy Pereira6c72a782012-04-07 14:29:15 -0700584 private boolean isPositionLeaveBehind(Conversation conv) {
Mindy Pereira79e6a082012-07-25 13:36:53 -0700585 return hasLeaveBehinds()
mindyp6a6deb22012-11-26 11:40:15 -0800586 && mLeaveBehindItems.containsKey(conv.id)
Mindy Pereira79e6a082012-07-25 13:36:53 -0700587 && conv.isMostlyDead();
Mindy Pereira6c72a782012-04-07 14:29:15 -0700588 }
589
Andy Huang62d79622012-07-24 18:50:34 -0700590 private boolean isPositionFadeLeaveBehind(Conversation conv) {
Mindy Pereira79e6a082012-07-25 13:36:53 -0700591 return hasFadeLeaveBehinds()
Mindy Pereira8f397022012-08-12 11:19:15 -0700592 && mFadeLeaveBehindItems.containsKey(conv.id)
Mindy Pereira79e6a082012-07-25 13:36:53 -0700593 && conv.isMostlyDead();
Andy Huang62d79622012-07-24 18:50:34 -0700594 }
595
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800596 @Override
597 public void onAnimationStart(Animator animation) {
Mindy Pereira6c72a782012-04-07 14:29:15 -0700598 if (!mUndoingItems.isEmpty()) {
Mindy Pereira866d3192012-03-26 09:50:00 -0700599 mDeletingItems.clear();
600 mLastDeletingItems.clear();
Mindy Pereira067ef972012-08-08 14:04:06 -0700601 mSwipeDeletingItems.clear();
Mindy Pereiraa41baad2012-04-13 08:30:54 -0700602 } else {
603 mUndoingItems.clear();
Mindy Pereira866d3192012-03-26 09:50:00 -0700604 }
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800605 }
606
Vikram Aggarwalc30fe412012-05-18 11:58:58 -0700607 /**
608 * Performs the pending destruction, if any and assigns the next pending action.
609 * @param next The next action that is to be performed, possibly null (if no next action is
610 * needed).
611 */
mindyp9365a822012-09-12 09:09:09 -0700612 private final void performAndSetNextAction(ListItemsRemovedListener next) {
Vikram Aggarwalc30fe412012-05-18 11:58:58 -0700613 if (mPendingDestruction != null) {
mindyp9365a822012-09-12 09:09:09 -0700614 mPendingDestruction.onListItemsRemoved();
Vikram Aggarwalc30fe412012-05-18 11:58:58 -0700615 }
616 mPendingDestruction = next;
617 }
618
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800619 @Override
620 public void onAnimationEnd(Animator animation) {
Mindy Pereira067ef972012-08-08 14:04:06 -0700621 Object obj;
622 if (animation instanceof AnimatorSet) {
623 AnimatorSet set = (AnimatorSet) animation;
624 obj = ((ObjectAnimator) set.getChildAnimations().get(0)).getTarget();
625 } else {
626 obj = ((ObjectAnimator) animation).getTarget();
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800627 }
Mindy Pereira067ef972012-08-08 14:04:06 -0700628 updateAnimatingConversationItems(obj, mSwipeDeletingItems);
629 updateAnimatingConversationItems(obj, mDeletingItems);
630 updateAnimatingConversationItems(obj, mSwipeUndoingItems);
631 updateAnimatingConversationItems(obj, mUndoingItems);
632 if (hasFadeLeaveBehinds() && obj instanceof LeaveBehindItem) {
633 LeaveBehindItem objItem = (LeaveBehindItem) obj;
634 clearLeaveBehind(objItem.getConversationId());
635 objItem.commit();
mindyp4d4531a2013-01-16 15:39:53 -0800636 if (!hasFadeLeaveBehinds()) {
mindypac2ef812013-01-17 09:10:04 -0800637 // Cancel any existing animations on the remaining leave behind
638 // item and start fading in text immediately.
mindypac2ef812013-01-17 09:10:04 -0800639 LeaveBehindItem item = getLastLeaveBehindItem();
640 if (item != null) {
mindypa44babd2013-01-17 09:59:25 -0800641 boolean cancelled = item.cancelFadeInTextAnimationIfNotStarted();
642 if (cancelled) {
643 item.startFadeInTextAnimation(0 /* delay start */);
644 }
mindypac2ef812013-01-17 09:10:04 -0800645 }
mindyp4d4531a2013-01-16 15:39:53 -0800646 }
Mindy Pereira067ef972012-08-08 14:04:06 -0700647 // The view types have changed, since the animating views are gone.
648 notifyDataSetChanged();
649 }
Paul Westbrookcff1aea2012-08-10 11:51:00 -0700650
651 if (!isAnimating()) {
652 mActivity.onAnimationEnd(this);
653 }
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800654 }
655
mindype85b8cd2012-08-23 11:32:26 -0700656 private void updateAnimatingConversationItems(Object obj, HashSet<Long> items) {
Mindy Pereira067ef972012-08-08 14:04:06 -0700657 if (!items.isEmpty()) {
658 if (obj instanceof ConversationItemView) {
659 final ConversationItemView target = (ConversationItemView) obj;
mindype85b8cd2012-08-23 11:32:26 -0700660 final long id = target.getConversation().id;
661 items.remove(id);
662 mAnimatingViews.remove(id);
Mindy Pereira067ef972012-08-08 14:04:06 -0700663 if (items.isEmpty()) {
664 performAndSetNextAction(null);
665 notifyDataSetChanged();
666 }
667 }
668 }
Mindy Pereirabdb43d52012-07-25 17:46:00 -0700669 }
670
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800671 @Override
Mindy Pereira866d3192012-03-26 09:50:00 -0700672 public boolean areAllItemsEnabled() {
Vikram Aggarwalb54a4672012-04-11 11:32:44 -0700673 // The animating positions are not enabled.
Mindy Pereira866d3192012-03-26 09:50:00 -0700674 return false;
675 }
676
677 @Override
678 public boolean isEnabled(int position) {
Mindy Pereiraa41baad2012-04-13 08:30:54 -0700679 return !isPositionDeleting(position) && !isPositionUndoing(position);
Mindy Pereira866d3192012-03-26 09:50:00 -0700680 }
681
682 @Override
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800683 public void onAnimationCancel(Animator animation) {
Mindy Pereira92cabad2012-01-31 12:53:22 -0800684 onAnimationEnd(animation);
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800685 }
686
687 @Override
688 public void onAnimationRepeat(Animator animation) {
Mindy Pereira9879d4c2012-01-31 09:34:18 -0800689 }
Mindy Pereira674afa42012-02-17 14:05:24 -0800690
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800691 public void showFooter() {
Paul Westbrook573b9e62012-08-02 14:56:17 -0700692 setFooterVisibility(true);
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800693 }
694
695 public void hideFooter() {
Paul Westbrook573b9e62012-08-02 14:56:17 -0700696 setFooterVisibility(false);
697 }
698
699 public void setFooterVisibility(boolean show) {
700 if (mShowFooter != show) {
701 mShowFooter = show;
Mindy Pereira6681f6b2012-03-09 13:55:54 -0800702 notifyDataSetChanged();
703 }
704 }
705
706 public void addFooter(View footerView) {
707 mFooter = footerView;
708 }
Mindy Pereira4584a0d2012-03-13 14:42:14 -0700709
710 public void setFolder(Folder folder) {
711 mFolder = folder;
712 }
Mindy Pereira6c72a782012-04-07 14:29:15 -0700713
Mindy Pereira79e6a082012-07-25 13:36:53 -0700714 public void clearLeaveBehind(long itemId) {
mindyp6a6deb22012-11-26 11:40:15 -0800715 if (hasLeaveBehinds() && mLeaveBehindItems.containsKey(itemId)) {
716 mLeaveBehindItems.remove(itemId);
Mindy Pereira8f397022012-08-12 11:19:15 -0700717 } else if (hasFadeLeaveBehinds()) {
718 mFadeLeaveBehindItems.remove(itemId);
Mindy Pereira79e6a082012-07-25 13:36:53 -0700719 } else {
720 LogUtils.d(LOG_TAG, "Trying to clear a non-existant leave behind");
721 }
mindyp6a6deb22012-11-26 11:40:15 -0800722 if (mLastLeaveBehind == itemId) {
723 mLastLeaveBehind = -1;
724 }
Mindy Pereira6c72a782012-04-07 14:29:15 -0700725 }
Vikram Aggarwal7d816002012-04-17 17:06:41 -0700726
Mindy Pereirad33674992012-06-25 16:26:30 -0700727 public void onSaveInstanceState(Bundle outState) {
mindype85b8cd2012-08-23 11:32:26 -0700728 long[] lastDeleting = new long[mLastDeletingItems.size()];
Mindy Pereira79e6a082012-07-25 13:36:53 -0700729 for (int i = 0; i < lastDeleting.length; i++) {
Mindy Pereirad33674992012-06-25 16:26:30 -0700730 lastDeleting[i] = mLastDeletingItems.get(i);
731 }
mindype85b8cd2012-08-23 11:32:26 -0700732 outState.putLongArray(LAST_DELETING_ITEMS, lastDeleting);
Mindy Pereira79e6a082012-07-25 13:36:53 -0700733 if (hasLeaveBehinds()) {
mindyp6a6deb22012-11-26 11:40:15 -0800734 if (mLastLeaveBehind != -1) {
735 outState.putParcelable(LEAVE_BEHIND_ITEM_DATA,
736 mLeaveBehindItems.get(mLastLeaveBehind).getLeaveBehindData());
737 outState.putLong(LEAVE_BEHIND_ITEM_ID, mLastLeaveBehind);
738 }
739 for (LeaveBehindItem item : mLeaveBehindItems.values()) {
740 if (mLastLeaveBehind == -1 || item.getData().id != mLastLeaveBehind) {
741 item.commit();
742 }
743 }
Mindy Pereira79e6a082012-07-25 13:36:53 -0700744 }
Mindy Pereirad33674992012-06-25 16:26:30 -0700745 }
746
Mindy Pereirad33674992012-06-25 16:26:30 -0700747 public void onRestoreInstanceState(Bundle outState) {
Paul Westbrookb8ef4ac2012-07-16 16:56:14 -0700748 if (outState.containsKey(LAST_DELETING_ITEMS)) {
mindype85b8cd2012-08-23 11:32:26 -0700749 final long[] lastDeleting = outState.getLongArray(LAST_DELETING_ITEMS);
mindyp6a6deb22012-11-26 11:40:15 -0800750 for (int i = 0; i < lastDeleting.length; i++) {
Paul Westbrookb8ef4ac2012-07-16 16:56:14 -0700751 mLastDeletingItems.add(lastDeleting[i]);
752 }
Mindy Pereirad33674992012-06-25 16:26:30 -0700753 }
mindyp6a6deb22012-11-26 11:40:15 -0800754 if (outState.containsKey(LEAVE_BEHIND_ITEM_DATA)) {
755 LeaveBehindData left =
756 (LeaveBehindData) outState.getParcelable(LEAVE_BEHIND_ITEM_DATA);
757 mLeaveBehindItems.put(outState.getLong(LEAVE_BEHIND_ITEM_ID),
758 setupLeaveBehind(left.data, left.op, left.data.position));
Mindy Pereira79e6a082012-07-25 13:36:53 -0700759 }
Mindy Pereirad33674992012-06-25 16:26:30 -0700760 }
Mindy Pereira69e88dd2012-08-10 09:30:18 -0700761
762 /**
763 * Return if the adapter is in the process of animating anything.
764 */
765 public boolean isAnimating() {
766 return !mUndoingItems.isEmpty()
767 || !mSwipeUndoingItems.isEmpty()
Mindy Pereira1e946db2012-08-12 12:05:06 -0700768 || hasFadeLeaveBehinds()
Mindy Pereira69e88dd2012-08-10 09:30:18 -0700769 || !mDeletingItems.isEmpty()
770 || !mSwipeDeletingItems.isEmpty();
771 }
mindyp215d2a42012-08-27 17:26:28 -0700772
773 /**
774 * Get the ConversationCursor associated with this adapter.
775 */
776 public ConversationCursor getConversationCursor() {
777 return (ConversationCursor) getCursor();
778 }
mindyp7af43c92012-12-19 11:52:17 -0800779
mindyp4d4531a2013-01-16 15:39:53 -0800780 /**
781 * Get the currently visible leave behind item.
782 */
mindyp7af43c92012-12-19 11:52:17 -0800783 public LeaveBehindItem getLastLeaveBehindItem() {
784 if (mLastLeaveBehind != -1) {
785 return mLeaveBehindItems.get(mLastLeaveBehind);
786 }
787 return null;
788 }
mindyp4d4531a2013-01-16 15:39:53 -0800789
790 /**
791 * Cancel fading out the text displayed in the leave behind item currently
792 * shown.
793 */
794 public void cancelFadeOutLastLeaveBehindItemText() {
795 LeaveBehindItem item = getLastLeaveBehindItem();
796 if (item != null) {
797 item.cancelFadeOutText();
798 }
799 }
Paul Westbrook7ed53772013-01-23 10:19:55 -0800800}