19879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira/*
29879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * Copyright (C) 2012 Google Inc.
39879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * Licensed to The Android Open Source Project.
49879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira *
59879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
69879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * you may not use this file except in compliance with the License.
79879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * You may obtain a copy of the License at
89879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira *
99879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira *      http://www.apache.org/licenses/LICENSE-2.0
109879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira *
119879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * Unless required by applicable law or agreed to in writing, software
129879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
139879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
149879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * See the License for the specific language governing permissions and
159879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira * limitations under the License.
169879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira */
179879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
189879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereirapackage com.android.mail.ui;
199879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
209879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.animation.Animator;
21370f868c834861e7732faaa9bdd07a0fa0105596Andy Huangimport android.animation.Animator.AnimatorListener;
22370f868c834861e7732faaa9bdd07a0fa0105596Andy Huangimport android.animation.AnimatorListenerAdapter;
23067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereiraimport android.animation.AnimatorSet;
249879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.animation.ObjectAnimator;
259879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.content.Context;
2637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwalimport android.content.res.Resources;
279879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.database.Cursor;
28d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereiraimport android.os.Bundle;
296a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport android.os.Handler;
30d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedyimport android.os.Looper;
311801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sappersteinimport android.support.v4.text.BidiFormatter;
327c8325de829ca029ce4547e4f0fa266124301367Scott Kennedyimport android.util.SparseArray;
336c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereiraimport android.view.LayoutInflater;
349879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.view.View;
359879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.view.ViewGroup;
369879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport android.widget.SimpleCursorAdapter;
379879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
382b806edc62eb8e83c77edc471fda4652281a15c4James Lemieuximport com.android.bitmap.BitmapCache;
396c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereiraimport com.android.mail.R;
40042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huangimport com.android.mail.analytics.Analytics;
41a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.bitmap.ContactResolver;
429879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.browse.ConversationCursor;
439879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.browse.ConversationItemView;
441aba32575a08da6cbad80af8446201d73c59783dMark Weiimport com.android.mail.browse.ConversationItemViewCoordinates.CoordinatesCache;
451ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereiraimport com.android.mail.browse.SwipeableConversationItemView;
469879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.providers.Account;
477c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwalimport com.android.mail.providers.AccountObserver;
489879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.providers.Conversation;
494584a0d83e160444f931cb565185a2eea39b1683Mindy Pereiraimport com.android.mail.providers.Folder;
509879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.providers.UIProvider;
51642731419abb9037a729114d32d6ddd15af0a406Alice Yangimport com.android.mail.providers.UIProvider.ConversationListIcon;
529365a826b46b0e274df88e92534f7d871eef2aa2mindypimport com.android.mail.ui.SwipeableListView.ListItemsRemovedListener;
53b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
542ae81266ced36f2733ceab5a09c17ec939b9a62aVikram Aggarwalimport com.android.mail.utils.LogUtils;
55f82d6e7342e277f123a04fc82cc841b180655c15Andy Huangimport com.android.mail.utils.Utils;
56eb145d45c17b08ce09131e84b96350925b3db81aJin Caoimport com.google.common.collect.Lists;
576a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport com.google.common.collect.Maps;
582596f0011dcb4e86b01fc8a6362b5ac922239571Marc Blank
599879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport java.util.ArrayList;
60fac92d71ad83a34eb200cd9bcb773642e5e58de2Mindy Pereiraimport java.util.Collection;
61067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereiraimport java.util.HashMap;
629879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport java.util.HashSet;
636a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport java.util.Iterator;
647c8325de829ca029ce4547e4f0fa266124301367Scott Kennedyimport java.util.List;
656a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport java.util.Map.Entry;
669879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
67370f868c834861e7732faaa9bdd07a0fa0105596Andy Huangpublic class AnimatedAdapter extends SimpleCursorAdapter {
68a44babdac4e070034f35d984d06c675af8fee81fmindyp    private static int sDismissAllShortDelay = -1;
69a44babdac4e070034f35d984d06c675af8fee81fmindyp    private static int sDismissAllLongDelay = -1;
7079e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    private static final String LAST_DELETING_ITEMS = "last_deleting_items";
716a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private static final String LEAVE_BEHIND_ITEM_DATA = "leave_behind_item_data";
726a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private static final String LEAVE_BEHIND_ITEM_ID = "leave_behind_item_id";
73b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal    private final static int TYPE_VIEW_CONVERSATION = 0;
749365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private final static int TYPE_VIEW_FOOTER = 1;
75eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    private final static int TYPE_VIEW_HEADER = 2;
76d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp    private final static int TYPE_VIEW_DONT_RECYCLE = -1;
77e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mDeletingItems = new HashSet<Long>();
78e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final ArrayList<Long> mLastDeletingItems = new ArrayList<Long>();
79e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mUndoingItems = new HashSet<Long>();
80e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mSwipeDeletingItems = new HashSet<Long>();
81e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mSwipeUndoingItems = new HashSet<Long>();
82067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private final HashMap<Long, SwipeableConversationItemView> mAnimatingViews =
83067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            new HashMap<Long, SwipeableConversationItemView>();
841e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira    private final HashMap<Long, LeaveBehindItem> mFadeLeaveBehindItems =
858f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira            new HashMap<Long, LeaveBehindItem>();
8633519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal    /** The current account */
877c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private Account mAccount;
8833519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal    private final Context mContext;
8933519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal    private final ConversationSelectionSet mBatchConversations;
906a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private Runnable mCountDown;
912102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei    private final Handler mHandler;
926a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    protected long mLastLeaveBehind = -1;
936a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp
94370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    private final AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
95370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
96370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        @Override
97370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        public void onAnimationStart(Animator animation) {
98370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (!mUndoingItems.isEmpty()) {
99370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mDeletingItems.clear();
100370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mLastDeletingItems.clear();
101370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mSwipeDeletingItems.clear();
102370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
103370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        }
104370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
105370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        @Override
106370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        public void onAnimationEnd(Animator animation) {
107370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            Object obj;
108370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (animation instanceof AnimatorSet) {
109370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                AnimatorSet set = (AnimatorSet) animation;
110370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                obj = ((ObjectAnimator) set.getChildAnimations().get(0)).getTarget();
111370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            } else {
112370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                obj = ((ObjectAnimator) animation).getTarget();
113370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
114370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mSwipeDeletingItems);
115370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mDeletingItems);
116370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mSwipeUndoingItems);
117370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mUndoingItems);
118370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (hasFadeLeaveBehinds() && obj instanceof LeaveBehindItem) {
119370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                LeaveBehindItem objItem = (LeaveBehindItem) obj;
120370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                clearLeaveBehind(objItem.getConversationId());
121370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                objItem.commit();
122370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                if (!hasFadeLeaveBehinds()) {
123370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    // Cancel any existing animations on the remaining leave behind
124370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    // item and start fading in text immediately.
125370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    LeaveBehindItem item = getLastLeaveBehindItem();
126370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    if (item != null) {
127370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                        boolean cancelled = item.cancelFadeInTextAnimationIfNotStarted();
128370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                        if (cancelled) {
129370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                            item.startFadeInTextAnimation(0 /* delay start */);
130370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                        }
131370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    }
132370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                }
133370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                // The view types have changed, since the animating views are gone.
134370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                notifyDataSetChanged();
135370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
136370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
137370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (!isAnimating()) {
138370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mActivity.onAnimationEnd(AnimatedAdapter.this);
139370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
140370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        }
141370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
142370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    };
143370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
144c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    /**
145c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * The next action to perform. Do not read or write this. All accesses should
14637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * be in {@link #performAndSetNextAction(SwipeableListView.ListItemsRemovedListener)} which
14737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * commits the previous action, if any.
148c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     */
1499365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private ListItemsRemovedListener mPendingDestruction;
15037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
151c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    /**
152c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * A destructive action that refreshes the list and performs no other action.
153c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     */
1549365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private final ListItemsRemovedListener mRefreshAction = new ListItemsRemovedListener() {
155c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        @Override
1569365a826b46b0e274df88e92534f7d871eef2aa2mindyp        public void onListItemsRemoved() {
157c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal            notifyDataSetChanged();
158c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        }
159c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    };
160c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal
161cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook    public interface Listener {
162cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook        void onAnimationEnd(AnimatedAdapter adapter);
163cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook    }
164cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook
1656681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    private View mFooter;
1666681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    private boolean mShowFooter;
167eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    private List<View> mHeaders = Lists.newArrayList();
1684584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    private Folder mFolder;
16907118a01f7183645957010779222b84930f75b4eMindy Pereira    private final SwipeableListView mListView;
1707c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private boolean mSwipeEnabled;
1716a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private final HashMap<Long, LeaveBehindItem> mLeaveBehindItems = Maps.newHashMap();
17217646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    /** True if importance markers are enabled, false otherwise. */
17317646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    private boolean mImportanceMarkersEnabled;
17417646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    /**
17517646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     * True if chevrons (personal level indicators) should be shown:
17617646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     * an arrow ( › ) by messages sent to my address (not a mailing list),
17717646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     * and a double arrow ( » ) by messages sent only to me.
17817646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     */
17917646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    private boolean mShowChevronsEnabled;
1802102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei    private final ControllableActivity mActivity;
1817c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private final AccountObserver mAccountListener = new AccountObserver() {
1827c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        @Override
1837c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        public void onChanged(Account newAccount) {
184d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            if (setAccount(newAccount)) {
185d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy                notifyDataSetChanged();
186d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            }
1877c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        }
1887c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    };
1897c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
19037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    /**
19137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * A list of all views that are not conversations. These include temporary views from
1921c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy     * {@link #mFleetingViews}.
19337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     */
19437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    private final SparseArray<ConversationSpecialItemView> mSpecialViews;
1957c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
1961aba32575a08da6cbad80af8446201d73c59783dMark Wei    private final CoordinatesCache mCoordinatesCache = new CoordinatesCache();
197fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
19837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    /**
19937a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * Temporary views insert at specific positions relative to conversations. These can be
20037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * related to showing new features (on-boarding) or showing information about new mailboxes
20137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * that have been added by the system.
20237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     */
20337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    private final List<ConversationSpecialItemView> mFleetingViews;
20437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
2051801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein    private final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
2061801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein
207d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy    /**
208d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy     * @return <code>true</code> if a relevant part of the account has changed, <code>false</code>
209d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy     *         otherwise
210d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy     */
211d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy    private boolean setAccount(Account newAccount) {
212d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        final boolean accountChanged;
213d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        if (mAccount != null && mAccount.uri.equals(newAccount.uri)
21417646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                && mAccount.settings.importanceMarkersEnabled ==
21517646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                        newAccount.settings.importanceMarkersEnabled
216d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy                && mAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO) ==
217d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy                        newAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO)
2180e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                && mAccount.settings.convListIcon == newAccount.settings.convListIcon) {
219d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            accountChanged = false;
220d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        } else {
221d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            accountChanged = true;
222d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        }
223d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy
2247c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mAccount = newAccount;
22517646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        mImportanceMarkersEnabled = mAccount.settings.importanceMarkersEnabled;
22617646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        mShowChevronsEnabled = mAccount.settings.showChevronsEnabled;
2277c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mSwipeEnabled = mAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO);
228042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
229042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang        Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_SENDER_IMAGES_ENABLED, Boolean
230042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang                .toString(newAccount.settings.convListIcon == ConversationListIcon.SENDER_IMAGE));
2314fe0af81874976a1995191321e35c844b2229811Andy Huang        Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_REPLY_ALL_SETTING,
2324fe0af81874976a1995191321e35c844b2229811Andy Huang                (newAccount.settings.replyBehavior == UIProvider.DefaultReplyBehavior.REPLY)
2334fe0af81874976a1995191321e35c844b2229811Andy Huang                ? "reply"
2344fe0af81874976a1995191321e35c844b2229811Andy Huang                : "reply_all");
235e6c9fb6835247d98898e2af581ad9449ad7f3184Andy Huang        Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_AUTO_ADVANCE,
236e6c9fb6835247d98898e2af581ad9449ad7f3184Andy Huang                UIProvider.AutoAdvance.getAutoAdvanceStr(
237e6c9fb6835247d98898e2af581ad9449ad7f3184Andy Huang                        newAccount.settings.getAutoAdvanceSetting()));
238d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy
239d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        return accountChanged;
2407c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
2417c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
242b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
243a44babdac4e070034f35d984d06c675af8fee81fmindyp    private static final int INCREASE_WAIT_COUNT = 2;
2449879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
245a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    private final BitmapCache mSendersImagesCache;
246a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    private final ContactResolver mContactResolver;
247a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
248a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal    public AnimatedAdapter(Context context, ConversationCursor cursor,
249a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal            ConversationSelectionSet batch, ControllableActivity activity,
2506af70772b2037d3527337f220fc053af73d4c81dScott Kennedy            SwipeableListView listView, final List<ConversationSpecialItemView> specialViews) {
251a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal        super(context, -1, cursor, UIProvider.CONVERSATION_PROJECTION, null, 0);
2529879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        mContext = context;
2539879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        mBatchConversations = batch;
2547c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        setAccount(mAccountListener.initialize(activity.getAccountController()));
255e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        mActivity = activity;
2566681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        mShowFooter = false;
25766bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        mListView = listView;
25837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
2598913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein        mSendersImagesCache = mActivity.getSenderImageCache();
2608913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein
2618913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein        mContactResolver =
2628913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein                mActivity.getContactResolver(mContext.getContentResolver(), mSendersImagesCache);
26379c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
2646a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        mHandler = new Handler();
265a44babdac4e070034f35d984d06c675af8fee81fmindyp        if (sDismissAllShortDelay == -1) {
26637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            final Resources r = context.getResources();
26737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            sDismissAllShortDelay = r.getInteger(R.integer.dismiss_all_leavebehinds_short_delay);
26837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            sDismissAllLongDelay = r.getInteger(R.integer.dismiss_all_leavebehinds_long_delay);
26937a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        }
27037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        if (specialViews != null) {
27137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            mFleetingViews = new ArrayList<ConversationSpecialItemView>(specialViews);
27237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        } else {
27337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            mFleetingViews = new ArrayList<ConversationSpecialItemView>(0);
2747c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
27537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        /** Total number of special views */
2760e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy        final int size = mFleetingViews.size();
27737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        mSpecialViews = new SparseArray<ConversationSpecialItemView>(size);
2787c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
2791c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Set the adapter in teaser views.
28037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView view : mFleetingViews) {
28137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            view.setAdapter(this);
28237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        }
2837c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
2847c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
2857c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
2863b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    public void cancelDismissCounter() {
2874d4531a63cff536d2ee1a2929d0820981df8516amindyp        cancelLeaveBehindFadeInAnimation();
2883b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        mHandler.removeCallbacks(mCountDown);
2893b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    }
2903b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp
2913b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    public void startDismissCounter() {
292a44babdac4e070034f35d984d06c675af8fee81fmindyp        if (mLeaveBehindItems.size() > INCREASE_WAIT_COUNT) {
293a44babdac4e070034f35d984d06c675af8fee81fmindyp            mHandler.postDelayed(mCountDown, sDismissAllLongDelay);
294a44babdac4e070034f35d984d06c675af8fee81fmindyp        } else {
295a44babdac4e070034f35d984d06c675af8fee81fmindyp            mHandler.postDelayed(mCountDown, sDismissAllShortDelay);
296a44babdac4e070034f35d984d06c675af8fee81fmindyp        }
2973b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    }
2983b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp
2997c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    public final void destroy() {
3007c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        // Set a null cursor in the adapter
3017c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        swapCursor(null);
3027c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mAccountListener.unregisterAndDestroy();
3036681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    }
3046681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira
3056681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    @Override
3066681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    public int getCount() {
30737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        // mSpecialViews only contains the views that are currently being displayed
30837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        final int specialViewCount = mSpecialViews.size();
3097c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
310eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        return super.getCount() + specialViewCount +
311eb145d45c17b08ce09131e84b96350925b3db81aJin Cao                (mShowFooter ? 1 : 0) + mHeaders.size();
3129879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
3139879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
314e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu    /**
315e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * Add a conversation to the undo set, but only if its deletion is still cached. If the
316e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * deletion has already been written through and the cursor doesn't have it anymore, we can't
317e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * handle it here, and should instead rely on the cursor refresh to restore the item.
318e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * @param item id for the conversation that is being undeleted.
319e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * @return true if the conversation is still cached and therefore we will handle the undo.
320e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     */
321e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu    private boolean addUndoingItem(final long item) {
322e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu        if (getConversationCursor().getUnderlyingPosition(item) >= 0) {
323e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            mUndoingItems.add(item);
324e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            return true;
325e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu        }
326e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu        return false;
327e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu    }
328e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu
3296c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void setUndo(boolean undo) {
3303b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (undo) {
331e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            boolean itemAdded = false;
3323b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (!mLastDeletingItems.isEmpty()) {
333e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                for (Long item : mLastDeletingItems) {
334e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                    itemAdded |= addUndoingItem(item);
335e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                }
3363b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastDeletingItems.clear();
3373b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
3383b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (mLastLeaveBehind != -1) {
339e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                itemAdded |= addUndoingItem(mLastLeaveBehind);
3403b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastLeaveBehind = -1;
3413b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
342e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            // Start animation, only if we're handling the undo.
343e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            if (itemAdded) {
344e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                notifyDataSetChanged();
345e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                performAndSetNextAction(mRefreshAction);
346e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            }
3473b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank        }
3483b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank    }
3493b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank
350bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    public void setSwipeUndo(boolean undo) {
3513b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (undo) {
3523b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (!mLastDeletingItems.isEmpty()) {
3533b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mSwipeUndoingItems.addAll(mLastDeletingItems);
3543b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastDeletingItems.clear();
3553b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
3563b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (mLastLeaveBehind != -1) {
3573b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mSwipeUndoingItems.add(mLastLeaveBehind);
3583b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastLeaveBehind = -1;
3593b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
360bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            // Start animation
361bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            notifyDataSetChanged();
362bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            performAndSetNextAction(mRefreshAction);
363bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        }
364bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
365bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
3660abee55d48f4b7c9f2fefa59d88726ee06c2a4b9mindyp    public View createConversationItemView(SwipeableConversationItemView view, Context context,
3678afccad8b03701577bb4b734a0f4fe76f6cab487Scott Kennedy            Conversation conv) {
3680abee55d48f4b7c9f2fefa59d88726ee06c2a4b9mindyp        if (view == null) {
36926a20758413f0f8629ea71a0943304e3ae740165Tony Mantler            view = new SwipeableConversationItemView(context, mAccount.getEmailAddress());
3709879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        }
371a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        view.bind(conv, mActivity, mBatchConversations, mFolder, getCheckboxSetting(),
3720e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this);
3730abee55d48f4b7c9f2fefa59d88726ee06c2a4b9mindyp        return view;
3749879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
3759879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
376dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    @Override
377dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    public boolean hasStableIds() {
378dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank        return true;
379dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    }
380dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank
381dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    @Override
382dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    public int getViewTypeCount() {
383464939499eec4c4d6fd728e75598232b5948a184Mindy Pereira        // TYPE_VIEW_CONVERSATION, TYPE_VIEW_DELETING, TYPE_VIEW_UNDOING, and
3846c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        // TYPE_VIEW_FOOTER, TYPE_VIEW_LEAVEBEHIND.
3856c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        return 5;
386dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    }
387dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank
388dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    @Override
389dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    public int getItemViewType(int position) {
390b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        // Try to recycle views.
391eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if (mHeaders.size() > position) {
392eb145d45c17b08ce09131e84b96350925b3db81aJin Cao            return TYPE_VIEW_HEADER;
393eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        } else if (mShowFooter && position == getCount() - 1) {
394e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            return TYPE_VIEW_FOOTER;
395d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp        } else if (hasLeaveBehinds() || isAnimating()) {
396d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // Setting as type -1 means the recycler won't take this view and
397d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // return it in get view. This is a bit of a "hammer" in that it
398d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // won't let even safe views be recycled here,
399d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // but its safer and cheaper than trying to determine individual
400d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // types. In a future release, use position/id map to try to make
401d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // this cleaner / faster to determine if the view is animating.
402d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            return TYPE_VIEW_DONT_RECYCLE;
4030e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        } else if (mSpecialViews.get(getSpecialViewsPos(position)) != null) {
4047c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            // Don't recycle the special views
4057c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            return TYPE_VIEW_DONT_RECYCLE;
406e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        }
407b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        return TYPE_VIEW_CONVERSATION;
408dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    }
409dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank
41054452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal    /**
411067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * Deletes the selected conversations from the conversation list view with a
412067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * translation and then a shrink. These conversations <b>must</b> have their
413067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * {@link Conversation#position} set to the position of these conversations
414067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * among the list. This will only remove the element from the list. The job
415067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * of deleting the actual element is left to the the listener. This listener
416067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * will be called when the animations are complete and is required to delete
417067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * the conversation.
418067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * @param conversations
419067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * @param listener
420067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     */
4219365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public void swipeDelete(Collection<Conversation> conversations,
4229365a826b46b0e274df88e92534f7d871eef2aa2mindyp            ListItemsRemovedListener listener) {
423067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        delete(conversations, listener, mSwipeDeletingItems);
424067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
425067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
426067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
427067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    /**
428067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * Deletes the selected conversations from the conversation list view by
429067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * shrinking them away. These conversations <b>must</b> have their
430067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * {@link Conversation#position} set to the position of these conversations
431067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * among the list. This will only remove the element from the list. The job
432067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * of deleting the actual element is left to the the listener. This listener
433067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * will be called when the animations are complete and is required to delete
434067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * the conversation.
43554452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal     * @param conversations
43654452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal     * @param listener
43754452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal     */
4389365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public void delete(Collection<Conversation> conversations, ListItemsRemovedListener listener) {
439067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        delete(conversations, listener, mDeletingItems);
440067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
441067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
4429365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private void delete(Collection<Conversation> conversations, ListItemsRemovedListener listener,
443e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            HashSet<Long> list) {
4443b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank        // Clear out any remaining items and add the new ones
4453b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank        mLastDeletingItems.clear();
446e4abda754bad698f81f55c139a530478dae5476dPaul Westbrook        // Since we are deleting new items, clear any remaining undo items
447e4abda754bad698f81f55c139a530478dae5476dPaul Westbrook        mUndoingItems.clear();
44866bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank
449b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        final int startPosition = mListView.getFirstVisiblePosition();
450b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        final int endPosition = mListView.getLastVisiblePosition();
45166bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank
45266bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        // Only animate visible items
453e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        for (Conversation c: conversations) {
454e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            if (c.position >= startPosition && c.position <= endPosition) {
455e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                mLastDeletingItems.add(c.id);
456e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                list.add(c.id);
45766bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank            }
45866bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        }
45966bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank
460067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (list.isEmpty()) {
46166bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank            // If we have no deleted items on screen, skip the animation
4629365a826b46b0e274df88e92534f7d871eef2aa2mindyp            listener.onListItemsRemoved();
463f01b02b09acca214892cbf865a89dbdf19f77238Scott Kennedy            // If we have an action queued up, perform it
464f01b02b09acca214892cbf865a89dbdf19f77238Scott Kennedy            performAndSetNextAction(null);
46566bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        } else {
4669365a826b46b0e274df88e92534f7d871eef2aa2mindyp            performAndSetNextAction(listener);
46766bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        }
4689879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        notifyDataSetChanged();
4699879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
4709879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
4719879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    @Override
4729879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    public View getView(int position, View convertView, ViewGroup parent) {
473eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if (mHeaders.size() > position) {
474eb145d45c17b08ce09131e84b96350925b3db81aJin Cao            return mHeaders.get(position);
475eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        } else if (mShowFooter && position == getCount() - 1) {
4766681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira            return mFooter;
4776681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        }
4787c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
4797c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        // Check if this is a special view
4800e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        final ConversationSpecialItemView specialView = mSpecialViews.get(
4810e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao                getSpecialViewsPos(position));
4827c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        if (specialView != null) {
483f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy            specialView.onGetView();
484b45d1418887d8595c230788e20516bbe10c2f3eaScott Kennedy            return (View) specialView;
4857c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
4867c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
487f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceBeginSection("AA.getView");
488f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang
48937a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        final ConversationCursor cursor = (ConversationCursor) getItem(position);
4901bca265b7a8a3f9ea08e0ae51eeb145f0883a266Andy Huang        final Conversation conv = cursor.getConversation();
491983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook
492983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook        // Notify the provider of this change in the position of Conversation cursor
493983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook        cursor.notifyUIPositionChange();
494983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook
495e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        if (isPositionUndoing(conv.id)) {
4966176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getUndoingView(position - getPositionOffset(position), conv, parent,
4976176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy                    false /* don't show swipe background */);
498e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        } if (isPositionUndoingSwipe(conv.id)) {
4996176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getUndoingView(position - getPositionOffset(position), conv, parent,
5006176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy                    true /* show swipe background */);
501e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        } else if (isPositionDeleting(conv.id)) {
5026176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getDeletingView(position - getPositionOffset(position), conv, parent, false);
503e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        } else if (isPositionSwipeDeleting(conv.id)) {
5046176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getDeletingView(position - getPositionOffset(position), conv, parent, true);
5059879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        }
50662d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        if (hasFadeLeaveBehinds()) {
50762d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            if(isPositionFadeLeaveBehind(conv)) {
50862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang                LeaveBehindItem fade  = getFadeLeaveBehindItem(position, conv);
5093b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy                fade.startShrinkAnimation(mAnimatorListener);
51070f0111a4337367b0cd5fcc1302b730fb332aeebMark Wei                Utils.traceEndSection();
51162d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang                return fade;
51262d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            }
51362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        }
5146c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        if (hasLeaveBehinds()) {
515e358ed5c4ed1b172f5eae98f97919a8e471c98dcmindyp            if (isPositionLeaveBehind(conv)) {
516370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                final LeaveBehindItem fadeIn = getLeaveBehindItem(conv);
5174d4531a63cff536d2ee1a2929d0820981df8516amindyp                if (conv.id == mLastLeaveBehind) {
518a44babdac4e070034f35d984d06c675af8fee81fmindyp                    // If it looks like the person is doing a lot of rapid
519a44babdac4e070034f35d984d06c675af8fee81fmindyp                    // swipes, wait patiently before animating
520a44babdac4e070034f35d984d06c675af8fee81fmindyp                    if (mLeaveBehindItems.size() > INCREASE_WAIT_COUNT) {
521a44babdac4e070034f35d984d06c675af8fee81fmindyp                        if (fadeIn.isAnimating()) {
522a44babdac4e070034f35d984d06c675af8fee81fmindyp                            fadeIn.increaseFadeInDelay(sDismissAllLongDelay);
523a44babdac4e070034f35d984d06c675af8fee81fmindyp                        } else {
524a44babdac4e070034f35d984d06c675af8fee81fmindyp                            fadeIn.startFadeInTextAnimation(sDismissAllLongDelay);
525a44babdac4e070034f35d984d06c675af8fee81fmindyp                        }
526a44babdac4e070034f35d984d06c675af8fee81fmindyp                    } else {
527a44babdac4e070034f35d984d06c675af8fee81fmindyp                        // Otherwise, assume they are just doing 1 and wait less time
528a44babdac4e070034f35d984d06c675af8fee81fmindyp                        fadeIn.startFadeInTextAnimation(sDismissAllShortDelay /* delay start */);
529a44babdac4e070034f35d984d06c675af8fee81fmindyp                    }
5304d4531a63cff536d2ee1a2929d0820981df8516amindyp                }
53170f0111a4337367b0cd5fcc1302b730fb332aeebMark Wei                Utils.traceEndSection();
53284f9b5c60dc023570202859ba1d30cf9cb5e6e7aMindy Pereira                return fadeIn;
5336c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            }
5346c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        }
5357c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
536067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (convertView != null && !(convertView instanceof SwipeableConversationItemView)) {
537067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            LogUtils.w(LOG_TAG, "Incorrect convert view received; nulling it out");
538eb88ececd0a53c4e956240b7b619da6410e2d356mindyp            convertView = newView(mContext, cursor, parent);
539c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        } else if (convertView != null) {
540c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira            ((SwipeableConversationItemView) convertView).reset();
541afd6f9246ddf645a45c8e91df5c5c2587cbf6a0dMindy Pereira        }
542f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        final View v = createConversationItemView((SwipeableConversationItemView) convertView,
5438afccad8b03701577bb4b734a0f4fe76f6cab487Scott Kennedy                mContext, conv);
544f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceEndSection();
545f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        return v;
5469879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
5479879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
5486c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private boolean hasLeaveBehinds() {
5496a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        return !mLeaveBehindItems.isEmpty();
5506c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
5516c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
55262d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    private boolean hasFadeLeaveBehinds() {
5538f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira        return !mFadeLeaveBehindItems.isEmpty();
55462d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
55562d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
55679e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    public LeaveBehindItem setupLeaveBehind(Conversation target, ToastBarOperation undoOp,
557370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            int deletedRow, int viewHeight) {
5584d4531a63cff536d2ee1a2929d0820981df8516amindyp        cancelLeaveBehindFadeInAnimation();
5596a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        mLastLeaveBehind = target.id;
56062d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        fadeOutLeaveBehindItems();
561370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
562370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        final LeaveBehindItem leaveBehind = (LeaveBehindItem) LayoutInflater.from(mContext)
563370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                .inflate(R.layout.swipe_leavebehind, mListView, false);
564370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        leaveBehind.bind(deletedRow, mAccount, this, undoOp, target, mFolder, viewHeight);
5656a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        mLeaveBehindItems.put(target.id, leaveBehind);
566e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        mLastDeletingItems.add(target.id);
56779e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        return leaveBehind;
5686c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
5696c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
5706a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    public void fadeOutSpecificLeaveBehindItem(long id) {
5716a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (mLastLeaveBehind == id) {
5726a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLastLeaveBehind = -1;
5736a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
5746a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        startFadeOutLeaveBehindItemsAnimations();
5756a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    }
5766a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp
5776a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    // This should kick off a timer such that there is a minimum time each item
5786a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    // shows up before being dismissed. That way if the user is swiping away
5796a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    // items in rapid succession, their finger position is maintained.
58062d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    public void fadeOutLeaveBehindItems() {
5816a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (mCountDown == null) {
5826a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mCountDown = new Runnable() {
5836a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                @Override
5846a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                public void run() {
5856a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    startFadeOutLeaveBehindItemsAnimations();
5866a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
5876a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            };
5886a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        } else {
5896a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mHandler.removeCallbacks(mCountDown);
5906a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
5916a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        // Clear all the text since these are no longer clickable
5926a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        Iterator<Entry<Long, LeaveBehindItem>> i = mLeaveBehindItems.entrySet().iterator();
5936a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        LeaveBehindItem item;
5946a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        while (i.hasNext()) {
5956a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            item = i.next().getValue();
5966a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            Conversation conv = item.getData();
5976a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            if (mLastLeaveBehind == -1 || conv.id != mLastLeaveBehind) {
598a44babdac4e070034f35d984d06c675af8fee81fmindyp                item.cancelFadeInTextAnimation();
5996a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                item.makeInert();
6006a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            }
6016a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
6023b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        startDismissCounter();
6036a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    }
6046a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp
6056a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    protected void startFadeOutLeaveBehindItemsAnimations() {
60662d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        final int startPosition = mListView.getFirstVisiblePosition();
60762d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        final int endPosition = mListView.getLastVisiblePosition();
60862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
60979e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        if (hasLeaveBehinds()) {
61079e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira            // If the item is visible, fade it out. Otherwise, just remove
61179e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira            // it.
6126a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            Iterator<Entry<Long, LeaveBehindItem>> i = mLeaveBehindItems.entrySet().iterator();
6136a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            LeaveBehindItem item;
6146a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            while (i.hasNext()) {
6156a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                item = i.next().getValue();
6166a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                Conversation conv = item.getData();
6176a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                if (mLastLeaveBehind == -1 || conv.id != mLastLeaveBehind) {
6186a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    if (conv.position >= startPosition && conv.position <= endPosition) {
6196a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                        mFadeLeaveBehindItems.put(conv.id, item);
6206a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    } else {
6216a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                        item.commit();
6226a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    }
6236a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    i.remove();
6246a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
62562d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            }
6264d4531a63cff536d2ee1a2929d0820981df8516amindyp            cancelLeaveBehindFadeInAnimation();
62762d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        }
62862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        if (!mLastDeletingItems.isEmpty()) {
62962d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            mLastDeletingItems.clear();
63062d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        }
63162d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        notifyDataSetChanged();
63262d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
63362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
6344d4531a63cff536d2ee1a2929d0820981df8516amindyp    private void cancelLeaveBehindFadeInAnimation() {
6354d4531a63cff536d2ee1a2929d0820981df8516amindyp        LeaveBehindItem leaveBehind = getLastLeaveBehindItem();
6364d4531a63cff536d2ee1a2929d0820981df8516amindyp        if (leaveBehind != null) {
6374d4531a63cff536d2ee1a2929d0820981df8516amindyp            leaveBehind.cancelFadeInTextAnimation();
6384d4531a63cff536d2ee1a2929d0820981df8516amindyp        }
6394d4531a63cff536d2ee1a2929d0820981df8516amindyp    }
6404d4531a63cff536d2ee1a2929d0820981df8516amindyp
6411aba32575a08da6cbad80af8446201d73c59783dMark Wei    public CoordinatesCache getCoordinatesCache() {
642fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        return mCoordinatesCache;
643fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
644fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
6451801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein    public BidiFormatter getBidiFormatter() {
6461801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein        return mBidiFormatter;
6471801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein    }
6481801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein
6495254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    public SwipeableListView getListView() {
6505254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        return mListView;
6515254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    }
6525254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp
653c6adce3cf6887c4c6dd5005724565702751843d0mindyp    public void commitLeaveBehindItems(boolean animate) {
654dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira        // Remove any previously existing leave behinds.
6555254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        boolean changed = false;
65679e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        if (hasLeaveBehinds()) {
6576a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            for (LeaveBehindItem item : mLeaveBehindItems.values()) {
6586a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                if (animate) {
659dcb26aea2b27b585c35c422c870e849b8c4e41d6mindyp                    mFadeLeaveBehindItems.put(item.getConversationId(), item);
6606a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                } else {
6616a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    item.commit();
6626a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
663c6adce3cf6887c4c6dd5005724565702751843d0mindyp            }
6645254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            changed = true;
6656a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLastLeaveBehind = -1;
6666a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLeaveBehindItems.clear();
667dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira        }
668aa55bc9cb210a46a950874f368baa07f041a4302mindyp        if (hasFadeLeaveBehinds() && !animate) {
669aa55bc9cb210a46a950874f368baa07f041a4302mindyp            // Find any fading leave behind items and commit them all, too.
670aa55bc9cb210a46a950874f368baa07f041a4302mindyp            for (LeaveBehindItem item : mFadeLeaveBehindItems.values()) {
671aa55bc9cb210a46a950874f368baa07f041a4302mindyp                item.commit();
672aa55bc9cb210a46a950874f368baa07f041a4302mindyp            }
673aa55bc9cb210a46a950874f368baa07f041a4302mindyp            mFadeLeaveBehindItems.clear();
674aa55bc9cb210a46a950874f368baa07f041a4302mindyp            changed = true;
675aa55bc9cb210a46a950874f368baa07f041a4302mindyp        }
67606b623852cdacc749d67d9c1b7c478dd52780297Mindy Pereira        if (!mLastDeletingItems.isEmpty()) {
67706b623852cdacc749d67d9c1b7c478dd52780297Mindy Pereira            mLastDeletingItems.clear();
6785254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            changed = true;
6795254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        }
680fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy
681fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy        for (final ConversationSpecialItemView view : mFleetingViews) {
682fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy            if (view.commitLeaveBehindItem()) {
683fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy                changed = true;
684fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy            }
685fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy        }
686fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy
6875254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        if (changed) {
6885254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            notifyDataSetChanged();
68906b623852cdacc749d67d9c1b7c478dd52780297Mindy Pereira        }
690dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira    }
691dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira
69279e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    private LeaveBehindItem getLeaveBehindItem(Conversation target) {
6936a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        return mLeaveBehindItems.get(target.id);
6946c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
6956c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
69662d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    private LeaveBehindItem getFadeLeaveBehindItem(int position, Conversation target) {
6978f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira        return mFadeLeaveBehindItems.get(target.id);
69862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
69962d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
700d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    @Override
701d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    public long getItemId(int position) {
702eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if ((mHeaders.size() > position) || (mShowFooter && position == getCount() - 1)) {
703d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira            return -1;
704d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira        }
705f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy
7060e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        final ConversationSpecialItemView specialView = mSpecialViews.get(
7070e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao                getSpecialViewsPos(position));
708f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy        if (specialView != null) {
709f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy            // TODO(skennedy) We probably want something better than this
710f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy            return specialView.hashCode();
711f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy        }
712f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy
71355e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang        final int cursorPos = position - getPositionOffset(position);
714348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // advance the cursor to the right position and read the cached conversation, if present
715348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        //
716348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // (no need to have CursorAdapter check mDataValid because in our incarnation without
717348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // FLAG_REGISTER_CONTENT_OBSERVER, mDataValid is effectively identical to mCursor being
718348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // non-null)
719348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        final ConversationCursor cursor = getConversationCursor();
720348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        if (cursor != null && cursor.moveToPosition(cursorPos)) {
7216cf45c601317d4b65ffb1896760fa1cb8a2b807cAndy Huang            final Conversation conv = cursor.getCachedConversation();
72255e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang            if (conv != null) {
72355e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang                return conv.id;
72455e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang            }
72555e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang        }
72655e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang        return super.getItemId(cursorPos);
727d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    }
728d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira
7296176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy    /**
7306176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     * @param position The position in the cursor
7316176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     */
732e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private View getDeletingView(int position, Conversation conversation, ViewGroup parent,
733e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            boolean swipe) {
734c7d201d79974fd0f1e935880d51fe516f78207a2Vikram Aggarwal        conversation.position = position;
735067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        SwipeableConversationItemView deletingView = mAnimatingViews.get(conversation.id);
736067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (deletingView == null) {
737067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // The undo animation consists of fading in the conversation that
738067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // had been destroyed.
739067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            deletingView = newConversationItemView(position, parent, conversation);
740370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            deletingView.startDeleteAnimation(mAnimatorListener, swipe);
741067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
742067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return deletingView;
743a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira    }
744a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira
7456176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy    /**
7466176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     * @param position The position in the cursor
7476176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     */
748e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private View getUndoingView(int position, Conversation conv, ViewGroup parent, boolean swipe) {
749e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        conv.position = position;
750e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        SwipeableConversationItemView undoView = mAnimatingViews.get(conv.id);
751067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (undoView == null) {
752067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // The undo animation consists of fading in the conversation that
753067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // had been destroyed.
754e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            undoView = newConversationItemView(position, parent, conv);
755370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            undoView.startUndoAnimation(mAnimatorListener, swipe);
756067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
757067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return undoView;
758067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
759067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
7605ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    @Override
7615ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    public View newView(Context context, Cursor cursor, ViewGroup parent) {
76226a20758413f0f8629ea71a0943304e3ae740165Tony Mantler        return new SwipeableConversationItemView(context, mAccount.getEmailAddress());
7635ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    }
7645ceab3bd6892b85b0252b987b67b70ec5055587fmindyp
7655ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    @Override
7665ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    public void bindView(View view, Context context, Cursor cursor) {
76707fe8df87bde8732398434e55cce366a8528c181Andy Huang        // no-op. we only get here from newConversationItemView(), which will immediately bind
76807fe8df87bde8732398434e55cce366a8528c181Andy Huang        // on its own.
7695ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    }
7705ceab3bd6892b85b0252b987b67b70ec5055587fmindyp
771067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private SwipeableConversationItemView newConversationItemView(int position, ViewGroup parent,
772067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            Conversation conversation) {
773067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        SwipeableConversationItemView view = (SwipeableConversationItemView) super.getView(
774067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                position, null, parent);
775dc0617f3478b21dd3324ab10b8c433517ae95460mindyp        view.reset();
776a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        view.bind(conversation, mActivity, mBatchConversations, mFolder, getCheckboxSetting(),
7770e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this);
778067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        mAnimatingViews.put(conversation.id, view);
779067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return view;
7809879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
7819879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
782642731419abb9037a729114d32d6ddd15af0a406Alice Yang    private int getCheckboxSetting() {
783642731419abb9037a729114d32d6ddd15af0a406Alice Yang        return mAccount != null ? mAccount.settings.convListIcon :
784642731419abb9037a729114d32d6ddd15af0a406Alice Yang            ConversationListIcon.DEFAULT;
785642731419abb9037a729114d32d6ddd15af0a406Alice Yang    }
786642731419abb9037a729114d32d6ddd15af0a406Alice Yang
787d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    @Override
788d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    public Object getItem(int position) {
7890e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        final ConversationSpecialItemView specialView = mSpecialViews.get(
7900e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao                getSpecialViewsPos(position));
791eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if (mHeaders.size() > position) {
792eb145d45c17b08ce09131e84b96350925b3db81aJin Cao            return mHeaders.get(position);
793eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        } else if (mShowFooter && position == getCount() - 1) {
794d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira            return mFooter;
7950e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        } else if (specialView != null) {
7960e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao            return specialView;
797d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira        }
7987c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        return super.getItem(position - getPositionOffset(position));
799d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    }
800d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira
801e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionDeleting(long id) {
802e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mDeletingItems.contains(id);
803a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira    }
804a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira
805e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionSwipeDeleting(long id) {
806e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mSwipeDeletingItems.contains(id);
807067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
808067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
809e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionUndoing(long id) {
810e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mUndoingItems.contains(id);
8119879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
8129879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
813e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionUndoingSwipe(long id) {
814e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mSwipeUndoingItems.contains(id);
815bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
816bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
8176c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private boolean isPositionLeaveBehind(Conversation conv) {
81879e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        return hasLeaveBehinds()
8196a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                && mLeaveBehindItems.containsKey(conv.id)
82079e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira                && conv.isMostlyDead();
8216c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
8226c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
82362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    private boolean isPositionFadeLeaveBehind(Conversation conv) {
82479e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        return hasFadeLeaveBehinds()
8258f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira                && mFadeLeaveBehindItems.containsKey(conv.id)
82679e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira                && conv.isMostlyDead();
82762d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
82862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
829c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    /**
830c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * Performs the pending destruction, if any and assigns the next pending action.
831c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * @param next The next action that is to be performed, possibly null (if no next action is
832c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * needed).
833c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     */
83437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    private void performAndSetNextAction(ListItemsRemovedListener next) {
835c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        if (mPendingDestruction != null) {
8369365a826b46b0e274df88e92534f7d871eef2aa2mindyp            mPendingDestruction.onListItemsRemoved();
837c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        }
838c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        mPendingDestruction = next;
839c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    }
840c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal
841e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private void updateAnimatingConversationItems(Object obj, HashSet<Long> items) {
842067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (!items.isEmpty()) {
843067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            if (obj instanceof ConversationItemView) {
844067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                final ConversationItemView target = (ConversationItemView) obj;
845e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                final long id = target.getConversation().id;
846e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                items.remove(id);
847e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                mAnimatingViews.remove(id);
848067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                if (items.isEmpty()) {
849bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira                    performAndSetNextAction(null);
850067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    notifyDataSetChanged();
851bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira                }
852866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            }
8539879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        }
854bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
855bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
8569879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    @Override
857866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public boolean areAllItemsEnabled() {
85837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        // The animating items and some special views are not enabled.
859866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return false;
860866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
861866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
862866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    @Override
863b90db28aac1311f0ed32a786594e17c007550853Scott Kennedy    public boolean isEnabled(final int position) {
86437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        final ConversationSpecialItemView view = mSpecialViews.get(position);
86537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        if (view != null) {
86637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            final boolean enabled = view.acceptsUserTaps();
86737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            LogUtils.d(LOG_TAG, "AA.isEnabled(%d) = %b", position, enabled);
86837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            return enabled;
869b90db28aac1311f0ed32a786594e17c007550853Scott Kennedy        }
870a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira        return !isPositionDeleting(position) && !isPositionUndoing(position);
871866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
872866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
873573b9e698852c6cf2cbf0f93bc01b7abb8b64ce1Paul Westbrook    public void setFooterVisibility(boolean show) {
874573b9e698852c6cf2cbf0f93bc01b7abb8b64ce1Paul Westbrook        if (mShowFooter != show) {
875573b9e698852c6cf2cbf0f93bc01b7abb8b64ce1Paul Westbrook            mShowFooter = show;
8766681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira            notifyDataSetChanged();
8776681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        }
8786681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    }
8796681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira
8806681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    public void addFooter(View footerView) {
8816681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        mFooter = footerView;
8826681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    }
8834584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira
884eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    public void addHeader(View headerView) {
885eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        mHeaders.add(headerView);
886eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    }
887eb145d45c17b08ce09131e84b96350925b3db81aJin Cao
8884584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    public void setFolder(Folder folder) {
8894584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira        mFolder = folder;
8904584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    }
8916c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
89279e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    public void clearLeaveBehind(long itemId) {
8936a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (hasLeaveBehinds() && mLeaveBehindItems.containsKey(itemId)) {
8946a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLeaveBehindItems.remove(itemId);
8958f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira        } else if (hasFadeLeaveBehinds()) {
8968f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira            mFadeLeaveBehindItems.remove(itemId);
89779e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        } else {
89879e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira            LogUtils.d(LOG_TAG, "Trying to clear a non-existant leave behind");
89979e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        }
9006a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (mLastLeaveBehind == itemId) {
9016a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLastLeaveBehind = -1;
9026a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
9036c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
9047d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal
905d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    public void onSaveInstanceState(Bundle outState) {
906e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        long[] lastDeleting = new long[mLastDeletingItems.size()];
90779e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        for (int i = 0; i < lastDeleting.length; i++) {
908d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira            lastDeleting[i] = mLastDeletingItems.get(i);
909d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        }
910e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        outState.putLongArray(LAST_DELETING_ITEMS, lastDeleting);
91179e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        if (hasLeaveBehinds()) {
9126a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            if (mLastLeaveBehind != -1) {
9136a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                outState.putParcelable(LEAVE_BEHIND_ITEM_DATA,
9146a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                        mLeaveBehindItems.get(mLastLeaveBehind).getLeaveBehindData());
9156a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                outState.putLong(LEAVE_BEHIND_ITEM_ID, mLastLeaveBehind);
9166a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            }
9176a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            for (LeaveBehindItem item : mLeaveBehindItems.values()) {
9186a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                if (mLastLeaveBehind == -1 || item.getData().id != mLastLeaveBehind) {
9196a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    item.commit();
9206a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
9216a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            }
92279e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        }
923d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    }
924d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira
925d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    public void onRestoreInstanceState(Bundle outState) {
926b8ef4ac43f3570245ec476e2ee9f8a9d1d3ff36cPaul Westbrook        if (outState.containsKey(LAST_DELETING_ITEMS)) {
927e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            final long[] lastDeleting = outState.getLongArray(LAST_DELETING_ITEMS);
92837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            for (final long aLastDeleting : lastDeleting) {
92937a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal                mLastDeletingItems.add(aLastDeleting);
930b8ef4ac43f3570245ec476e2ee9f8a9d1d3ff36cPaul Westbrook            }
931d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        }
9326a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (outState.containsKey(LEAVE_BEHIND_ITEM_DATA)) {
9336a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            LeaveBehindData left =
9346a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    (LeaveBehindData) outState.getParcelable(LEAVE_BEHIND_ITEM_DATA);
9356a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLeaveBehindItems.put(outState.getLong(LEAVE_BEHIND_ITEM_ID),
936370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    setupLeaveBehind(left.data, left.op, left.data.position, left.height));
93779e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        }
938d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    }
93969e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira
94069e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira    /**
94169e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira     * Return if the adapter is in the process of animating anything.
94269e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira     */
94369e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira    public boolean isAnimating() {
94469e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira        return !mUndoingItems.isEmpty()
94569e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira                || !mSwipeUndoingItems.isEmpty()
9461e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira                || hasFadeLeaveBehinds()
94769e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira                || !mDeletingItems.isEmpty()
94869e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira                || !mSwipeDeletingItems.isEmpty();
94969e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira    }
950215d2a465dd17139d4c8cce426ae8c8ff556746emindyp
951f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang    /**
952f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     * Forcibly clear any internal state that would cause {@link #isAnimating()} to return true.
953f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     * Call this in times of desperation, when you really, really want to trash state and just
954f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     * start over.
955f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     */
956f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang    public void clearAnimationState() {
957f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        if (!isAnimating()) {
958f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang            return;
959f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        }
960f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang
961f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mUndoingItems.clear();
962f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mSwipeUndoingItems.clear();
963f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mFadeLeaveBehindItems.clear();
964f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mDeletingItems.clear();
965f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mSwipeDeletingItems.clear();
966f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mAnimatingViews.clear();
967f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        LogUtils.w(LOG_TAG, "AA.clearAnimationState forcibly cleared state, this=%s", this);
968f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang    }
969f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang
970c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang    @Override
971c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang    public String toString() {
972c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        final StringBuilder sb = new StringBuilder("{");
973c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(super.toString());
974c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mUndoingItems=");
975c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mUndoingItems);
976c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mSwipeUndoingItems=");
977c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mSwipeUndoingItems);
978c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mDeletingItems=");
979c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mDeletingItems);
980c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mSwipeDeletingItems=");
981c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mSwipeDeletingItems);
982c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mLeaveBehindItems=");
983c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mLeaveBehindItems);
984c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mFadeLeaveBehindItems=");
985c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mFadeLeaveBehindItems);
986c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mLastDeletingItems=");
987c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mLastDeletingItems);
988f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(" mAnimatingViews=");
989f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(mAnimatingViews);
990f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(" mPendingDestruction=");
991f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(mPendingDestruction);
992c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append("}");
993c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        return sb.toString();
994c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang    }
995c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang
996215d2a465dd17139d4c8cce426ae8c8ff556746emindyp    /**
997215d2a465dd17139d4c8cce426ae8c8ff556746emindyp     * Get the ConversationCursor associated with this adapter.
998215d2a465dd17139d4c8cce426ae8c8ff556746emindyp     */
999215d2a465dd17139d4c8cce426ae8c8ff556746emindyp    public ConversationCursor getConversationCursor() {
1000215d2a465dd17139d4c8cce426ae8c8ff556746emindyp        return (ConversationCursor) getCursor();
1001215d2a465dd17139d4c8cce426ae8c8ff556746emindyp    }
10027af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp
10034d4531a63cff536d2ee1a2929d0820981df8516amindyp    /**
10044d4531a63cff536d2ee1a2929d0820981df8516amindyp     * Get the currently visible leave behind item.
10054d4531a63cff536d2ee1a2929d0820981df8516amindyp     */
10067af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    public LeaveBehindItem getLastLeaveBehindItem() {
10077af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        if (mLastLeaveBehind != -1) {
10087af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp            return mLeaveBehindItems.get(mLastLeaveBehind);
10097af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        }
10107af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        return null;
10117af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    }
10124d4531a63cff536d2ee1a2929d0820981df8516amindyp
10134d4531a63cff536d2ee1a2929d0820981df8516amindyp    /**
10144d4531a63cff536d2ee1a2929d0820981df8516amindyp     * Cancel fading out the text displayed in the leave behind item currently
10154d4531a63cff536d2ee1a2929d0820981df8516amindyp     * shown.
10164d4531a63cff536d2ee1a2929d0820981df8516amindyp     */
10174d4531a63cff536d2ee1a2929d0820981df8516amindyp    public void cancelFadeOutLastLeaveBehindItemText() {
10184d4531a63cff536d2ee1a2929d0820981df8516amindyp        LeaveBehindItem item = getLastLeaveBehindItem();
10194d4531a63cff536d2ee1a2929d0820981df8516amindyp        if (item != null) {
10204d4531a63cff536d2ee1a2929d0820981df8516amindyp            item.cancelFadeOutText();
10214d4531a63cff536d2ee1a2929d0820981df8516amindyp        }
10224d4531a63cff536d2ee1a2929d0820981df8516amindyp    }
10237c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
102437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    /**
10251c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy     * Updates special (non-conversation view) when {@link #mFleetingViews} changed
102637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     */
10277c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    private void updateSpecialViews() {
10281c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // We recreate all the special views using mFleetingViews.
102937a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        mSpecialViews.clear();
103037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
1031bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao        // If the conversation cursor hasn't finished loading, hide all special views
1032bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao        if (!ConversationCursor.isCursorReadyToShow(getConversationCursor())) {
1033bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao            return;
1034bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao        }
1035bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao
10361c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Fleeting (temporary) views specify a position, which is 0-indexed and
10371c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // has to be adjusted for the number of fleeting views above it.
103837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView specialView : mFleetingViews) {
10390e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy            specialView.onUpdate(mFolder, getConversationCursor());
10407c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10417c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            if (specialView.getShouldDisplayInList()) {
10420e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy                // If the special view asks for position 0, it wants to be at the top.
10430e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy                int position = (specialView.getPosition());
10442102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei
10452102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                // insert the special view into the position, but if there is
10462102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                // already an item occupying that position, move that item back
10472102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                // one position, and repeat
10482102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                ConversationSpecialItemView insert = specialView;
10492102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                while (insert != null) {
105037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal                    final ConversationSpecialItemView kickedOut = mSpecialViews.get(position);
105137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal                    mSpecialViews.put(position, insert);
10522102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                    insert = kickedOut;
10532102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                    position++;
10542102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                }
10557c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            }
10567c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
10577c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
10587c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
1059e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy    /**
1060e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     * Gets the position of the specified {@link ConversationSpecialItemView}, as determined by
1061e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     * the adapter.
1062e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     *
1063e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     * @return The position in the list, or a negative value if it could not be found
1064e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     */
1065e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy    public int getSpecialViewPosition(final ConversationSpecialItemView view) {
1066e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy        return mSpecialViews.indexOfValue(view);
1067e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy    }
1068e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy
10697c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
10707c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void notifyDataSetChanged() {
1071d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        // This may be a temporary catch for a problem, or we may leave it here.
1072d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        // b/9527863
1073d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        if (Looper.getMainLooper() != Looper.myLooper()) {
1074d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy            LogUtils.wtf(LOG_TAG, "notifyDataSetChanged() called off the main thread");
1075d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        }
1076d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy
10777c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
10787c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        super.notifyDataSetChanged();
10797c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
10807c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10817c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
10827c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void changeCursor(final Cursor cursor) {
10837c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        super.changeCursor(cursor);
10847c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
10857c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
10867c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10877c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
10887c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void changeCursorAndColumns(final Cursor c, final String[] from, final int[] to) {
10897c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        super.changeCursorAndColumns(c, from, to);
10907c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
10917c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
10927c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10937c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
10947c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public Cursor swapCursor(final Cursor c) {
10957c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        final Cursor oldCursor = super.swapCursor(c);
10967c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
10977c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10987c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        return oldCursor;
10997c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
11007c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
1101a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    public BitmapCache getSendersImagesCache() {
1102a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        return mSendersImagesCache;
110379c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang    }
110479c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
1105a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    public ContactResolver getContactResolver() {
1106a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        return mContactResolver;
110765b6d180f50922a3393795203cae68a5a2f6a33dMark Wei    }
110865b6d180f50922a3393795203cae68a5a2f6a33dMark Wei
11097c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    /**
11107c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy     * Gets the offset for the given position in the underlying cursor, based on any special views
11117c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy     * that may be above it.
11127c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy     */
11130e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    public int getPositionOffset(int position) {
1114eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        int viewsAbove = mHeaders.size();
11157c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11160e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        position -= viewsAbove;
1117da8b096b6a9128dc7c7e7d4fd46d48f9a594268dMark Wei        for (int i = 0, size = mSpecialViews.size(); i < size; i++) {
111818310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal            final int bidPosition = mSpecialViews.keyAt(i);
111918310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal            // If the view bid for a position above the cursor position,
11200e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy            // it is above the conversation.
11210e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy            if (bidPosition <= position) {
112218310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal                viewsAbove++;
11237c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            }
11247c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
11257c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
112618310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal        return viewsAbove;
11277c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
11287c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11290e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    /**
11300e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao     * Gets the correct position for special views given the number of headers we have.
11310e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao     */
11320e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    private int getSpecialViewsPos(final int position) {
11330e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        return position - mHeaders.size();
11340e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    }
11350e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao
11367c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void cleanup() {
11371c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Clean up teaser views.
113837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView view : mFleetingViews) {
11397c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            view.cleanup();
11407c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
11417c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
1142fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang
1143fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang    public void onConversationSelected() {
11441c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Notify teaser views.
114537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView specialView : mFleetingViews) {
1146fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang            specialView.onConversationSelected();
1147fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang        }
1148fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang    }
11492f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein
11502f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein    public void onCabModeEntered() {
1151a2f1922c41eb5a01f1972c49ab80019a72f1aa0fAndrew Sapperstein        for (final ConversationSpecialItemView specialView : mFleetingViews) {
11522f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein            specialView.onCabModeEntered();
11532f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein        }
11542f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein    }
115579c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
1156cc139833bc5829ba70244519e9870de783c41848Scott Kennedy    public void onCabModeExited() {
1157cc139833bc5829ba70244519e9870de783c41848Scott Kennedy        for (final ConversationSpecialItemView specialView : mFleetingViews) {
1158cc139833bc5829ba70244519e9870de783c41848Scott Kennedy            specialView.onCabModeExited();
1159cc139833bc5829ba70244519e9870de783c41848Scott Kennedy        }
1160cc139833bc5829ba70244519e9870de783c41848Scott Kennedy    }
1161cc139833bc5829ba70244519e9870de783c41848Scott Kennedy
116232ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    public void onConversationListVisibilityChanged(final boolean visible) {
116332ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        for (final ConversationSpecialItemView specialView : mFleetingViews) {
116432ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy            specialView.onConversationListVisibilityChanged(visible);
116532ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        }
116632ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    }
116732ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy
1168f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy    public int getViewMode() {
1169f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy        return mActivity.getViewMode().getMode();
1170f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy    }
117159bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy
117259bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy    public boolean isInCabMode() {
117359bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy        // If we have conversation in our selected set, we're in CAB mode
117459bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy        return !mBatchConversations.isEmpty();
117559bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy    }
117632ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy
117732ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    public void saveSpecialItemInstanceState(final Bundle outState) {
117832ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        for (final ConversationSpecialItemView specialView : mFleetingViews) {
117932ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy            specialView.saveInstanceState(outState);
118032ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        }
118132ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    }
11827ed53776a053782ca37303075c144926647ac557Paul Westbrook}
1183