1f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira/*
2f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Copyright (C) 2012 Google Inc.
3f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Licensed to The Android Open Source Project.
4f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *
5f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License");
6f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * you may not use this file except in compliance with the License.
7f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * You may obtain a copy of the License at
8f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *
9f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *      http://www.apache.org/licenses/LICENSE-2.0
10f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira *
11f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * Unless required by applicable law or agreed to in writing, software
12f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS,
13f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * See the License for the specific language governing permissions and
15f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira * limitations under the License.
16f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira */
17f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
18f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereirapackage com.android.mail.ui;
19f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
20b2033d855ab0f13e253e5403ce25989bcbc49488Andy Huangimport android.content.ContentValues;
21f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.content.Context;
22f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereiraimport android.content.res.Configuration;
237517e3b61b898a57f19be0671f70d58a82224643Andy Huangimport android.graphics.Rect;
248db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport android.net.Uri;
25f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.util.AttributeSet;
26f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.view.MotionEvent;
27f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.view.View;
28f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereiraimport android.view.ViewConfiguration;
297c411aafd9ef059f881b7532426e61d1def54a07Andrew Sappersteinimport android.widget.AbsListView;
307c411aafd9ef059f881b7532426e61d1def54a07Andrew Sappersteinimport android.widget.AbsListView.OnScrollListener;
31f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.widget.ListView;
32f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
33f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.R;
34042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huangimport com.android.mail.analytics.Analytics;
35bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.browse.ConversationCursor;
36f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.browse.ConversationItemView;
371ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereiraimport com.android.mail.browse.SwipeableConversationItemView;
386126d72ae2769bd39451872f45781cadb5b90515Mark Weiimport com.android.mail.providers.Account;
39f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.providers.Conversation;
4006642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereiraimport com.android.mail.providers.Folder;
41b2033d855ab0f13e253e5403ce25989bcbc49488Andy Huangimport com.android.mail.providers.FolderList;
42f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.ui.SwipeHelper.Callback;
43b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
44b0219eb7b77212902a38821c050922ac73a68250Mindy Pereiraimport com.android.mail.utils.LogUtils;
457517e3b61b898a57f19be0671f70d58a82224643Andy Huangimport com.android.mail.utils.Utils;
46f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
47866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport java.util.ArrayList;
48f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport java.util.Collection;
498db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport java.util.HashMap;
50f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
5169b440141f402669fe44dfd8924a94fd22ebccf7mindyppublic class SwipeableListView extends ListView implements Callback, OnScrollListener {
52f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    private static final long INVALID_CONVERSATION_ID = -1;
53f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao
546126d72ae2769bd39451872f45781cadb5b90515Mark Wei    private final SwipeHelper mSwipeHelper;
55f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    /**
56f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     * Are swipes enabled on all items? (Each individual item can still prevent swiping.)<br>
57f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     * When swiping is disabled, the UI still reacts to the gesture to acknowledge it.
58f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     */
59ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    private boolean mEnableSwipe = false;
60f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    /**
61f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     * When set, we prevent the SwipeHelper from kicking in at all. This
62f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     * short-circuits {@link #mEnableSwipe}.
63f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     */
64f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    private boolean mPreventSwipesEntirely = false;
65489dd22c64c718b6953b4bd6acef925e82c53c87Andy Huang
66b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    public static final String LOG_TAG = LogTag.getLogTag();
6752a61db87c487fe5bb7cc673037887a6d35b0f0fMark Wei
68ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    private ConversationCheckedSet mConvCheckedSet;
696c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private int mSwipeAction;
706126d72ae2769bd39451872f45781cadb5b90515Mark Wei    private Account mAccount;
7106642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    private Folder mFolder;
729365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private ListItemSwipedListener mSwipedListener;
7369b440141f402669fe44dfd8924a94fd22ebccf7mindyp    private boolean mScrolling;
74866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
75e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang    private SwipeListener mSwipeListener;
76e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang
77f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    private long mSelectedConversationId = INVALID_CONVERSATION_ID;
780532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao
794485ade4b8c949a222f8b98650a9a48d074dc87eVikram Aggarwal    // Instantiated through view inflation
804485ade4b8c949a222f8b98650a9a48d074dc87eVikram Aggarwal    @SuppressWarnings("unused")
81f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context) {
82f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        this(context, null);
83f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
84f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
85f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context, AttributeSet attrs) {
86f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        this(context, attrs, -1);
87f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
88f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
89f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context, AttributeSet attrs, int defStyle) {
90f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        super(context, attrs, defStyle);
91f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        float densityScale = getResources().getDisplayMetrics().density;
92f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float pagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
936f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
946f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira                pagingTouchSlop);
95f9fd2cf057d845c7b081a3f17482dd0b886179d1Rohan Shah        mScrolling = false;
96f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
97f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
98f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    @Override
99f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    protected void onConfigurationChanged(Configuration newConfig) {
100f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        super.onConfigurationChanged(newConfig);
101f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float densityScale = getResources().getDisplayMetrics().density;
102f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        mSwipeHelper.setDensityScale(densityScale);
103f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
104f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
105f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    }
106f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira
1077517e3b61b898a57f19be0671f70d58a82224643Andy Huang    @Override
1087517e3b61b898a57f19be0671f70d58a82224643Andy Huang    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
109bc88f16af48d9538b79cbeab88cd275cb769a67dVikram Aggarwal        LogUtils.d(Utils.VIEW_DEBUGGING_TAG,
1107517e3b61b898a57f19be0671f70d58a82224643Andy Huang                "START CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s",
1117517e3b61b898a57f19be0671f70d58a82224643Andy Huang                isLayoutRequested(), getRootView().isLayoutRequested());
1127517e3b61b898a57f19be0671f70d58a82224643Andy Huang        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
113bc88f16af48d9538b79cbeab88cd275cb769a67dVikram Aggarwal        LogUtils.d(Utils.VIEW_DEBUGGING_TAG, new Error(),
1147517e3b61b898a57f19be0671f70d58a82224643Andy Huang                "FINISH CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s",
1157517e3b61b898a57f19be0671f70d58a82224643Andy Huang                isLayoutRequested(), getRootView().isLayoutRequested());
1167517e3b61b898a57f19be0671f70d58a82224643Andy Huang    }
1177517e3b61b898a57f19be0671f70d58a82224643Andy Huang
118ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    /**
119ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira     * Enable swipe gestures.
120ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira     */
121ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    public void enableSwipe(boolean enable) {
122ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira        mEnableSwipe = enable;
123ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    }
124ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira
125f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    /**
126f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     * Completely ignore any horizontal swiping gestures.
127f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     */
128f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    public void preventSwipesEntirely() {
129f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang        mPreventSwipesEntirely = true;
130f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    }
131f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang
132f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    /**
133f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     * Reverses a prior call to {@link #preventSwipesEntirely()}.
134f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang     */
135f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    public void stopPreventingSwipes() {
136f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang        mPreventSwipesEntirely = false;
137f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang    }
138f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang
1396c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void setSwipeAction(int action) {
1406c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        mSwipeAction = action;
141f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
142f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
1437c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein    public void setListItemSwipedListener(ListItemSwipedListener listener) {
1449365a826b46b0e274df88e92534f7d871eef2aa2mindyp        mSwipedListener = listener;
1459365a826b46b0e274df88e92534f7d871eef2aa2mindyp    }
1469365a826b46b0e274df88e92534f7d871eef2aa2mindyp
147de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira    public int getSwipeAction() {
148de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira        return mSwipeAction;
149de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira    }
150de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira
151ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    public void setCheckedSet(ConversationCheckedSet set) {
152ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        mConvCheckedSet = set;
153866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
154866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1556126d72ae2769bd39451872f45781cadb5b90515Mark Wei    public void setCurrentAccount(Account account) {
1566126d72ae2769bd39451872f45781cadb5b90515Mark Wei        mAccount = account;
1576126d72ae2769bd39451872f45781cadb5b90515Mark Wei    }
1586126d72ae2769bd39451872f45781cadb5b90515Mark Wei
15906642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    public void setCurrentFolder(Folder folder) {
16006642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira        mFolder = folder;
16106642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    }
16206642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira
163866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    @Override
164ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao    public ConversationCheckedSet getCheckedSet() {
165ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        return mConvCheckedSet;
166866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
167866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
168f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
169f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public boolean onInterceptTouchEvent(MotionEvent ev) {
1703432b636fbcf7d6cc551b9705ed4dd88ae2b4f49Jin Cao        if (mScrolling) {
17119bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return super.onInterceptTouchEvent(ev);
17269b440141f402669fe44dfd8924a94fd22ebccf7mindyp        } else {
173f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang            return (!mPreventSwipesEntirely && mSwipeHelper.onInterceptTouchEvent(ev))
174f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang                    || super.onInterceptTouchEvent(ev);
17519bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        }
176f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
177f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
178f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
179f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public boolean onTouchEvent(MotionEvent ev) {
180f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang        return (!mPreventSwipesEntirely && mSwipeHelper.onTouchEvent(ev)) || super.onTouchEvent(ev);
181f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
182f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
183f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
184f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public View getChildAtPosition(MotionEvent ev) {
185f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // find the view under the pointer, accounting for GONE views
186f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        final int count = getChildCount();
187f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal        final int touchY = (int) ev.getY();
188f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        int childIdx = 0;
189f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        View slidingChild;
190f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        for (; childIdx < count; childIdx++) {
191f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            slidingChild = getChildAt(childIdx);
192f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            if (slidingChild.getVisibility() == GONE) {
193f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira                continue;
194f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            }
195866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            if (touchY >= slidingChild.getTop() && touchY <= slidingChild.getBottom()) {
1961ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                if (slidingChild instanceof SwipeableConversationItemView) {
1971ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                    return ((SwipeableConversationItemView) slidingChild).getSwipeableItemView();
1981ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                }
199866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                return slidingChild;
200866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            }
201f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        }
202f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        return null;
203f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
204f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
205f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
2066c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public boolean canChildBeDismissed(SwipeableItemView v) {
2073432b636fbcf7d6cc551b9705ed4dd88ae2b4f49Jin Cao        return mEnableSwipe && v.canChildBeDismissed();
208f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
209f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
210f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
2116c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void onChildDismissed(SwipeableItemView v) {
2120760bfbf8259e4161ce7737fc980b6b9297885ccmindyp        if (v != null) {
2130760bfbf8259e4161ce7737fc980b6b9297885ccmindyp            v.dismiss();
2140760bfbf8259e4161ce7737fc980b6b9297885ccmindyp        }
215f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
216f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
2178937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    // Call this whenever a new action is taken; this forces a commit of any
2188937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    // existing destructive actions.
219c6adce3cf6887c4c6dd5005724565702751843d0mindyp    public void commitDestructiveActions(boolean animate) {
2200fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
2218937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        if (adapter != null) {
222c6adce3cf6887c4c6dd5005724565702751843d0mindyp            adapter.commitLeaveBehindItems(animate);
2238937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        }
2248937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    }
2258937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira
226a538984fcc19e7624f2650b119ede39bf1f35846mindyp    public void dismissChild(final ConversationItemView target) {
2277c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        // Notifies the SwipeListener that a swipe has ended.
2287c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        if (mSwipeListener != null) {
2297c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein            mSwipeListener.onEndSwipe();
2307c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        }
2317c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein
232d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        final ToastBarOperation undoOp;
233866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
2346a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy        undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false /* batch */,
2356a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy                mFolder);
2366c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        Conversation conv = target.getConversation();
23713e6243683cc8cb998a43d06f25d6ff1aab9d93bMindy Pereira        target.getConversation().position = findConversation(target, conv);
2380fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
23909f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira        if (adapter == null) {
24009f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira            return;
24109f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira        }
242370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang        adapter.setupLeaveBehind(conv, undoOp, conv.position, target.getHeight());
24300ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        ConversationCursor cc = (ConversationCursor) adapter.getCursor();
2449365a826b46b0e274df88e92534f7d871eef2aa2mindyp        Collection<Conversation> convList = Conversation.listOf(conv);
2455cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp        ArrayList<Uri> folderUris;
2465cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp        ArrayList<Boolean> adds;
247042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
2482b55549d4fbe25e91f673a0727fc89ff755d9327Andy Huang        Analytics.getInstance().sendMenuItemEvent("list_swipe", mSwipeAction, null, 0);
249042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang
2502b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        if (mSwipeAction == R.id.remove_folder) {
2512b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            FolderOperation folderOp = new FolderOperation(mFolder, false);
2522b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            HashMap<Uri, Folder> targetFolders = Folder
2532b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy                    .hashMapForFolders(conv.getRawFolders());
2542b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            targetFolders.remove(folderOp.mFolder.folderUri.fullUri);
2552b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final FolderList folders = FolderList.copyOf(targetFolders.values());
2562b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            conv.setRawFolders(folders);
2572b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            final ContentValues values = new ContentValues();
2582b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            folderUris = new ArrayList<Uri>();
2592b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            folderUris.add(mFolder.folderUri.fullUri);
2602b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            adds = new ArrayList<Boolean>();
2612b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            adds.add(Boolean.FALSE);
2622b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ConversationCursor.addFolderUpdates(folderUris, adds, values);
2632b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            ConversationCursor.addTargetFolders(targetFolders.values(), values);
2642b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            cc.mostlyDestructiveUpdate(Conversation.listOf(conv), values);
2652b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (mSwipeAction == R.id.archive) {
2662b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            cc.mostlyArchive(convList);
2672b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy        } else if (mSwipeAction == R.id.delete) {
2682b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy            cc.mostlyDelete(convList);
269512821c11d89d49908f3cfdee0b582601f500f3dJin Cao        } else if (mSwipeAction == R.id.discard_outbox) {
270512821c11d89d49908f3cfdee0b582601f500f3dJin Cao            cc.moveFailedIntoDrafts(convList);
2716c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        }
2729365a826b46b0e274df88e92534f7d871eef2aa2mindyp        if (mSwipedListener != null) {
2739365a826b46b0e274df88e92534f7d871eef2aa2mindyp            mSwipedListener.onListItemSwiped(convList);
2749365a826b46b0e274df88e92534f7d871eef2aa2mindyp        }
2756c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        adapter.notifyDataSetChanged();
276ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao        if (mConvCheckedSet != null && !mConvCheckedSet.isEmpty()
277ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao                && mConvCheckedSet.contains(conv)) {
278ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            mConvCheckedSet.toggle(conv);
27954f120f6ada40c7191811dfff99b151e9e192c78mindyp            // Don't commit destructive actions if the item we just removed from
28054f120f6ada40c7191811dfff99b151e9e192c78mindyp            // the selection set is the item we just destroyed!
281ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao            if (!conv.isMostlyDead() && mConvCheckedSet.isEmpty()) {
28254f120f6ada40c7191811dfff99b151e9e192c78mindyp                commitDestructiveActions(true);
28354f120f6ada40c7191811dfff99b151e9e192c78mindyp            }
284cff4a2b2e92258c6c85ed4af15bc13101aa71170Mindy Pereira        }
285f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
286f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
287f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
288f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public void onBeginDrag(View v) {
289f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // We do this so the underlying ScrollView knows that it won't get
290f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // the chance to intercept events anymore
291f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        requestDisallowInterceptTouchEvent(true);
2923b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        cancelDismissCounter();
293e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang
2947c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        // Notifies the SwipeListener that a swipe has begun.
295e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang        if (mSwipeListener != null) {
296e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang            mSwipeListener.onBeginSwipe();
297e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang        }
298f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
299f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
300f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
3016c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void onDragCancelled(SwipeableItemView v) {
3023b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        final AnimatedAdapter adapter = getAnimatedAdapter();
3033b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (adapter != null) {
3043b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            adapter.startDismissCounter();
3054d4531a63cff536d2ee1a2929d0820981df8516amindyp            adapter.cancelFadeOutLastLeaveBehindItemText();
3063b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        }
3077c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein
3087c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        // Notifies the SwipeListener that a swipe has ended.
3097c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        if (mSwipeListener != null) {
3107c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein            mSwipeListener.onEndSwipe();
3117c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        }
312f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
313f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
31407118a01f7183645957010779222b84930f75b4eMindy Pereira    /**
31507118a01f7183645957010779222b84930f75b4eMindy Pereira     * Archive items using the swipe away animation before shrinking them away.
31607118a01f7183645957010779222b84930f75b4eMindy Pereira     */
317cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook    public boolean destroyItems(Collection<Conversation> convs,
31884f7d32bdc79263004ed5241480988e02f8e618cmindyp            final ListItemsRemovedListener listener) {
31984f7d32bdc79263004ed5241480988e02f8e618cmindyp        if (convs == null) {
320cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook            LogUtils.e(LOG_TAG, "SwipeableListView.destroyItems: null conversations.");
321cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook            return false;
32284f7d32bdc79263004ed5241480988e02f8e618cmindyp        }
323a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal        final AnimatedAdapter adapter = getAnimatedAdapter();
324a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal        if (adapter == null) {
325a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal            LogUtils.e(LOG_TAG, "SwipeableListView.destroyItems: Cannot destroy: adapter is null.");
326cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook            return false;
327067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
32884f7d32bdc79263004ed5241480988e02f8e618cmindyp        adapter.swipeDelete(convs, listener);
329cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook        return true;
330067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
331067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
332cc2f9296ad63ed681c200feb118c5caace36e72emindyp    public int findConversation(ConversationItemView view, Conversation conv) {
333dbb587f15c723ae80edb33f65c29cc2b6c15eba0Scott Kennedy        int position = INVALID_POSITION;
334067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        long convId = conv.id;
335067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        try {
336dbb587f15c723ae80edb33f65c29cc2b6c15eba0Scott Kennedy            position = getPositionForView(view);
337067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        } catch (Exception e) {
338067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            position = INVALID_POSITION;
339599e7f8bf95d2f21a966cbff1bf72adf77a90a33Andy Huang            LogUtils.w(LOG_TAG, e, "Exception finding position; using alternate strategy");
340067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
341067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (position == INVALID_POSITION) {
342067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // Try the other way!
343067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            Conversation foundConv;
344067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            long foundId;
345067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            for (int i = 0; i < getChildCount(); i++) {
346067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                View child = getChildAt(i);
347067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                if (child instanceof SwipeableConversationItemView) {
348067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    foundConv = ((SwipeableConversationItemView) child).getSwipeableItemView()
349067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                            .getConversation();
350067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    foundId = foundConv.id;
351067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    if (foundId == convId) {
352599e7f8bf95d2f21a966cbff1bf72adf77a90a33Andy Huang                        position = i + getFirstVisiblePosition();
353067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                        break;
354067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    }
355067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                }
356067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            }
357c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        }
358067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return position;
35907118a01f7183645957010779222b84930f75b4eMindy Pereira    }
36007118a01f7183645957010779222b84930f75b4eMindy Pereira
3610fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira    private AnimatedAdapter getAnimatedAdapter() {
3620fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        return (AnimatedAdapter) getAdapter();
3630fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira    }
3640fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira
3658937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    @Override
3668937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    public boolean performItemClick(View view, int pos, long id) {
3676126d72ae2769bd39451872f45781cadb5b90515Mark Wei        // Superclass method modifies the selection set
368f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal        final boolean handled = super.performItemClick(view, pos, id);
3696126d72ae2769bd39451872f45781cadb5b90515Mark Wei
37000ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        // Commit any existing destructive actions when the user selects a
37100ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        // conversation to view.
372c6adce3cf6887c4c6dd5005724565702751843d0mindyp        commitDestructiveActions(true);
373dd9d3a16148b178cb95fd4db4168a67c64eb944fMindy Pereira        return handled;
3748937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    }
3755254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp
3765254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    @Override
377d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp    public void onScroll() {
378d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp        commitDestructiveActions(true);
3795254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    }
3809365a826b46b0e274df88e92534f7d871eef2aa2mindyp
3819365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public interface ListItemsRemovedListener {
3829365a826b46b0e274df88e92534f7d871eef2aa2mindyp        public void onListItemsRemoved();
3839365a826b46b0e274df88e92534f7d871eef2aa2mindyp    }
3849365a826b46b0e274df88e92534f7d871eef2aa2mindyp
3859365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public interface ListItemSwipedListener {
3869365a826b46b0e274df88e92534f7d871eef2aa2mindyp        public void onListItemSwiped(Collection<Conversation> conversations);
3879365a826b46b0e274df88e92534f7d871eef2aa2mindyp    }
38869b440141f402669fe44dfd8924a94fd22ebccf7mindyp
38969b440141f402669fe44dfd8924a94fd22ebccf7mindyp    @Override
39079c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang    public final void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
391479505d71969e26b0785d8e0e1b81108731cf827Mark Wei            int totalItemCount) {
39269b440141f402669fe44dfd8924a94fd22ebccf7mindyp    }
39369b440141f402669fe44dfd8924a94fd22ebccf7mindyp
39469b440141f402669fe44dfd8924a94fd22ebccf7mindyp    @Override
39581aea35d45b3d0191ec595562a2fcf67009845d5Mark Wei    public void onScrollStateChanged(final AbsListView view, final int scrollState) {
396479505d71969e26b0785d8e0e1b81108731cf827Mark Wei        mScrolling = scrollState != OnScrollListener.SCROLL_STATE_IDLE;
397479505d71969e26b0785d8e0e1b81108731cf827Mark Wei
39848ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang        if (!mScrolling) {
39948ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang            final Context c = getContext();
40048ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang            if (c instanceof ControllableActivity) {
40148ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang                final ControllableActivity activity = (ControllableActivity) c;
40248ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang                activity.onAnimationEnd(null /* adapter */);
40348ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang            } else {
40448ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang                LogUtils.wtf(LOG_TAG, "unexpected context=%s", c);
40548ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang            }
40648ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang        }
40748ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang    }
40848ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang
40948ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang    public boolean isScrolling() {
41048ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang        return mScrolling;
41169b440141f402669fe44dfd8924a94fd22ebccf7mindyp    }
4123b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp
4130532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    /**
4140532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao     * Set the currently selected (focused by the list view) position.
4150532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao     */
416f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    public void setSelectedConversation(Conversation conv) {
417f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        if (conv == null) {
4180532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao            return;
4190532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao        }
4200532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao
421f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        mSelectedConversationId = conv.id;
422f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    }
423f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao
424f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    public boolean isConversationSelected(Conversation conv) {
425f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        return mSelectedConversationId != INVALID_CONVERSATION_ID && conv != null
426f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                && mSelectedConversationId == conv.id;
4270532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    }
4280532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao
429f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    /**
430f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao     * This is only used for debugging/logging purposes. DO NOT call this function to try to get
431f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao     * the currently selected position. Use {@link #mSelectedConversationId} instead.
432f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao     */
433f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    public int getSelectedConversationPosDebug() {
434f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        for (int i = getFirstVisiblePosition(); i < getLastVisiblePosition(); i++) {
435f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            final Object item = getItemAtPosition(i);
436f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            if (item instanceof ConversationCursor) {
437f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                final Conversation c = ((ConversationCursor) item).getConversation();
438f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                if (c.id == mSelectedConversationId) {
439f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                    return i;
440f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                }
441f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            }
442f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        }
443f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        return ListView.INVALID_POSITION;
4440532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    }
4450532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao
446f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    @Override
447f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao    public void onTouchModeChanged(boolean isInTouchMode) {
448f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        super.onTouchModeChanged(isInTouchMode);
449f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        if (!isInTouchMode) {
450f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            // We need to invalidate going from touch mode -> keyboard mode because the currently
451f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            // selected item might have changed in touch mode. However, since from the framework's
452f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            // perspective the selected position doesn't matter in touch mode, when we enter
453f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            // keyboard mode via up/down arrow, the list view will ONLY invalidate the newly
454f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            // selected item and not the currently selected item. As a result, we might get an
455f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            // inconsistent UI where it looks like both the old and new selected items are focused.
456f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            final int index = getSelectedItemPosition();
457f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            if (index != ListView.INVALID_POSITION) {
458f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                final View child = getChildAt(index - getFirstVisiblePosition());
459f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                if (child != null) {
460f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                    child.invalidate();
461f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao                }
462f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao            }
463f9b96e244e6c6a19cb1920ff129f424997db2727Jin Cao        }
4640532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao    }
4650532b0edb999c6e131bfd1f2e1eccefed049ba49Jin Cao
4663b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    @Override
4673b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    public void cancelDismissCounter() {
4683b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        AnimatedAdapter adapter = getAnimatedAdapter();
4693b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (adapter != null) {
4703b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            adapter.cancelDismissCounter();
4713b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        }
4723b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    }
4737af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp
4747af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    @Override
4757af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    public LeaveBehindItem getLastSwipedItem() {
4767af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        AnimatedAdapter adapter = getAnimatedAdapter();
4777af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        if (adapter != null) {
4787af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp            return adapter.getLastLeaveBehindItem();
4797af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        }
4807af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        return null;
4817af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    }
482e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang
483e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang    public void setSwipeListener(SwipeListener swipeListener) {
484e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang        mSwipeListener = swipeListener;
485e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang    }
486e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang
487e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang    public interface SwipeListener {
488e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang        public void onBeginSwipe();
4897c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein        public void onEndSwipe();
490e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang    }
49100ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira}
492