SwipeableListView.java revision 4485ade4b8c949a222f8b98650a9a48d074dc87e
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;
2669b440141f402669fe44dfd8924a94fd22ebccf7mindypimport android.widget.AbsListView;
2769b440141f402669fe44dfd8924a94fd22ebccf7mindypimport android.widget.AbsListView.OnScrollListener;
28f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.view.MotionEvent;
29f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.view.View;
30f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereiraimport android.view.ViewConfiguration;
31f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport android.widget.ListView;
32f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
33f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.R;
34bf232c3735f65b1a4746943e4a134e59e36f0bdePaul Westbrookimport com.android.mail.browse.ConversationCursor;
35f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.browse.ConversationItemView;
361ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereiraimport com.android.mail.browse.SwipeableConversationItemView;
37f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.providers.Conversation;
3806642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereiraimport com.android.mail.providers.Folder;
39b2033d855ab0f13e253e5403ce25989bcbc49488Andy Huangimport com.android.mail.providers.FolderList;
40f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport com.android.mail.ui.SwipeHelper.Callback;
41b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrookimport com.android.mail.utils.LogTag;
42b0219eb7b77212902a38821c050922ac73a68250Mindy Pereiraimport com.android.mail.utils.LogUtils;
437517e3b61b898a57f19be0671f70d58a82224643Andy Huangimport com.android.mail.utils.Utils;
44f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
45866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereiraimport java.util.ArrayList;
46f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereiraimport java.util.Collection;
478db7e407109532557718c6b8064792f2df7a073dMindy Pereiraimport java.util.HashMap;
48f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
4969b440141f402669fe44dfd8924a94fd22ebccf7mindyppublic class SwipeableListView extends ListView implements Callback, OnScrollListener {
50f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    private SwipeHelper mSwipeHelper;
51ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    private boolean mEnableSwipe = false;
52489dd22c64c718b6953b4bd6acef925e82c53c87Andy Huang
53b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook    public static final String LOG_TAG = LogTag.getLogTag();
54f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
55866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    private ConversationSelectionSet mConvSelectionSet;
566c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    private int mSwipeAction;
5706642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    private Folder mFolder;
589365a826b46b0e274df88e92534f7d871eef2aa2mindyp    private ListItemSwipedListener mSwipedListener;
5969b440141f402669fe44dfd8924a94fd22ebccf7mindyp    private boolean mScrolling;
60866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
614485ade4b8c949a222f8b98650a9a48d074dc87eVikram Aggarwal    // Instantiated through view inflation
624485ade4b8c949a222f8b98650a9a48d074dc87eVikram Aggarwal    @SuppressWarnings("unused")
63f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context) {
64f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        this(context, null);
65f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
66f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
67f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context, AttributeSet attrs) {
68f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        this(context, attrs, -1);
69f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
70f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
71f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public SwipeableListView(Context context, AttributeSet attrs, int defStyle) {
72f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        super(context, attrs, defStyle);
73f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        float densityScale = getResources().getDisplayMetrics().density;
74f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float pagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
756f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
766f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira                pagingTouchSlop);
7769b440141f402669fe44dfd8924a94fd22ebccf7mindyp        setOnScrollListener(this);
78f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
79f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
80f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    @Override
81f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    protected void onConfigurationChanged(Configuration newConfig) {
82f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        super.onConfigurationChanged(newConfig);
83f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float densityScale = getResources().getDisplayMetrics().density;
84f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        mSwipeHelper.setDensityScale(densityScale);
85f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
86f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira        mSwipeHelper.setPagingTouchSlop(pagingTouchSlop);
87f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira    }
88f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira
897517e3b61b898a57f19be0671f70d58a82224643Andy Huang    @Override
907517e3b61b898a57f19be0671f70d58a82224643Andy Huang    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
91bc88f16af48d9538b79cbeab88cd275cb769a67dVikram Aggarwal        LogUtils.d(Utils.VIEW_DEBUGGING_TAG,
927517e3b61b898a57f19be0671f70d58a82224643Andy Huang                "START CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s",
937517e3b61b898a57f19be0671f70d58a82224643Andy Huang                isLayoutRequested(), getRootView().isLayoutRequested());
947517e3b61b898a57f19be0671f70d58a82224643Andy Huang        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
95bc88f16af48d9538b79cbeab88cd275cb769a67dVikram Aggarwal        LogUtils.d(Utils.VIEW_DEBUGGING_TAG, new Error(),
967517e3b61b898a57f19be0671f70d58a82224643Andy Huang                "FINISH CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s",
977517e3b61b898a57f19be0671f70d58a82224643Andy Huang                isLayoutRequested(), getRootView().isLayoutRequested());
987517e3b61b898a57f19be0671f70d58a82224643Andy Huang    }
997517e3b61b898a57f19be0671f70d58a82224643Andy Huang
100ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    /**
101ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira     * Enable swipe gestures.
102ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira     */
103ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    public void enableSwipe(boolean enable) {
104ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira        mEnableSwipe = enable;
105ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira    }
106ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira
1076c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void setSwipeAction(int action) {
1086c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        mSwipeAction = action;
109f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
110f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
1119365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public void setSwipedListener(ListItemSwipedListener listener) {
1129365a826b46b0e274df88e92534f7d871eef2aa2mindyp        mSwipedListener = listener;
1139365a826b46b0e274df88e92534f7d871eef2aa2mindyp    }
1149365a826b46b0e274df88e92534f7d871eef2aa2mindyp
115de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira    public int getSwipeAction() {
116de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira        return mSwipeAction;
117de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira    }
118de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira
119866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public void setSelectionSet(ConversationSelectionSet set) {
120866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        mConvSelectionSet = set;
121866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
122866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
12306642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    public void setCurrentFolder(Folder folder) {
12406642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira        mFolder = folder;
12506642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira    }
12606642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira
127866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    @Override
128866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    public ConversationSelectionSet getSelectionSet() {
129866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira        return mConvSelectionSet;
130866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira    }
131866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
132f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
133f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public boolean onInterceptTouchEvent(MotionEvent ev) {
13469b440141f402669fe44dfd8924a94fd22ebccf7mindyp        if (mScrolling || !mEnableSwipe) {
13519bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return super.onInterceptTouchEvent(ev);
13669b440141f402669fe44dfd8924a94fd22ebccf7mindyp        } else {
13769b440141f402669fe44dfd8924a94fd22ebccf7mindyp            return mSwipeHelper.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
13819bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        }
139f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
140f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
141f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
142f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public boolean onTouchEvent(MotionEvent ev) {
143ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira        if (mEnableSwipe) {
14419bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return mSwipeHelper.onTouchEvent(ev) || super.onTouchEvent(ev);
14519bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        } else {
14619bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira            return super.onTouchEvent(ev);
14719bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira        }
148f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
149f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
150f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
151f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public View getChildAtPosition(MotionEvent ev) {
152f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // find the view under the pointer, accounting for GONE views
153f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        final int count = getChildCount();
154f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        int touchY = (int) ev.getY();
155f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        int childIdx = 0;
156f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        View slidingChild;
157f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        for (; childIdx < count; childIdx++) {
158f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            slidingChild = getChildAt(childIdx);
159f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            if (slidingChild.getVisibility() == GONE) {
160f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira                continue;
161f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira            }
162866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            if (touchY >= slidingChild.getTop() && touchY <= slidingChild.getBottom()) {
1631ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                if (slidingChild instanceof SwipeableConversationItemView) {
1641ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                    return ((SwipeableConversationItemView) slidingChild).getSwipeableItemView();
1651ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira                }
166866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira                return slidingChild;
167866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira            }
168f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        }
169f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        return null;
170f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
171f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
172f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
1736c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public boolean canChildBeDismissed(SwipeableItemView v) {
174a538984fcc19e7624f2650b119ede39bf1f35846mindyp        return v.canChildBeDismissed();
175f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
176f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
177f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
1786c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void onChildDismissed(SwipeableItemView v) {
1790760bfbf8259e4161ce7737fc980b6b9297885ccmindyp        if (v != null) {
1800760bfbf8259e4161ce7737fc980b6b9297885ccmindyp            v.dismiss();
1810760bfbf8259e4161ce7737fc980b6b9297885ccmindyp        }
182f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
183f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
1848937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    // Call this whenever a new action is taken; this forces a commit of any
1858937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    // existing destructive actions.
186c6adce3cf6887c4c6dd5005724565702751843d0mindyp    public void commitDestructiveActions(boolean animate) {
1870fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
1888937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        if (adapter != null) {
189c6adce3cf6887c4c6dd5005724565702751843d0mindyp            adapter.commitLeaveBehindItems(animate);
1908937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira        }
1918937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    }
1928937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira
193a538984fcc19e7624f2650b119ede39bf1f35846mindyp    public void dismissChild(final ConversationItemView target) {
194d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira        final ToastBarOperation undoOp;
195866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira
1966a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy        undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false /* batch */,
1976a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy                mFolder);
1986c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        Conversation conv = target.getConversation();
19913e6243683cc8cb998a43d06f25d6ff1aab9d93bMindy Pereira        target.getConversation().position = findConversation(target, conv);
2000fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        final AnimatedAdapter adapter = getAnimatedAdapter();
20109f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira        if (adapter == null) {
20209f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira            return;
20309f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira        }
2046c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        adapter.setupLeaveBehind(conv, undoOp, conv.position);
20500ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        ConversationCursor cc = (ConversationCursor) adapter.getCursor();
2069365a826b46b0e274df88e92534f7d871eef2aa2mindyp        Collection<Conversation> convList = Conversation.listOf(conv);
2075cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp        ArrayList<Uri> folderUris;
2085cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp        ArrayList<Boolean> adds;
2096c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        switch (mSwipeAction) {
21001f30509c4c8ad0d13b7635447b7f023c7a0cab7Mindy Pereira            case R.id.remove_folder:
2118db7e407109532557718c6b8064792f2df7a073dMindy Pereira                FolderOperation folderOp = new FolderOperation(mFolder, false);
2128db7e407109532557718c6b8064792f2df7a073dMindy Pereira                HashMap<Uri, Folder> targetFolders = Folder
21368f83843e821d9627a53f68244dbc4cb26662edcMindy Pereira                        .hashMapForFolders(conv.getRawFolders());
2148db7e407109532557718c6b8064792f2df7a073dMindy Pereira                targetFolders.remove(folderOp.mFolder.uri);
215b2033d855ab0f13e253e5403ce25989bcbc49488Andy Huang                final FolderList folders = FolderList.copyOf(targetFolders.values());
216b2033d855ab0f13e253e5403ce25989bcbc49488Andy Huang                conv.setRawFolders(folders);
217b2033d855ab0f13e253e5403ce25989bcbc49488Andy Huang                final ContentValues values = new ContentValues();
2185cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp                folderUris = new ArrayList<Uri>();
2195cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp                folderUris.add(mFolder.uri);
2205cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp                adds = new ArrayList<Boolean>();
2215cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp                adds.add(Boolean.FALSE);
2229e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy                ConversationCursor.addFolderUpdates(folderUris, adds, values);
2239e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy                ConversationCursor.addTargetFolders(targetFolders.values(), values);
2249e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy                cc.mostlyDestructiveUpdate(Conversation.listOf(conv), values);
22506642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira                break;
2266c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            case R.id.archive:
2279e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy                cc.mostlyArchive(convList);
2286c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                break;
2296c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira            case R.id.delete:
2309e2d407fdafeb874e640eb84017feaf784309075Scott Kennedy                cc.mostlyDelete(convList);
2316c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira                break;
2326c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        }
2339365a826b46b0e274df88e92534f7d871eef2aa2mindyp        if (mSwipedListener != null) {
2349365a826b46b0e274df88e92534f7d871eef2aa2mindyp            mSwipedListener.onListItemSwiped(convList);
2359365a826b46b0e274df88e92534f7d871eef2aa2mindyp        }
2366c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira        adapter.notifyDataSetChanged();
237a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira        if (mConvSelectionSet != null && !mConvSelectionSet.isEmpty()
238a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira                && mConvSelectionSet.contains(conv)) {
239a8ead90ce1e6c66e4ecacdf7cfa25c2cafc9bb3bMindy Pereira            mConvSelectionSet.toggle(null, conv);
24054f120f6ada40c7191811dfff99b151e9e192c78mindyp            // Don't commit destructive actions if the item we just removed from
24154f120f6ada40c7191811dfff99b151e9e192c78mindyp            // the selection set is the item we just destroyed!
24254f120f6ada40c7191811dfff99b151e9e192c78mindyp            if (!conv.isMostlyDead() && mConvSelectionSet.isEmpty()) {
24354f120f6ada40c7191811dfff99b151e9e192c78mindyp                commitDestructiveActions(true);
24454f120f6ada40c7191811dfff99b151e9e192c78mindyp            }
245cff4a2b2e92258c6c85ed4af15bc13101aa71170Mindy Pereira        }
246f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
247f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
248f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
249f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    public void onBeginDrag(View v) {
250f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // We do this so the underlying ScrollView knows that it won't get
251f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        // the chance to intercept events anymore
252f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira        requestDisallowInterceptTouchEvent(true);
2531ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        SwipeableConversationItemView view = null;
2541ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        if (v instanceof ConversationItemView) {
25500ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira            view = (SwipeableConversationItemView) v.getParent();
2561ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        }
2571ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        if (view != null) {
25884f9b5c60dc023570202859ba1d30cf9cb5e6e7aMindy Pereira            view.addBackground(getContext());
2591ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira            view.setBackgroundVisibility(View.VISIBLE);
2601ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira        }
2613b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        cancelDismissCounter();
262f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
263f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
264f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    @Override
2656c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira    public void onDragCancelled(SwipeableItemView v) {
266709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        SwipeableConversationItemView view = null;
267709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        if (v instanceof ConversationItemView) {
26800ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira            view = (SwipeableConversationItemView) ((View) v).getParent();
269709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        }
270709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        if (view != null) {
271709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira            view.removeBackground();
272709a174a40ec296c40368d723c2f51e3fc48ed50Mindy Pereira        }
2733b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        final AnimatedAdapter adapter = getAnimatedAdapter();
2743b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (adapter != null) {
2753b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            adapter.startDismissCounter();
2764d4531a63cff536d2ee1a2929d0820981df8516amindyp            adapter.cancelFadeOutLastLeaveBehindItemText();
2773b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        }
278f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira    }
279f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira
28007118a01f7183645957010779222b84930f75b4eMindy Pereira    /**
28107118a01f7183645957010779222b84930f75b4eMindy Pereira     * Archive items using the swipe away animation before shrinking them away.
28207118a01f7183645957010779222b84930f75b4eMindy Pereira     */
283cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook    public boolean destroyItems(Collection<Conversation> convs,
28484f7d32bdc79263004ed5241480988e02f8e618cmindyp            final ListItemsRemovedListener listener) {
28584f7d32bdc79263004ed5241480988e02f8e618cmindyp        if (convs == null) {
286cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook            LogUtils.e(LOG_TAG, "SwipeableListView.destroyItems: null conversations.");
287cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook            return false;
28884f7d32bdc79263004ed5241480988e02f8e618cmindyp        }
289a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal        final AnimatedAdapter adapter = getAnimatedAdapter();
290a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal        if (adapter == null) {
291a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal            LogUtils.e(LOG_TAG, "SwipeableListView.destroyItems: Cannot destroy: adapter is null.");
292cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook            return false;
293067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
29484f7d32bdc79263004ed5241480988e02f8e618cmindyp        adapter.swipeDelete(convs, listener);
295cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook        return true;
296067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira    }
297067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira
298cc2f9296ad63ed681c200feb118c5caace36e72emindyp    public int findConversation(ConversationItemView view, Conversation conv) {
299067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        int position = conv.position;
300067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        long convId = conv.id;
301067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        try {
302067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            if (position == INVALID_POSITION) {
303067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                position = getPositionForView(view);
304067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            }
305067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        } catch (Exception e) {
306067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            position = INVALID_POSITION;
307067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            LogUtils.w(LOG_TAG, "Exception finding position; using alternate strategy");
308067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        }
309067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        if (position == INVALID_POSITION) {
310067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            // Try the other way!
311067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            Conversation foundConv;
312067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            long foundId;
313067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            for (int i = 0; i < getChildCount(); i++) {
314067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                View child = getChildAt(i);
315067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                if (child instanceof SwipeableConversationItemView) {
316067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    foundConv = ((SwipeableConversationItemView) child).getSwipeableItemView()
317067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                            .getConversation();
318067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    foundId = foundConv.id;
319067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    if (foundId == convId) {
320067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                        position = i;
321067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                        break;
322067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                    }
323067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira                }
324067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira            }
325c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira        }
326067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira        return position;
32707118a01f7183645957010779222b84930f75b4eMindy Pereira    }
32807118a01f7183645957010779222b84930f75b4eMindy Pereira
3290fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira    private AnimatedAdapter getAnimatedAdapter() {
3300fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira        return (AnimatedAdapter) getAdapter();
3310fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira    }
3320fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira
3338937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    @Override
3348937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    public boolean performItemClick(View view, int pos, long id) {
335dd9d3a16148b178cb95fd4db4168a67c64eb944fMindy Pereira        boolean handled = super.performItemClick(view, pos, id);
33600ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        // Commit any existing destructive actions when the user selects a
33700ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira        // conversation to view.
338c6adce3cf6887c4c6dd5005724565702751843d0mindyp        commitDestructiveActions(true);
339dd9d3a16148b178cb95fd4db4168a67c64eb944fMindy Pereira        return handled;
3408937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira    }
3415254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp
3425254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    @Override
343d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp    public void onScroll() {
344d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp        commitDestructiveActions(true);
3455254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp    }
3469365a826b46b0e274df88e92534f7d871eef2aa2mindyp
3479365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public interface ListItemsRemovedListener {
3489365a826b46b0e274df88e92534f7d871eef2aa2mindyp        public void onListItemsRemoved();
3499365a826b46b0e274df88e92534f7d871eef2aa2mindyp    }
3509365a826b46b0e274df88e92534f7d871eef2aa2mindyp
3519365a826b46b0e274df88e92534f7d871eef2aa2mindyp    public interface ListItemSwipedListener {
3529365a826b46b0e274df88e92534f7d871eef2aa2mindyp        public void onListItemSwiped(Collection<Conversation> conversations);
3539365a826b46b0e274df88e92534f7d871eef2aa2mindyp    }
35469b440141f402669fe44dfd8924a94fd22ebccf7mindyp
35569b440141f402669fe44dfd8924a94fd22ebccf7mindyp    @Override
35669b440141f402669fe44dfd8924a94fd22ebccf7mindyp    public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
35769b440141f402669fe44dfd8924a94fd22ebccf7mindyp        // Do nothing.
35869b440141f402669fe44dfd8924a94fd22ebccf7mindyp    }
35969b440141f402669fe44dfd8924a94fd22ebccf7mindyp
36069b440141f402669fe44dfd8924a94fd22ebccf7mindyp    @Override
36169b440141f402669fe44dfd8924a94fd22ebccf7mindyp    public void onScrollStateChanged(AbsListView arg0, int scrollState) {
36269b440141f402669fe44dfd8924a94fd22ebccf7mindyp        switch (scrollState) {
36369b440141f402669fe44dfd8924a94fd22ebccf7mindyp            case OnScrollListener.SCROLL_STATE_IDLE:
36469b440141f402669fe44dfd8924a94fd22ebccf7mindyp                mScrolling = false;
36569b440141f402669fe44dfd8924a94fd22ebccf7mindyp                break;
36669b440141f402669fe44dfd8924a94fd22ebccf7mindyp            default:
36769b440141f402669fe44dfd8924a94fd22ebccf7mindyp                mScrolling = true;
36869b440141f402669fe44dfd8924a94fd22ebccf7mindyp        }
36969b440141f402669fe44dfd8924a94fd22ebccf7mindyp    }
3703b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp
3713b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    @Override
3723b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    public void cancelDismissCounter() {
3733b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        AnimatedAdapter adapter = getAnimatedAdapter();
3743b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        if (adapter != null) {
3753b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp            adapter.cancelDismissCounter();
3763b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp        }
3773b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp    }
3787af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp
3797af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    @Override
3807af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    public LeaveBehindItem getLastSwipedItem() {
3817af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        AnimatedAdapter adapter = getAnimatedAdapter();
3827af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        if (adapter != null) {
3837af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp            return adapter.getLastLeaveBehindItem();
3847af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        }
3857af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp        return null;
3867af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp    }
38700ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira}
388