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;
370a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Caoimport android.widget.Space;
389879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
392b806edc62eb8e83c77edc471fda4652281a15c4James Lemieuximport com.android.bitmap.BitmapCache;
406c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereiraimport com.android.mail.R;
41042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huangimport com.android.mail.analytics.Analytics;
42a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Weiimport com.android.mail.bitmap.ContactResolver;
439879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.browse.ConversationCursor;
449879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.browse.ConversationItemView;
451aba32575a08da6cbad80af8446201d73c59783dMark Weiimport com.android.mail.browse.ConversationItemViewCoordinates.CoordinatesCache;
461ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereiraimport com.android.mail.browse.SwipeableConversationItemView;
479879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.providers.Account;
487c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwalimport com.android.mail.providers.AccountObserver;
499879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.providers.Conversation;
504584a0d83e160444f931cb565185a2eea39b1683Mindy Pereiraimport com.android.mail.providers.Folder;
519879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport com.android.mail.providers.UIProvider;
52642731419abb9037a729114d32d6ddd15af0a406Alice Yangimport com.android.mail.providers.UIProvider.ConversationListIcon;
539365a826b46b0e274df88e92534f7d871eef2aa2mindypimport com.android.mail.ui.SwipeableListView.ListItemsRemovedListener;
54b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
552ae81266ced36f2733ceab5a09c17ec939b9a62aVikram Aggarwalimport com.android.mail.utils.LogUtils;
56f82d6e7342e277f123a04fc82cc841b180655c15Andy Huangimport com.android.mail.utils.Utils;
57eb145d45c17b08ce09131e84b96350925b3db81aJin Caoimport com.google.common.collect.Lists;
586a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport com.google.common.collect.Maps;
592596f0011dcb4e86b01fc8a6362b5ac922239571Marc Blank
609879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport java.util.ArrayList;
61fac92d71ad83a34eb200cd9bcb773642e5e58de2Mindy Pereiraimport java.util.Collection;
62067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereiraimport java.util.HashMap;
639879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereiraimport java.util.HashSet;
646a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport java.util.Iterator;
657c8325de829ca029ce4547e4f0fa266124301367Scott Kennedyimport java.util.List;
666a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindypimport java.util.Map.Entry;
679879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
68370f868c834861e7732faaa9bdd07a0fa0105596Andy Huangpublic class AnimatedAdapter extends SimpleCursorAdapter {
69a44babdac4e070034f35d984d06c675af8fee81fmindyp    private static int sDismissAllShortDelay = -1;
70a44babdac4e070034f35d984d06c675af8fee81fmindyp    private static int sDismissAllLongDelay = -1;
7179e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    private static final String LAST_DELETING_ITEMS = "last_deleting_items";
726a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private static final String LEAVE_BEHIND_ITEM_DATA = "leave_behind_item_data";
736a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private static final String LEAVE_BEHIND_ITEM_ID = "leave_behind_item_id";
74b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal    private final static int TYPE_VIEW_CONVERSATION = 0;
759365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private final static int TYPE_VIEW_FOOTER = 1;
76eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    private final static int TYPE_VIEW_HEADER = 2;
77d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp    private final static int TYPE_VIEW_DONT_RECYCLE = -1;
78e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mDeletingItems = new HashSet<Long>();
79e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final ArrayList<Long> mLastDeletingItems = new ArrayList<Long>();
80e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mUndoingItems = new HashSet<Long>();
81e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mSwipeDeletingItems = new HashSet<Long>();
82e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private final HashSet<Long> mSwipeUndoingItems = new HashSet<Long>();
83067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private final HashMap<Long, SwipeableConversationItemView> mAnimatingViews =
84067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            new HashMap<Long, SwipeableConversationItemView>();
851e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira    private final HashMap<Long, LeaveBehindItem> mFadeLeaveBehindItems =
868f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira            new HashMap<Long, LeaveBehindItem>();
8733519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal    /** The current account */
887c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private Account mAccount;
8933519c002b7e4504dbf964a808cf2f7aff32d16cVikram Aggarwal    private final Context mContext;
90ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    private final ConversationCheckedSet mBatchConversations;
916a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private Runnable mCountDown;
922102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei    private final Handler mHandler;
936a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    protected long mLastLeaveBehind = -1;
946a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp
95370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    private final AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
96370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
97370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        @Override
98370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        public void onAnimationStart(Animator animation) {
99370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (!mUndoingItems.isEmpty()) {
100370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mDeletingItems.clear();
101370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mLastDeletingItems.clear();
102370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mSwipeDeletingItems.clear();
103370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
104370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        }
105370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
106370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        @Override
107370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        public void onAnimationEnd(Animator animation) {
108370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            Object obj;
109370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (animation instanceof AnimatorSet) {
110370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                AnimatorSet set = (AnimatorSet) animation;
111370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                obj = ((ObjectAnimator) set.getChildAnimations().get(0)).getTarget();
112370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            } else {
113370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                obj = ((ObjectAnimator) animation).getTarget();
114370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
115370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mSwipeDeletingItems);
116370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mDeletingItems);
117370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mSwipeUndoingItems);
118370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            updateAnimatingConversationItems(obj, mUndoingItems);
119370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (hasFadeLeaveBehinds() && obj instanceof LeaveBehindItem) {
120370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                LeaveBehindItem objItem = (LeaveBehindItem) obj;
121370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                clearLeaveBehind(objItem.getConversationId());
122370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                objItem.commit();
123370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                if (!hasFadeLeaveBehinds()) {
124370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    // Cancel any existing animations on the remaining leave behind
125370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    // item and start fading in text immediately.
126370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    LeaveBehindItem item = getLastLeaveBehindItem();
127370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    if (item != null) {
128370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                        boolean cancelled = item.cancelFadeInTextAnimationIfNotStarted();
129370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                        if (cancelled) {
130370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                            item.startFadeInTextAnimation(0 /* delay start */);
131370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                        }
132370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    }
133370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                }
134370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                // The view types have changed, since the animating views are gone.
135370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                notifyDataSetChanged();
136370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
137370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
138370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            if (!isAnimating()) {
139370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                mActivity.onAnimationEnd(AnimatedAdapter.this);
140370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            }
141370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        }
142370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
143370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang    };
144370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
145c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    /**
146c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * The next action to perform. Do not read or write this. All accesses should
14737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * be in {@link #performAndSetNextAction(SwipeableListView.ListItemsRemovedListener)} which
14837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * commits the previous action, if any.
149c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     */
1509365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private ListItemsRemovedListener mPendingDestruction;
15137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
152c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    /**
153c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * A destructive action that refreshes the list and performs no other action.
154c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     */
1559365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private final ListItemsRemovedListener mRefreshAction = new ListItemsRemovedListener() {
156c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        @Override
1579365a826b46b0e274df88e92534f7d871eef2aa2mindyp        public void onListItemsRemoved() {
158c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal            notifyDataSetChanged();
159c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        }
160c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    };
161c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal
162cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook    public interface Listener {
163cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook        void onAnimationEnd(AnimatedAdapter adapter);
164cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook    }
165cff1aeaff92efb9f7a03203d9f757a2820b87686Paul Westbrook
1660a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao    private Space mDefaultFooter;
1676681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    private View mFooter;
1680a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao    // If true, the last list item will be mFooter, otherwise it's mDefaultFooter.
1690a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao    private boolean mShowCustomFooter;
170eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    private List<View> mHeaders = Lists.newArrayList();
1714584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    private Folder mFolder;
17207118a01f7183645957010779222b84930f75b4eMindy Pereira    private final SwipeableListView mListView;
1737c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private boolean mSwipeEnabled;
1746a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    private final HashMap<Long, LeaveBehindItem> mLeaveBehindItems = Maps.newHashMap();
17517646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    /** True if importance markers are enabled, false otherwise. */
17617646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    private boolean mImportanceMarkersEnabled;
17717646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    /**
17817646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     * True if chevrons (personal level indicators) should be shown:
17917646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     * an arrow ( › ) by messages sent to my address (not a mailing list),
18017646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     * and a double arrow ( » ) by messages sent only to me.
18117646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein     */
18217646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein    private boolean mShowChevronsEnabled;
1832102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei    private final ControllableActivity mActivity;
1847c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    private final AccountObserver mAccountListener = new AccountObserver() {
1857c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        @Override
1867c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        public void onChanged(Account newAccount) {
187d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            if (setAccount(newAccount)) {
188d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy                notifyDataSetChanged();
189d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            }
1907c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        }
1917c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    };
1927c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
19337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    /**
19437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * A list of all views that are not conversations. These include temporary views from
1951c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy     * {@link #mFleetingViews}.
19637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     */
19737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    private final SparseArray<ConversationSpecialItemView> mSpecialViews;
1987c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
1991aba32575a08da6cbad80af8446201d73c59783dMark Wei    private final CoordinatesCache mCoordinatesCache = new CoordinatesCache();
200fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
20137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    /**
20237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * Temporary views insert at specific positions relative to conversations. These can be
20337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * related to showing new features (on-boarding) or showing information about new mailboxes
20437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     * that have been added by the system.
20537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     */
20637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    private final List<ConversationSpecialItemView> mFleetingViews;
20737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
2081801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein    private final BidiFormatter mBidiFormatter = BidiFormatter.getInstance();
2091801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein
210d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy    /**
211d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy     * @return <code>true</code> if a relevant part of the account has changed, <code>false</code>
212d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy     *         otherwise
213d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy     */
214d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy    private boolean setAccount(Account newAccount) {
215d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        final boolean accountChanged;
216d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        if (mAccount != null && mAccount.uri.equals(newAccount.uri)
21717646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                && mAccount.settings.importanceMarkersEnabled ==
21817646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein                        newAccount.settings.importanceMarkersEnabled
219d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy                && mAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO) ==
220d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy                        newAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO)
2210e29e769c74e385342fc5dc8e9c85517771aaa34James Lemieux                && mAccount.settings.convListIcon == newAccount.settings.convListIcon) {
222d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            accountChanged = false;
223d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        } else {
224d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy            accountChanged = true;
225d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        }
226d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy
2277c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mAccount = newAccount;
22817646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        mImportanceMarkersEnabled = mAccount.settings.importanceMarkersEnabled;
22917646055214b9ab3abc2553379bf046ca3e53fb2Andrew Sapperstein        mShowChevronsEnabled = mAccount.settings.showChevronsEnabled;
2307c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mSwipeEnabled = mAccount.supportsCapability(UIProvider.AccountCapabilities.UNDO);
231042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
232042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang        Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_SENDER_IMAGES_ENABLED, Boolean
233042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang                .toString(newAccount.settings.convListIcon == ConversationListIcon.SENDER_IMAGE));
2344fe0af81874976a1995191321e35c844b2229811Andy Huang        Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_REPLY_ALL_SETTING,
2354fe0af81874976a1995191321e35c844b2229811Andy Huang                (newAccount.settings.replyBehavior == UIProvider.DefaultReplyBehavior.REPLY)
2364fe0af81874976a1995191321e35c844b2229811Andy Huang                ? "reply"
2374fe0af81874976a1995191321e35c844b2229811Andy Huang                : "reply_all");
238e6c9fb6835247d98898e2af581ad9449ad7f3184Andy Huang        Analytics.getInstance().setCustomDimension(Analytics.CD_INDEX_AUTO_ADVANCE,
239e6c9fb6835247d98898e2af581ad9449ad7f3184Andy Huang                UIProvider.AutoAdvance.getAutoAdvanceStr(
240e6c9fb6835247d98898e2af581ad9449ad7f3184Andy Huang                        newAccount.settings.getAutoAdvanceSetting()));
241d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy
242d6522ea881e80ab849f2a88565db5a6a73e7623eScott Kennedy        return accountChanged;
2437c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
2447c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
245b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    private static final String LOG_TAG = LogTag.getLogTag();
246a44babdac4e070034f35d984d06c675af8fee81fmindyp    private static final int INCREASE_WAIT_COUNT = 2;
2479879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
248a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    private final BitmapCache mSendersImagesCache;
249a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    private final ContactResolver mContactResolver;
250a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei
251a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal    public AnimatedAdapter(Context context, ConversationCursor cursor,
252ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            ConversationCheckedSet batch, ControllableActivity activity,
2536af70772b2037d3527337f220fc053af73d4c81dScott Kennedy            SwipeableListView listView, final List<ConversationSpecialItemView> specialViews) {
254a91d00b4de3092b41af5f36436d3b49fe4586f64Vikram Aggarwal        super(context, -1, cursor, UIProvider.CONVERSATION_PROJECTION, null, 0);
2559879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        mContext = context;
2569879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        mBatchConversations = batch;
2577c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        setAccount(mAccountListener.initialize(activity.getAccountController()));
258e7d783d726236cb090bba1baed1ea44f743ad788Mindy Pereira        mActivity = activity;
2590a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        mDefaultFooter = (Space) LayoutInflater.from(context).inflate(
2600a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao                R.layout.conversation_list_default_footer, listView, false);
2610a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        mShowCustomFooter = false;
26266bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        mListView = listView;
26337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
2648913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein        mSendersImagesCache = mActivity.getSenderImageCache();
2658913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein
2668913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein        mContactResolver =
2678913ca6aebe6017efe8060b61b8ad38eda95aa8bAndrew Sapperstein                mActivity.getContactResolver(mContext.getContentResolver(), mSendersImagesCache);
26879c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
2696a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        mHandler = new Handler();
270a44babdac4e070034f35d984d06c675af8fee81fmindyp        if (sDismissAllShortDelay == -1) {
27137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            final Resources r = context.getResources();
27237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            sDismissAllShortDelay = r.getInteger(R.integer.dismiss_all_leavebehinds_short_delay);
27337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            sDismissAllLongDelay = r.getInteger(R.integer.dismiss_all_leavebehinds_long_delay);
27437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        }
27537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        if (specialViews != null) {
27637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            mFleetingViews = new ArrayList<ConversationSpecialItemView>(specialViews);
27737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        } else {
27837a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            mFleetingViews = new ArrayList<ConversationSpecialItemView>(0);
2797c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
28037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        /** Total number of special views */
2810e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy        final int size = mFleetingViews.size();
28237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        mSpecialViews = new SparseArray<ConversationSpecialItemView>(size);
2837c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
2841c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Set the adapter in teaser views.
28537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView view : mFleetingViews) {
28637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            view.setAdapter(this);
28737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        }
2887c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
2897c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    }
2907c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal
2913b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    public void cancelDismissCounter() {
2924d4531a63cff536d2ee1a2929d0820981df8516amindyp        cancelLeaveBehindFadeInAnimation();
2933b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        mHandler.removeCallbacks(mCountDown);
2943b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    }
2953b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp
2963b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    public void startDismissCounter() {
297a44babdac4e070034f35d984d06c675af8fee81fmindyp        if (mLeaveBehindItems.size() > INCREASE_WAIT_COUNT) {
298a44babdac4e070034f35d984d06c675af8fee81fmindyp            mHandler.postDelayed(mCountDown, sDismissAllLongDelay);
299a44babdac4e070034f35d984d06c675af8fee81fmindyp        } else {
300a44babdac4e070034f35d984d06c675af8fee81fmindyp            mHandler.postDelayed(mCountDown, sDismissAllShortDelay);
301a44babdac4e070034f35d984d06c675af8fee81fmindyp        }
3023b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    }
3033b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp
3047c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal    public final void destroy() {
3057c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        // Set a null cursor in the adapter
3067c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        swapCursor(null);
3077c401b7896910c00e6234e8774aab0be45740d32Vikram Aggarwal        mAccountListener.unregisterAndDestroy();
3086681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    }
3096681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira
3106681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    @Override
3116681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    public int getCount() {
31237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        // mSpecialViews only contains the views that are currently being displayed
31337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        final int specialViewCount = mSpecialViews.size();
3147c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
3154d888936856ea0e9bc108aa2642ff8e21afeff44Jin Cao        // Headers are not included in the content count because their availability is not affected
3164d888936856ea0e9bc108aa2642ff8e21afeff44Jin Cao        // by the underlying cursor.
3174d888936856ea0e9bc108aa2642ff8e21afeff44Jin Cao        //
3184d888936856ea0e9bc108aa2642ff8e21afeff44Jin Cao        // !! This count still includes the teasers since they are separate from headers. !!
3198c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao        int contentCount = super.getCount() + specialViewCount;
3208c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao        // If we have no content, the only possible thing to show is custom footer (e.g. loading)
3218c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao        if (contentCount == 0) {
3228c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao            contentCount += mShowCustomFooter ? 1 : 0;
3238c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao        } else {
3248c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao            // Only add header & footer is always visible when there are content
3258c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao            contentCount += 1 /* footer */ + mHeaders.size();
3268c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao        }
3278c0fdff583d0471bd830bb7e0c33df8beaa25e93Jin Cao        return contentCount;
328ce407cd978b0482b67426706ddc972a89a507999Jin Cao    }
329ce407cd978b0482b67426706ddc972a89a507999Jin Cao
330ce407cd978b0482b67426706ddc972a89a507999Jin Cao    /**
331e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * Add a conversation to the undo set, but only if its deletion is still cached. If the
332e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * deletion has already been written through and the cursor doesn't have it anymore, we can't
333e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * handle it here, and should instead rely on the cursor refresh to restore the item.
334e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * @param item id for the conversation that is being undeleted.
335e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     * @return true if the conversation is still cached and therefore we will handle the undo.
336e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu     */
337e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu    private boolean addUndoingItem(final long item) {
338e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu        if (getConversationCursor().getUnderlyingPosition(item) >= 0) {
339e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            mUndoingItems.add(item);
340e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            return true;
341e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu        }
342e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu        return false;
343e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu    }
344e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu
3456c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void setUndo(boolean undo) {
3463b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (undo) {
347e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            boolean itemAdded = false;
3483b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (!mLastDeletingItems.isEmpty()) {
349e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                for (Long item : mLastDeletingItems) {
350e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                    itemAdded |= addUndoingItem(item);
351e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                }
3523b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastDeletingItems.clear();
3533b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
3543b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (mLastLeaveBehind != -1) {
355e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                itemAdded |= addUndoingItem(mLastLeaveBehind);
3563b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastLeaveBehind = -1;
3573b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
358e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            // Start animation, only if we're handling the undo.
359e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            if (itemAdded) {
360e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                notifyDataSetChanged();
361e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu                performAndSetNextAction(mRefreshAction);
362e5ca52d91ee8482a81abbd80d625ef592db6fa8dYu Ping Hu            }
3633b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank        }
3643b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank    }
3653b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank
366bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    public void setSwipeUndo(boolean undo) {
3673b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (undo) {
3683b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (!mLastDeletingItems.isEmpty()) {
3693b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mSwipeUndoingItems.addAll(mLastDeletingItems);
3703b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastDeletingItems.clear();
3713b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
3723b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            if (mLastLeaveBehind != -1) {
3733b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mSwipeUndoingItems.add(mLastLeaveBehind);
3743b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp                mLastLeaveBehind = -1;
3753b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            }
376bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            // Start animation
377bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            notifyDataSetChanged();
378bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira            performAndSetNextAction(mRefreshAction);
379bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira        }
380bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
381bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
3820abee55d48f4b7c9f2fefa59d88726ee06c2a4b9mindyp    public View createConversationItemView(SwipeableConversationItemView view, Context context,
383f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            Conversation conv) {
3840abee55d48f4b7c9f2fefa59d88726ee06c2a4b9mindyp        if (view == null) {
3853dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao            view = new SwipeableConversationItemView(context, mAccount);
3869879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        }
387a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        view.bind(conv, mActivity, mBatchConversations, mFolder, getCheckboxSetting(),
388f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this);
3890abee55d48f4b7c9f2fefa59d88726ee06c2a4b9mindyp        return view;
3909879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
3919879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
392dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    @Override
393dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    public boolean hasStableIds() {
394dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank        return true;
395dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    }
396dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank
397dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    @Override
398dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    public int getViewTypeCount() {
399464939499eec4c4d6fd728e75598232b5948a184Mindy Pereira        // TYPE_VIEW_CONVERSATION, TYPE_VIEW_DELETING, TYPE_VIEW_UNDOING, and
4006c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        // TYPE_VIEW_FOOTER, TYPE_VIEW_LEAVEBEHIND.
4016c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        return 5;
402dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    }
403dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank
404dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    @Override
405dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    public int getItemViewType(int position) {
406b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        // Try to recycle views.
407eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if (mHeaders.size() > position) {
408eb145d45c17b08ce09131e84b96350925b3db81aJin Cao            return TYPE_VIEW_HEADER;
4090a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        } else if (position == getCount() - 1) {
410e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            return TYPE_VIEW_FOOTER;
411d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp        } else if (hasLeaveBehinds() || isAnimating()) {
412d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // Setting as type -1 means the recycler won't take this view and
413d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // return it in get view. This is a bit of a "hammer" in that it
414d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // won't let even safe views be recycled here,
415d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // but its safer and cheaper than trying to determine individual
416d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // types. In a future release, use position/id map to try to make
417d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            // this cleaner / faster to determine if the view is animating.
418d0f9578e0c0e01e981937310613ed0bb2550ba42mindyp            return TYPE_VIEW_DONT_RECYCLE;
4190e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        } else if (mSpecialViews.get(getSpecialViewsPos(position)) != null) {
4207c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            // Don't recycle the special views
4217c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            return TYPE_VIEW_DONT_RECYCLE;
422e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        }
423b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        return TYPE_VIEW_CONVERSATION;
424dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank    }
425dd10bc8736282262da0cd9a5f9a0236c10b47028Marc Blank
42654452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal    /**
427067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * Deletes the selected conversations from the conversation list view with a
428067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * translation and then a shrink. These conversations <b>must</b> have their
429067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * {@link Conversation#position} set to the position of these conversations
430067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * among the list. This will only remove the element from the list. The job
431067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * of deleting the actual element is left to the the listener. This listener
432067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * will be called when the animations are complete and is required to delete
433067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * the conversation.
434067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * @param conversations
435067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * @param listener
436067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     */
4379365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public void swipeDelete(Collection<Conversation> conversations,
4389365a826b46b0e274df88e92534f7d871eef2aa2mindyp            ListItemsRemovedListener listener) {
439067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        delete(conversations, listener, mSwipeDeletingItems);
440067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
441067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
442067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
443067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    /**
444067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * Deletes the selected conversations from the conversation list view by
445067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * shrinking them away. These conversations <b>must</b> have their
446067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * {@link Conversation#position} set to the position of these conversations
447067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * among the list. This will only remove the element from the list. The job
448067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * of deleting the actual element is left to the the listener. This listener
449067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * will be called when the animations are complete and is required to delete
450067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira     * the conversation.
45154452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal     * @param conversations
45254452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal     * @param listener
45354452ae7a9cdb607ed1db5e74077b5ebd95c46a2Vikram Aggarwal     */
4549365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public void delete(Collection<Conversation> conversations, ListItemsRemovedListener listener) {
455067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        delete(conversations, listener, mDeletingItems);
456067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
457067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
4589365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private void delete(Collection<Conversation> conversations, ListItemsRemovedListener listener,
459e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            HashSet<Long> list) {
4603b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank        // Clear out any remaining items and add the new ones
4613b2d91316fcfc407ba0e40ad35dea659922dccecMarc Blank        mLastDeletingItems.clear();
462e4abda754bad698f81f55c139a530478dae5476dPaul Westbrook        // Since we are deleting new items, clear any remaining undo items
463e4abda754bad698f81f55c139a530478dae5476dPaul Westbrook        mUndoingItems.clear();
46466bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank
465b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        final int startPosition = mListView.getFirstVisiblePosition();
466b54a46756017c81a9f253df4d4e8f967f137f803Vikram Aggarwal        final int endPosition = mListView.getLastVisiblePosition();
46766bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank
46866bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        // Only animate visible items
469e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        for (Conversation c: conversations) {
470e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            if (c.position >= startPosition && c.position <= endPosition) {
471e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                mLastDeletingItems.add(c.id);
472e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                list.add(c.id);
47366bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank            }
47466bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        }
47566bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank
476067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (list.isEmpty()) {
47766bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank            // If we have no deleted items on screen, skip the animation
4789365a826b46b0e274df88e92534f7d871eef2aa2mindyp            listener.onListItemsRemoved();
479f01b02b09acca214892cbf865a89dbdf19f77238Scott Kennedy            // If we have an action queued up, perform it
480f01b02b09acca214892cbf865a89dbdf19f77238Scott Kennedy            performAndSetNextAction(null);
48166bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        } else {
4829365a826b46b0e274df88e92534f7d871eef2aa2mindyp            performAndSetNextAction(listener);
48366bee6e884dc7f6c6f880fc0213bbd5e4c23e476Marc Blank        }
4849879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        notifyDataSetChanged();
4859879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
4869879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
4879879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    @Override
4889879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    public View getView(int position, View convertView, ViewGroup parent) {
489eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if (mHeaders.size() > position) {
490eb145d45c17b08ce09131e84b96350925b3db81aJin Cao            return mHeaders.get(position);
4910a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        } else if (position == getCount() - 1) {
4920a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao            return mShowCustomFooter ? mFooter : mDefaultFooter;
4936681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        }
4947c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
4957c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        // Check if this is a special view
4960e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        final ConversationSpecialItemView specialView = mSpecialViews.get(
4970e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao                getSpecialViewsPos(position));
4987c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        if (specialView != null) {
499f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy            specialView.onGetView();
500b45d1418887d8595c230788e20516bbe10c2f3eaScott Kennedy            return (View) specialView;
5017c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
5027c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
503f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceBeginSection("AA.getView");
504f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang
50537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        final ConversationCursor cursor = (ConversationCursor) getItem(position);
5061bca265b7a8a3f9ea08e0ae51eeb145f0883a266Andy Huang        final Conversation conv = cursor.getConversation();
507983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook
508983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook        // Notify the provider of this change in the position of Conversation cursor
509983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook        cursor.notifyUIPositionChange();
510983a723931447b6261a2e42b25e6f931dba6de33Paul Westbrook
511e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        if (isPositionUndoing(conv.id)) {
5126176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getUndoingView(position - getPositionOffset(position), conv, parent,
5136176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy                    false /* don't show swipe background */);
514e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        } if (isPositionUndoingSwipe(conv.id)) {
5156176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getUndoingView(position - getPositionOffset(position), conv, parent,
5166176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy                    true /* show swipe background */);
517e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        } else if (isPositionDeleting(conv.id)) {
5186176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getDeletingView(position - getPositionOffset(position), conv, parent, false);
519e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        } else if (isPositionSwipeDeleting(conv.id)) {
5206176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy            return getDeletingView(position - getPositionOffset(position), conv, parent, true);
5219879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        }
52262d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        if (hasFadeLeaveBehinds()) {
52362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            if(isPositionFadeLeaveBehind(conv)) {
52462d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang                LeaveBehindItem fade  = getFadeLeaveBehindItem(position, conv);
5253b965d78774a42358ce6bbdcc43b4c8df130a60eScott Kennedy                fade.startShrinkAnimation(mAnimatorListener);
52670f0111a4337367b0cd5fcc1302b730fb332aeebMark Wei                Utils.traceEndSection();
52762d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang                return fade;
52862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            }
52962d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        }
5306c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        if (hasLeaveBehinds()) {
531e358ed5c4ed1b172f5eae98f97919a8e471c98dcmindyp            if (isPositionLeaveBehind(conv)) {
532370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                final LeaveBehindItem fadeIn = getLeaveBehindItem(conv);
5334d4531a63cff536d2ee1a2929d0820981df8516amindyp                if (conv.id == mLastLeaveBehind) {
534a44babdac4e070034f35d984d06c675af8fee81fmindyp                    // If it looks like the person is doing a lot of rapid
535a44babdac4e070034f35d984d06c675af8fee81fmindyp                    // swipes, wait patiently before animating
536a44babdac4e070034f35d984d06c675af8fee81fmindyp                    if (mLeaveBehindItems.size() > INCREASE_WAIT_COUNT) {
537a44babdac4e070034f35d984d06c675af8fee81fmindyp                        if (fadeIn.isAnimating()) {
538a44babdac4e070034f35d984d06c675af8fee81fmindyp                            fadeIn.increaseFadeInDelay(sDismissAllLongDelay);
539a44babdac4e070034f35d984d06c675af8fee81fmindyp                        } else {
540a44babdac4e070034f35d984d06c675af8fee81fmindyp                            fadeIn.startFadeInTextAnimation(sDismissAllLongDelay);
541a44babdac4e070034f35d984d06c675af8fee81fmindyp                        }
542a44babdac4e070034f35d984d06c675af8fee81fmindyp                    } else {
543a44babdac4e070034f35d984d06c675af8fee81fmindyp                        // Otherwise, assume they are just doing 1 and wait less time
544a44babdac4e070034f35d984d06c675af8fee81fmindyp                        fadeIn.startFadeInTextAnimation(sDismissAllShortDelay /* delay start */);
545a44babdac4e070034f35d984d06c675af8fee81fmindyp                    }
5464d4531a63cff536d2ee1a2929d0820981df8516amindyp                }
54770f0111a4337367b0cd5fcc1302b730fb332aeebMark Wei                Utils.traceEndSection();
54884f9b5c60dc023570202859ba1d30cf9cb5e6e7aMindy Pereira                return fadeIn;
5496c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            }
5506c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        }
5517c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
552067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (convertView != null && !(convertView instanceof SwipeableConversationItemView)) {
553067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            LogUtils.w(LOG_TAG, "Incorrect convert view received; nulling it out");
554eb88ececd0a53c4e956240b7b619da6410e2d356mindyp            convertView = newView(mContext, cursor, parent);
555c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        } else if (convertView != null) {
556c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira            ((SwipeableConversationItemView) convertView).reset();
557afd6f9246ddf645a45c8e91df5c5c2587cbf6a0dMindy Pereira        }
558f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        final View v = createConversationItemView((SwipeableConversationItemView) convertView,
559f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                mContext, conv);
560f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        Utils.traceEndSection();
561f82d6e7342e277f123a04fc82cc841b180655c15Andy Huang        return v;
5629879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
5639879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
5646c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private boolean hasLeaveBehinds() {
5656a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        return !mLeaveBehindItems.isEmpty();
5666c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
5676c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
56862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    private boolean hasFadeLeaveBehinds() {
5698f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira        return !mFadeLeaveBehindItems.isEmpty();
57062d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
57162d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
57279e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    public LeaveBehindItem setupLeaveBehind(Conversation target, ToastBarOperation undoOp,
573370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            int deletedRow, int viewHeight) {
5744d4531a63cff536d2ee1a2929d0820981df8516amindyp        cancelLeaveBehindFadeInAnimation();
5756a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        mLastLeaveBehind = target.id;
57662d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        fadeOutLeaveBehindItems();
577370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang
578370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        final LeaveBehindItem leaveBehind = (LeaveBehindItem) LayoutInflater.from(mContext)
579370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                .inflate(R.layout.swipe_leavebehind, mListView, false);
580370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        leaveBehind.bind(deletedRow, mAccount, this, undoOp, target, mFolder, viewHeight);
5816a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        mLeaveBehindItems.put(target.id, leaveBehind);
582e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        mLastDeletingItems.add(target.id);
58379e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        return leaveBehind;
5846c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
5856c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
5866a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    public void fadeOutSpecificLeaveBehindItem(long id) {
5876a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (mLastLeaveBehind == id) {
5886a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLastLeaveBehind = -1;
5896a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
5906a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        startFadeOutLeaveBehindItemsAnimations();
5916a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    }
5926a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp
5936a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    // This should kick off a timer such that there is a minimum time each item
5946a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    // shows up before being dismissed. That way if the user is swiping away
5956a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    // items in rapid succession, their finger position is maintained.
59662d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    public void fadeOutLeaveBehindItems() {
5976a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (mCountDown == null) {
5986a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mCountDown = new Runnable() {
5996a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                @Override
6006a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                public void run() {
6016a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    startFadeOutLeaveBehindItemsAnimations();
6026a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
6036a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            };
6046a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        } else {
6056a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mHandler.removeCallbacks(mCountDown);
6066a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
6076a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        // Clear all the text since these are no longer clickable
6086a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        Iterator<Entry<Long, LeaveBehindItem>> i = mLeaveBehindItems.entrySet().iterator();
6096a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        LeaveBehindItem item;
6106a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        while (i.hasNext()) {
6116a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            item = i.next().getValue();
6126a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            Conversation conv = item.getData();
6136a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            if (mLastLeaveBehind == -1 || conv.id != mLastLeaveBehind) {
614a44babdac4e070034f35d984d06c675af8fee81fmindyp                item.cancelFadeInTextAnimation();
6156a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                item.makeInert();
6166a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            }
6176a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
6183b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        startDismissCounter();
6196a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    }
6206a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp
6216a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp    protected void startFadeOutLeaveBehindItemsAnimations() {
62262d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        final int startPosition = mListView.getFirstVisiblePosition();
62362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        final int endPosition = mListView.getLastVisiblePosition();
62462d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
62579e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        if (hasLeaveBehinds()) {
62679e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira            // If the item is visible, fade it out. Otherwise, just remove
62779e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira            // it.
6286a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            Iterator<Entry<Long, LeaveBehindItem>> i = mLeaveBehindItems.entrySet().iterator();
6296a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            LeaveBehindItem item;
6306a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            while (i.hasNext()) {
6316a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                item = i.next().getValue();
6326a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                Conversation conv = item.getData();
6336a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                if (mLastLeaveBehind == -1 || conv.id != mLastLeaveBehind) {
6346a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    if (conv.position >= startPosition && conv.position <= endPosition) {
6356a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                        mFadeLeaveBehindItems.put(conv.id, item);
6366a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    } else {
6376a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                        item.commit();
6386a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    }
6396a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    i.remove();
6406a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
64162d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            }
6424d4531a63cff536d2ee1a2929d0820981df8516amindyp            cancelLeaveBehindFadeInAnimation();
64362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        }
64462d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        if (!mLastDeletingItems.isEmpty()) {
64562d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang            mLastDeletingItems.clear();
64662d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        }
64762d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang        notifyDataSetChanged();
64862d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
64962d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
6504d4531a63cff536d2ee1a2929d0820981df8516amindyp    private void cancelLeaveBehindFadeInAnimation() {
6514d4531a63cff536d2ee1a2929d0820981df8516amindyp        LeaveBehindItem leaveBehind = getLastLeaveBehindItem();
6524d4531a63cff536d2ee1a2929d0820981df8516amindyp        if (leaveBehind != null) {
6534d4531a63cff536d2ee1a2929d0820981df8516amindyp            leaveBehind.cancelFadeInTextAnimation();
6544d4531a63cff536d2ee1a2929d0820981df8516amindyp        }
6554d4531a63cff536d2ee1a2929d0820981df8516amindyp    }
6564d4531a63cff536d2ee1a2929d0820981df8516amindyp
6571aba32575a08da6cbad80af8446201d73c59783dMark Wei    public CoordinatesCache getCoordinatesCache() {
658fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang        return mCoordinatesCache;
659fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang    }
660fbc519e976de0c0debd810ed8c7f77de44d136a1Andy Huang
6611801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein    public BidiFormatter getBidiFormatter() {
6621801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein        return mBidiFormatter;
6631801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein    }
6641801b32a2977ca97ca194a3c9e9633b03e5496a4Andrew Sapperstein
6655254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    public SwipeableListView getListView() {
6665254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        return mListView;
6675254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    }
6685254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp
669c6adce3cf6887c4c6dd5005724565702751843d0mindyp    public void commitLeaveBehindItems(boolean animate) {
670dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira        // Remove any previously existing leave behinds.
6715254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        boolean changed = false;
67279e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        if (hasLeaveBehinds()) {
6736a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            for (LeaveBehindItem item : mLeaveBehindItems.values()) {
6746a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                if (animate) {
675dcb26aea2b27b585c35c422c870e849b8c4e41d6mindyp                    mFadeLeaveBehindItems.put(item.getConversationId(), item);
6766a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                } else {
6776a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    item.commit();
6786a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
679c6adce3cf6887c4c6dd5005724565702751843d0mindyp            }
6805254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            changed = true;
6816a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLastLeaveBehind = -1;
6826a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLeaveBehindItems.clear();
683dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira        }
684aa55bc9cb210a46a950874f368baa07f041a4302mindyp        if (hasFadeLeaveBehinds() && !animate) {
685aa55bc9cb210a46a950874f368baa07f041a4302mindyp            // Find any fading leave behind items and commit them all, too.
686aa55bc9cb210a46a950874f368baa07f041a4302mindyp            for (LeaveBehindItem item : mFadeLeaveBehindItems.values()) {
687aa55bc9cb210a46a950874f368baa07f041a4302mindyp                item.commit();
688aa55bc9cb210a46a950874f368baa07f041a4302mindyp            }
689aa55bc9cb210a46a950874f368baa07f041a4302mindyp            mFadeLeaveBehindItems.clear();
690aa55bc9cb210a46a950874f368baa07f041a4302mindyp            changed = true;
691aa55bc9cb210a46a950874f368baa07f041a4302mindyp        }
69206b623852cdacc749d67d9c1b7c478dd52780297Mindy Pereira        if (!mLastDeletingItems.isEmpty()) {
69306b623852cdacc749d67d9c1b7c478dd52780297Mindy Pereira            mLastDeletingItems.clear();
6945254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            changed = true;
6955254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        }
696fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy
697fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy        for (final ConversationSpecialItemView view : mFleetingViews) {
698fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy            if (view.commitLeaveBehindItem()) {
699fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy                changed = true;
700fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy            }
701fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy        }
702fbf4f4729c9bea907cb57d4f449893eb2fc5dd1dScott Kennedy
7035254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp        if (changed) {
7045254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp            notifyDataSetChanged();
70506b623852cdacc749d67d9c1b7c478dd52780297Mindy Pereira        }
706dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira    }
707dea5d77be4c6601b461b45fd06a92bb3e44b8810Mindy Pereira
70879e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    private LeaveBehindItem getLeaveBehindItem(Conversation target) {
7096a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        return mLeaveBehindItems.get(target.id);
7106c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
7116c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
71262d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    private LeaveBehindItem getFadeLeaveBehindItem(int position, Conversation target) {
7138f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira        return mFadeLeaveBehindItems.get(target.id);
71462d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
71562d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
716d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    @Override
717d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    public long getItemId(int position) {
7180a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        if ((mHeaders.size() > position) || (position == getCount() - 1)) {
719d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira            return -1;
720d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira        }
721f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy
7220e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        final ConversationSpecialItemView specialView = mSpecialViews.get(
7230e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao                getSpecialViewsPos(position));
724f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy        if (specialView != null) {
725f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy            // TODO(skennedy) We probably want something better than this
726f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy            return specialView.hashCode();
727f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy        }
728f77806ed36ab49861a5ea13a3ab34e5a3a21c022Scott Kennedy
72955e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang        final int cursorPos = position - getPositionOffset(position);
730348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // advance the cursor to the right position and read the cached conversation, if present
731348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        //
732348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // (no need to have CursorAdapter check mDataValid because in our incarnation without
733348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // FLAG_REGISTER_CONTENT_OBSERVER, mDataValid is effectively identical to mCursor being
734348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        // non-null)
735348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        final ConversationCursor cursor = getConversationCursor();
736348398d7f3ff058248ef9f7d37443496c0e400a5Andy Huang        if (cursor != null && cursor.moveToPosition(cursorPos)) {
7376cf45c601317d4b65ffb1896760fa1cb8a2b807cAndy Huang            final Conversation conv = cursor.getCachedConversation();
73855e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang            if (conv != null) {
73955e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang                return conv.id;
74055e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang            }
74155e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang        }
74255e76949ca7464c3bd55fdc25fb3daa43466ef5cAndy Huang        return super.getItemId(cursorPos);
743d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    }
744d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira
7456176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy    /**
7466176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     * @param position The position in the cursor
7476176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     */
748e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private View getDeletingView(int position, Conversation conversation, ViewGroup parent,
749e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            boolean swipe) {
750c7d201d79974fd0f1e935880d51fe516f78207a2Vikram Aggarwal        conversation.position = position;
751067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        SwipeableConversationItemView deletingView = mAnimatingViews.get(conversation.id);
752067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (deletingView == null) {
753067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // The undo animation consists of fading in the conversation that
754067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // had been destroyed.
755067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            deletingView = newConversationItemView(position, parent, conversation);
756370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            deletingView.startDeleteAnimation(mAnimatorListener, swipe);
757067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
758067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return deletingView;
759a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira    }
760a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira
7616176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy    /**
7626176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     * @param position The position in the cursor
7636176b722c53d0fa546f679cc453af615045b1e14Scott Kennedy     */
764e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private View getUndoingView(int position, Conversation conv, ViewGroup parent, boolean swipe) {
765e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        conv.position = position;
766e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        SwipeableConversationItemView undoView = mAnimatingViews.get(conv.id);
767067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (undoView == null) {
768067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // The undo animation consists of fading in the conversation that
769067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // had been destroyed.
770e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            undoView = newConversationItemView(position, parent, conv);
771370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang            undoView.startUndoAnimation(mAnimatorListener, swipe);
772067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
773067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return undoView;
774067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
775067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
7765ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    @Override
7775ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    public View newView(Context context, Cursor cursor, ViewGroup parent) {
7783dbfbc210a607382ba9c150d7ae373ca0508267cJin Cao        return new SwipeableConversationItemView(context, mAccount);
7795ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    }
7805ceab3bd6892b85b0252b987b67b70ec5055587fmindyp
7815ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    @Override
7825ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    public void bindView(View view, Context context, Cursor cursor) {
78307fe8df87bde8732398434e55cce366a8528c181Andy Huang        // no-op. we only get here from newConversationItemView(), which will immediately bind
78407fe8df87bde8732398434e55cce366a8528c181Andy Huang        // on its own.
7855ceab3bd6892b85b0252b987b67b70ec5055587fmindyp    }
7865ceab3bd6892b85b0252b987b67b70ec5055587fmindyp
787067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    private SwipeableConversationItemView newConversationItemView(int position, ViewGroup parent,
788067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            Conversation conversation) {
789067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        SwipeableConversationItemView view = (SwipeableConversationItemView) super.getView(
790067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                position, null, parent);
791dc0617f3478b21dd3324ab10b8c433517ae95460mindyp        view.reset();
792a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        view.bind(conversation, mActivity, mBatchConversations, mFolder, getCheckboxSetting(),
793f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                mSwipeEnabled, mImportanceMarkersEnabled, mShowChevronsEnabled, this);
794067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        mAnimatingViews.put(conversation.id, view);
795067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return view;
7969879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
7979879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
798642731419abb9037a729114d32d6ddd15af0a406Alice Yang    private int getCheckboxSetting() {
799642731419abb9037a729114d32d6ddd15af0a406Alice Yang        return mAccount != null ? mAccount.settings.convListIcon :
800642731419abb9037a729114d32d6ddd15af0a406Alice Yang            ConversationListIcon.DEFAULT;
801642731419abb9037a729114d32d6ddd15af0a406Alice Yang    }
802642731419abb9037a729114d32d6ddd15af0a406Alice Yang
803d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    @Override
804d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    public Object getItem(int position) {
8050e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        final ConversationSpecialItemView specialView = mSpecialViews.get(
8060e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao                getSpecialViewsPos(position));
807eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        if (mHeaders.size() > position) {
808eb145d45c17b08ce09131e84b96350925b3db81aJin Cao            return mHeaders.get(position);
8090a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        } else if (position == getCount() - 1) {
8100a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao            return mShowCustomFooter ? mFooter : mDefaultFooter;
8110e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        } else if (specialView != null) {
8120e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao            return specialView;
813d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira        }
8147c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        return super.getItem(position - getPositionOffset(position));
815d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira    }
816d3651a6ad41c1451e90f538b9f66afb008a44216Mindy Pereira
817e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionDeleting(long id) {
818e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mDeletingItems.contains(id);
819a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira    }
820a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira
821e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionSwipeDeleting(long id) {
822e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mSwipeDeletingItems.contains(id);
823067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
824067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
825e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionUndoing(long id) {
826e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mUndoingItems.contains(id);
8279879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    }
8289879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira
829e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private boolean isPositionUndoingSwipe(long id) {
830e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        return mSwipeUndoingItems.contains(id);
831bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
832bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
8336c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private boolean isPositionLeaveBehind(Conversation conv) {
83479e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        return hasLeaveBehinds()
8356a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                && mLeaveBehindItems.containsKey(conv.id)
83679e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira                && conv.isMostlyDead();
8376c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
8386c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
83962d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    private boolean isPositionFadeLeaveBehind(Conversation conv) {
84079e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        return hasFadeLeaveBehinds()
8418f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira                && mFadeLeaveBehindItems.containsKey(conv.id)
84279e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira                && conv.isMostlyDead();
84362d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang    }
84462d7962b2b4d73f8414bbab1f42952442ac25be0Andy Huang
845c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    /**
846c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * Performs the pending destruction, if any and assigns the next pending action.
847c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * @param next The next action that is to be performed, possibly null (if no next action is
848c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     * needed).
849c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal     */
85037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    private void performAndSetNextAction(ListItemsRemovedListener next) {
851c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        if (mPendingDestruction != null) {
8529365a826b46b0e274df88e92534f7d871eef2aa2mindyp            mPendingDestruction.onListItemsRemoved();
853c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        }
854c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal        mPendingDestruction = next;
855c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal    }
856c30fe4172676a5ea3fdc0da8a0fbb917d9cf878eVikram Aggarwal
857e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp    private void updateAnimatingConversationItems(Object obj, HashSet<Long> items) {
858067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (!items.isEmpty()) {
859067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            if (obj instanceof ConversationItemView) {
860067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                final ConversationItemView target = (ConversationItemView) obj;
861e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                final long id = target.getConversation().id;
862e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                items.remove(id);
863e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp                mAnimatingViews.remove(id);
864067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                if (items.isEmpty()) {
865bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira                    performAndSetNextAction(null);
866067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    notifyDataSetChanged();
867bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira                }
868866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            }
8699879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira        }
870bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira    }
871bdb43d559dfba09752e95ca88f73ca566dcbb86fMindy Pereira
8729879d4c74520800eff386ab27eb5e03432c610b5Mindy Pereira    @Override
873866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public boolean areAllItemsEnabled() {
87437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        // The animating items and some special views are not enabled.
875866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return false;
876866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
877866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
878866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    @Override
879b90db28aac1311f0ed32a786594e17c007550853Scott Kennedy    public boolean isEnabled(final int position) {
88037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        final ConversationSpecialItemView view = mSpecialViews.get(position);
88137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        if (view != null) {
88237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            final boolean enabled = view.acceptsUserTaps();
88337a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            LogUtils.d(LOG_TAG, "AA.isEnabled(%d) = %b", position, enabled);
88437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            return enabled;
885b90db28aac1311f0ed32a786594e17c007550853Scott Kennedy        }
886a41baad67f0e49a53e67ae560d130dc463bba4f8Mindy Pereira        return !isPositionDeleting(position) && !isPositionUndoing(position);
887866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
888866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
889573b9e698852c6cf2cbf0f93bc01b7abb8b64ce1Paul Westbrook    public void setFooterVisibility(boolean show) {
8900a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao        if (mShowCustomFooter != show) {
8910a72b736dae35dc6a8a0d38a9a6e8a17607a9d25Jin Cao            mShowCustomFooter = show;
8926681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira            notifyDataSetChanged();
8936681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        }
8946681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    }
8956681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira
8966681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    public void addFooter(View footerView) {
8976681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira        mFooter = footerView;
8986681f6b78557850d9ec76a7a8f9ac1ec930d2513Mindy Pereira    }
8994584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira
900eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    public void addHeader(View headerView) {
901eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        mHeaders.add(headerView);
902eb145d45c17b08ce09131e84b96350925b3db81aJin Cao    }
903eb145d45c17b08ce09131e84b96350925b3db81aJin Cao
9044584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    public void setFolder(Folder folder) {
9054584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira        mFolder = folder;
9064584a0d83e160444f931cb565185a2eea39b1683Mindy Pereira    }
9076c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira
90879e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira    public void clearLeaveBehind(long itemId) {
9096a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (hasLeaveBehinds() && mLeaveBehindItems.containsKey(itemId)) {
9106a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLeaveBehindItems.remove(itemId);
9118f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira        } else if (hasFadeLeaveBehinds()) {
9128f39702ca9f9bea23d27a46a288cd6f6660de447Mindy Pereira            mFadeLeaveBehindItems.remove(itemId);
91379e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        } else {
91479e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira            LogUtils.d(LOG_TAG, "Trying to clear a non-existant leave behind");
91579e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        }
9166a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (mLastLeaveBehind == itemId) {
9176a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLastLeaveBehind = -1;
9186a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        }
9196c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    }
9207d81600cbce3cfd366cbff9ecd1b7317ff957221Vikram Aggarwal
921d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    public void onSaveInstanceState(Bundle outState) {
922e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        long[] lastDeleting = new long[mLastDeletingItems.size()];
92379e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        for (int i = 0; i < lastDeleting.length; i++) {
924d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira            lastDeleting[i] = mLastDeletingItems.get(i);
925d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        }
926e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp        outState.putLongArray(LAST_DELETING_ITEMS, lastDeleting);
92779e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        if (hasLeaveBehinds()) {
9286a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            if (mLastLeaveBehind != -1) {
9296a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                outState.putParcelable(LEAVE_BEHIND_ITEM_DATA,
9306a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                        mLeaveBehindItems.get(mLastLeaveBehind).getLeaveBehindData());
9316a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                outState.putLong(LEAVE_BEHIND_ITEM_ID, mLastLeaveBehind);
9326a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            }
9336a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            for (LeaveBehindItem item : mLeaveBehindItems.values()) {
9346a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                if (mLastLeaveBehind == -1 || item.getData().id != mLastLeaveBehind) {
9356a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    item.commit();
9366a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                }
9376a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            }
93879e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        }
939d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    }
940d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira
941d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    public void onRestoreInstanceState(Bundle outState) {
942b8ef4ac43f3570245ec476e2ee9f8a9d1d3ff36cPaul Westbrook        if (outState.containsKey(LAST_DELETING_ITEMS)) {
943e85b8cdf23ba579246a1c8c3774687ca614eb39bmindyp            final long[] lastDeleting = outState.getLongArray(LAST_DELETING_ITEMS);
94437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal            for (final long aLastDeleting : lastDeleting) {
94537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal                mLastDeletingItems.add(aLastDeleting);
946b8ef4ac43f3570245ec476e2ee9f8a9d1d3ff36cPaul Westbrook            }
947d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        }
9486a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp        if (outState.containsKey(LEAVE_BEHIND_ITEM_DATA)) {
9496a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            LeaveBehindData left =
9506a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp                    (LeaveBehindData) outState.getParcelable(LEAVE_BEHIND_ITEM_DATA);
9516a6deb20dbbea543ccf093487d26dea4ac4f9cd4mindyp            mLeaveBehindItems.put(outState.getLong(LEAVE_BEHIND_ITEM_ID),
952370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang                    setupLeaveBehind(left.data, left.op, left.data.position, left.height));
95379e6a0830cc23deb9ba7be07d4ec5b5235a3398bMindy Pereira        }
954d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira    }
95569e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira
95669e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira    /**
95769e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira     * Return if the adapter is in the process of animating anything.
95869e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira     */
95969e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira    public boolean isAnimating() {
96069e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira        return !mUndoingItems.isEmpty()
96169e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira                || !mSwipeUndoingItems.isEmpty()
9621e946db1a0e20a92361cf1c86d8b28a1f878fdbcMindy Pereira                || hasFadeLeaveBehinds()
96369e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira                || !mDeletingItems.isEmpty()
96469e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira                || !mSwipeDeletingItems.isEmpty();
96569e88dd6779a8f88212a049d49d69503cd746ef7Mindy Pereira    }
966215d2a465dd17139d4c8cce426ae8c8ff556746emindyp
967f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang    /**
968f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     * Forcibly clear any internal state that would cause {@link #isAnimating()} to return true.
969f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     * Call this in times of desperation, when you really, really want to trash state and just
970f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     * start over.
971f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang     */
972f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang    public void clearAnimationState() {
973f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        if (!isAnimating()) {
974f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang            return;
975f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        }
976f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang
977f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mUndoingItems.clear();
978f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mSwipeUndoingItems.clear();
979f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mFadeLeaveBehindItems.clear();
980f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mDeletingItems.clear();
981f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mSwipeDeletingItems.clear();
982f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        mAnimatingViews.clear();
983f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        LogUtils.w(LOG_TAG, "AA.clearAnimationState forcibly cleared state, this=%s", this);
984f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang    }
985f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang
986c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang    @Override
987c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang    public String toString() {
988c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        final StringBuilder sb = new StringBuilder("{");
989c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(super.toString());
990c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mUndoingItems=");
991c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mUndoingItems);
992c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mSwipeUndoingItems=");
993c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mSwipeUndoingItems);
994c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mDeletingItems=");
995c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mDeletingItems);
996c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mSwipeDeletingItems=");
997c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mSwipeDeletingItems);
998c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mLeaveBehindItems=");
999c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mLeaveBehindItems);
1000c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mFadeLeaveBehindItems=");
1001c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mFadeLeaveBehindItems);
1002c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(" mLastDeletingItems=");
1003c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append(mLastDeletingItems);
1004f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(" mAnimatingViews=");
1005f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(mAnimatingViews);
1006f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(" mPendingDestruction=");
1007f21787ad2ac7d68e3620ffa3ae6e8e7fadf0bd54Andy Huang        sb.append(mPendingDestruction);
1008c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        sb.append("}");
1009c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang        return sb.toString();
1010c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang    }
1011c1922a93fb9540d4ff8c28a30d1ae58d3a3d73f9Andy Huang
1012215d2a465dd17139d4c8cce426ae8c8ff556746emindyp    /**
1013215d2a465dd17139d4c8cce426ae8c8ff556746emindyp     * Get the ConversationCursor associated with this adapter.
1014215d2a465dd17139d4c8cce426ae8c8ff556746emindyp     */
1015215d2a465dd17139d4c8cce426ae8c8ff556746emindyp    public ConversationCursor getConversationCursor() {
1016215d2a465dd17139d4c8cce426ae8c8ff556746emindyp        return (ConversationCursor) getCursor();
1017215d2a465dd17139d4c8cce426ae8c8ff556746emindyp    }
10187af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp
10194d4531a63cff536d2ee1a2929d0820981df8516amindyp    /**
10204d4531a63cff536d2ee1a2929d0820981df8516amindyp     * Get the currently visible leave behind item.
10214d4531a63cff536d2ee1a2929d0820981df8516amindyp     */
10227af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    public LeaveBehindItem getLastLeaveBehindItem() {
10237af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        if (mLastLeaveBehind != -1) {
10247af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp            return mLeaveBehindItems.get(mLastLeaveBehind);
10257af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        }
10267af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        return null;
10277af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    }
10284d4531a63cff536d2ee1a2929d0820981df8516amindyp
10294d4531a63cff536d2ee1a2929d0820981df8516amindyp    /**
10304d4531a63cff536d2ee1a2929d0820981df8516amindyp     * Cancel fading out the text displayed in the leave behind item currently
10314d4531a63cff536d2ee1a2929d0820981df8516amindyp     * shown.
10324d4531a63cff536d2ee1a2929d0820981df8516amindyp     */
10334d4531a63cff536d2ee1a2929d0820981df8516amindyp    public void cancelFadeOutLastLeaveBehindItemText() {
10344d4531a63cff536d2ee1a2929d0820981df8516amindyp        LeaveBehindItem item = getLastLeaveBehindItem();
10354d4531a63cff536d2ee1a2929d0820981df8516amindyp        if (item != null) {
10364d4531a63cff536d2ee1a2929d0820981df8516amindyp            item.cancelFadeOutText();
10374d4531a63cff536d2ee1a2929d0820981df8516amindyp        }
10384d4531a63cff536d2ee1a2929d0820981df8516amindyp    }
10397c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
104037a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal    /**
10411c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy     * Updates special (non-conversation view) when {@link #mFleetingViews} changed
104237a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal     */
10437c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    private void updateSpecialViews() {
10441c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // We recreate all the special views using mFleetingViews.
104537a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        mSpecialViews.clear();
104637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal
1047bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao        // If the conversation cursor hasn't finished loading, hide all special views
1048bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao        if (!ConversationCursor.isCursorReadyToShow(getConversationCursor())) {
1049bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao            return;
1050bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao        }
1051bc29ed3a5fe96ac144d5157150551febfb4d1355Jin Cao
10521c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Fleeting (temporary) views specify a position, which is 0-indexed and
10531c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // has to be adjusted for the number of fleeting views above it.
105437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView specialView : mFleetingViews) {
10550e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy            specialView.onUpdate(mFolder, getConversationCursor());
10567c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10577c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            if (specialView.getShouldDisplayInList()) {
10580e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy                // If the special view asks for position 0, it wants to be at the top.
10590e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy                int position = (specialView.getPosition());
10602102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei
10612102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                // insert the special view into the position, but if there is
10622102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                // already an item occupying that position, move that item back
10632102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                // one position, and repeat
10642102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                ConversationSpecialItemView insert = specialView;
10652102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                while (insert != null) {
106637a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal                    final ConversationSpecialItemView kickedOut = mSpecialViews.get(position);
106737a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal                    mSpecialViews.put(position, insert);
10682102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                    insert = kickedOut;
10692102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                    position++;
10702102b2c87a6cb39bc63fb7eff13dda64da56b72eMark Wei                }
10717c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            }
10727c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
10737c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
10747c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
1075e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy    /**
1076e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     * Gets the position of the specified {@link ConversationSpecialItemView}, as determined by
1077e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     * the adapter.
1078e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     *
1079e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     * @return The position in the list, or a negative value if it could not be found
1080e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy     */
1081e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy    public int getSpecialViewPosition(final ConversationSpecialItemView view) {
1082e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy        return mSpecialViews.indexOfValue(view);
1083e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy    }
1084e0d01fb7379225a0f058999d9da9050f2fcc6945Scott Kennedy
10857c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
10867c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void notifyDataSetChanged() {
1087d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        // This may be a temporary catch for a problem, or we may leave it here.
1088d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        // b/9527863
1089d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        if (Looper.getMainLooper() != Looper.myLooper()) {
1090d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy            LogUtils.wtf(LOG_TAG, "notifyDataSetChanged() called off the main thread");
1091d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy        }
1092d54a43c1d722ad7cb0376ba801c59c69d8a70234Scott Kennedy
10937c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
10947c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        super.notifyDataSetChanged();
10957c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
10967c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
10977c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
10987c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void changeCursor(final Cursor cursor) {
10997c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        super.changeCursor(cursor);
11007c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
11017c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
11027c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11037c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
11047c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void changeCursorAndColumns(final Cursor c, final String[] from, final int[] to) {
11057c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        super.changeCursorAndColumns(c, from, to);
11067c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
11077c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
11087c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11097c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    @Override
11107c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public Cursor swapCursor(final Cursor c) {
11117c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        final Cursor oldCursor = super.swapCursor(c);
11127c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        updateSpecialViews();
11137c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11147c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        return oldCursor;
11157c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
11167c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
1117a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    public BitmapCache getSendersImagesCache() {
1118a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        return mSendersImagesCache;
111979c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang    }
112079c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
1121a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei    public ContactResolver getContactResolver() {
1122a8301e2eb5a083a73f58331279c86e8ec7b11a48Mark Wei        return mContactResolver;
112365b6d180f50922a3393795203cae68a5a2f6a33dMark Wei    }
112465b6d180f50922a3393795203cae68a5a2f6a33dMark Wei
11257c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    /**
11267c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy     * Gets the offset for the given position in the underlying cursor, based on any special views
11277c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy     * that may be above it.
11287c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy     */
11290e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    public int getPositionOffset(int position) {
1130eb145d45c17b08ce09131e84b96350925b3db81aJin Cao        int viewsAbove = mHeaders.size();
11317c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11320e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        position -= viewsAbove;
1133da8b096b6a9128dc7c7e7d4fd46d48f9a594268dMark Wei        for (int i = 0, size = mSpecialViews.size(); i < size; i++) {
113418310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal            final int bidPosition = mSpecialViews.keyAt(i);
113518310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal            // If the view bid for a position above the cursor position,
11360e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy            // it is above the conversation.
11370e8dc84326ad3e6d146a203538665f98dd98f688Scott Kennedy            if (bidPosition <= position) {
113818310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal                viewsAbove++;
11397c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            }
11407c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
11417c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
114218310f861218587fd8c5a5b270a20f29380af462Vikram Aggarwal        return viewsAbove;
11437c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
11447c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy
11450e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    /**
11460e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao     * Gets the correct position for special views given the number of headers we have.
11470e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao     */
11480e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    private int getSpecialViewsPos(final int position) {
11490e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao        return position - mHeaders.size();
11500e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao    }
11510e424db6bc5cfbb7f8d980fb9d184f0835bb1fe3Jin Cao
11527c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    public void cleanup() {
11531c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Clean up teaser views.
115437a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView view : mFleetingViews) {
11557c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy            view.cleanup();
11567c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy        }
11577c8325de829ca029ce4547e4f0fa266124301367Scott Kennedy    }
1158fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang
1159fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang    public void onConversationSelected() {
11601c2676be24de6e490a149aeea0cf0f4499887751Scott Kennedy        // Notify teaser views.
116137a20ca39be842b4b4cb54d5b5ed418d49d950cfVikram Aggarwal        for (final ConversationSpecialItemView specialView : mFleetingViews) {
1162fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang            specialView.onConversationSelected();
1163fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang        }
1164fe8e081d6230f343dc74b45d69e5f4634a332b5aAlice Yang    }
11652f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein
11662f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein    public void onCabModeEntered() {
1167a2f1922c41eb5a01f1972c49ab80019a72f1aa0fAndrew Sapperstein        for (final ConversationSpecialItemView specialView : mFleetingViews) {
11682f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein            specialView.onCabModeEntered();
11692f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein        }
11702f542873183b37fa38a0d468f46bbfebc1f537e2Andrew Sapperstein    }
117179c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang
1172cc139833bc5829ba70244519e9870de783c41848Scott Kennedy    public void onCabModeExited() {
1173cc139833bc5829ba70244519e9870de783c41848Scott Kennedy        for (final ConversationSpecialItemView specialView : mFleetingViews) {
1174cc139833bc5829ba70244519e9870de783c41848Scott Kennedy            specialView.onCabModeExited();
1175cc139833bc5829ba70244519e9870de783c41848Scott Kennedy        }
1176cc139833bc5829ba70244519e9870de783c41848Scott Kennedy    }
1177cc139833bc5829ba70244519e9870de783c41848Scott Kennedy
117832ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    public void onConversationListVisibilityChanged(final boolean visible) {
117932ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        for (final ConversationSpecialItemView specialView : mFleetingViews) {
118032ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy            specialView.onConversationListVisibilityChanged(visible);
118132ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        }
118232ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    }
118332ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy
1184f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy    public int getViewMode() {
1185f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy        return mActivity.getViewMode().getMode();
1186f45e0e7f65eb421fc5c2acf7bb76a714e12dc68bScott Kennedy    }
118759bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy
118859bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy    public boolean isInCabMode() {
118959bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy        // If we have conversation in our selected set, we're in CAB mode
119059bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy        return !mBatchConversations.isEmpty();
119159bd7d331b38322dbe760be7a96c84ea832406c4Scott Kennedy    }
119232ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy
119332ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    public void saveSpecialItemInstanceState(final Bundle outState) {
119432ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        for (final ConversationSpecialItemView specialView : mFleetingViews) {
119532ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy            specialView.saveInstanceState(outState);
119632ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy        }
119732ddb84f2d4f53bfc4b53656461068c0c69d6325Scott Kennedy    }
11987ed53776a053782ca37303075c144926647ac557Paul Westbrook}
1199