SwipeableListView.java revision f9fd2cf057d845c7b081a3f17482dd0b886179d1
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 { 526126d72ae2769bd39451872f45781cadb5b90515Mark Wei private final SwipeHelper mSwipeHelper; 53f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang /** 54f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang * Are swipes enabled on all items? (Each individual item can still prevent swiping.)<br> 55f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang * When swiping is disabled, the UI still reacts to the gesture to acknowledge it. 56f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang */ 57ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira private boolean mEnableSwipe = false; 58f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang /** 59f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang * When set, we prevent the SwipeHelper from kicking in at all. This 60f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang * short-circuits {@link #mEnableSwipe}. 61f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang */ 62f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang private boolean mPreventSwipesEntirely = false; 63489dd22c64c718b6953b4bd6acef925e82c53c87Andy Huang 64b334c9035e9b7a38766bb66c29da2208525d1e11Paul Westbrook public static final String LOG_TAG = LogTag.getLogTag(); 6552a61db87c487fe5bb7cc673037887a6d35b0f0fMark Wei 66ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao private ConversationCheckedSet mConvCheckedSet; 676c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira private int mSwipeAction; 686126d72ae2769bd39451872f45781cadb5b90515Mark Wei private Account mAccount; 6906642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira private Folder mFolder; 709365a826b46b0e274df88e92534f7d871eef2aa2mindyp private ListItemSwipedListener mSwipedListener; 7169b440141f402669fe44dfd8924a94fd22ebccf7mindyp private boolean mScrolling; 72866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira 73e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang private SwipeListener mSwipeListener; 74e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang 754485ade4b8c949a222f8b98650a9a48d074dc87eVikram Aggarwal // Instantiated through view inflation 764485ade4b8c949a222f8b98650a9a48d074dc87eVikram Aggarwal @SuppressWarnings("unused") 77f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public SwipeableListView(Context context) { 78f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira this(context, null); 79f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 80f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 81f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public SwipeableListView(Context context, AttributeSet attrs) { 82f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira this(context, attrs, -1); 83f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 84f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 85f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public SwipeableListView(Context context, AttributeSet attrs, int defStyle) { 86f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira super(context, attrs, defStyle); 87f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira float densityScale = getResources().getDisplayMetrics().density; 88f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira float pagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop(); 896f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, 906f0b2be9d3855e93ec2977b2736798c60adb9b7eMindy Pereira pagingTouchSlop); 91f9fd2cf057d845c7b081a3f17482dd0b886179d1Rohan Shah mScrolling = false; 92f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 93f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 94f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira @Override 95f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira protected void onConfigurationChanged(Configuration newConfig) { 96f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira super.onConfigurationChanged(newConfig); 97f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira float densityScale = getResources().getDisplayMetrics().density; 98f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira mSwipeHelper.setDensityScale(densityScale); 99f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop(); 100f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira mSwipeHelper.setPagingTouchSlop(pagingTouchSlop); 101f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira } 102f913894d3f1fa80b7174477999074b813e1deb12Mindy Pereira 1037517e3b61b898a57f19be0671f70d58a82224643Andy Huang @Override 1047517e3b61b898a57f19be0671f70d58a82224643Andy Huang protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { 105bc88f16af48d9538b79cbeab88cd275cb769a67dVikram Aggarwal LogUtils.d(Utils.VIEW_DEBUGGING_TAG, 1067517e3b61b898a57f19be0671f70d58a82224643Andy Huang "START CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s", 1077517e3b61b898a57f19be0671f70d58a82224643Andy Huang isLayoutRequested(), getRootView().isLayoutRequested()); 1087517e3b61b898a57f19be0671f70d58a82224643Andy Huang super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); 109bc88f16af48d9538b79cbeab88cd275cb769a67dVikram Aggarwal LogUtils.d(Utils.VIEW_DEBUGGING_TAG, new Error(), 1107517e3b61b898a57f19be0671f70d58a82224643Andy Huang "FINISH CLF-ListView.onFocusChanged layoutRequested=%s root.layoutRequested=%s", 1117517e3b61b898a57f19be0671f70d58a82224643Andy Huang isLayoutRequested(), getRootView().isLayoutRequested()); 1127517e3b61b898a57f19be0671f70d58a82224643Andy Huang } 1137517e3b61b898a57f19be0671f70d58a82224643Andy Huang 114ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira /** 115ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira * Enable swipe gestures. 116ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira */ 117ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira public void enableSwipe(boolean enable) { 118ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira mEnableSwipe = enable; 119ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira } 120ff9aff3c28c4c20c7866ebfaaa642997e324f274Mindy Pereira 121f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang /** 122f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang * Completely ignore any horizontal swiping gestures. 123f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang */ 124f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang public void preventSwipesEntirely() { 125f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang mPreventSwipesEntirely = true; 126f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang } 127f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang 128f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang /** 129f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang * Reverses a prior call to {@link #preventSwipesEntirely()}. 130f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang */ 131f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang public void stopPreventingSwipes() { 132f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang mPreventSwipesEntirely = false; 133f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang } 134f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang 1356c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira public void setSwipeAction(int action) { 1366c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira mSwipeAction = action; 137f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 138f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 1397c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein public void setListItemSwipedListener(ListItemSwipedListener listener) { 1409365a826b46b0e274df88e92534f7d871eef2aa2mindyp mSwipedListener = listener; 1419365a826b46b0e274df88e92534f7d871eef2aa2mindyp } 1429365a826b46b0e274df88e92534f7d871eef2aa2mindyp 143de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira public int getSwipeAction() { 144de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira return mSwipeAction; 145de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira } 146de3e74a82043733243c7391d7f983a5af8842891Mindy Pereira 147ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao public void setCheckedSet(ConversationCheckedSet set) { 148ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mConvCheckedSet = set; 149866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira } 150866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira 1516126d72ae2769bd39451872f45781cadb5b90515Mark Wei public void setCurrentAccount(Account account) { 1526126d72ae2769bd39451872f45781cadb5b90515Mark Wei mAccount = account; 1536126d72ae2769bd39451872f45781cadb5b90515Mark Wei } 1546126d72ae2769bd39451872f45781cadb5b90515Mark Wei 15506642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira public void setCurrentFolder(Folder folder) { 15606642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira mFolder = folder; 15706642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira } 15806642fab1bf4ab95b5dd97a65b262845cf60c865Mindy Pereira 159866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira @Override 160ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao public ConversationCheckedSet getCheckedSet() { 161ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao return mConvCheckedSet; 162866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira } 163866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira 164f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 165f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public boolean onInterceptTouchEvent(MotionEvent ev) { 1663432b636fbcf7d6cc551b9705ed4dd88ae2b4f49Jin Cao if (mScrolling) { 16719bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira return super.onInterceptTouchEvent(ev); 16869b440141f402669fe44dfd8924a94fd22ebccf7mindyp } else { 169f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang return (!mPreventSwipesEntirely && mSwipeHelper.onInterceptTouchEvent(ev)) 170f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang || super.onInterceptTouchEvent(ev); 17119bf5f5a4944f5bb4e62e1f32c47dce87f662cbdMindy Pereira } 172f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 173f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 174f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 175f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public boolean onTouchEvent(MotionEvent ev) { 176f211b12a7cdf6556f489df51c6f57dd79e8887feAndy Huang return (!mPreventSwipesEntirely && mSwipeHelper.onTouchEvent(ev)) || super.onTouchEvent(ev); 177f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 178f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 179f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 180f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public View getChildAtPosition(MotionEvent ev) { 181f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira // find the view under the pointer, accounting for GONE views 182f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira final int count = getChildCount(); 183f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal final int touchY = (int) ev.getY(); 184f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira int childIdx = 0; 185f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira View slidingChild; 186f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira for (; childIdx < count; childIdx++) { 187f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira slidingChild = getChildAt(childIdx); 188f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira if (slidingChild.getVisibility() == GONE) { 189f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira continue; 190f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 191866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira if (touchY >= slidingChild.getTop() && touchY <= slidingChild.getBottom()) { 1921ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira if (slidingChild instanceof SwipeableConversationItemView) { 1931ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira return ((SwipeableConversationItemView) slidingChild).getSwipeableItemView(); 1941ef988f0c8be136fda75ed207c222413db1d3f0cMindy Pereira } 195866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira return slidingChild; 196866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira } 197f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 198f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira return null; 199f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 200f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 201f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 2026c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira public boolean canChildBeDismissed(SwipeableItemView v) { 2033432b636fbcf7d6cc551b9705ed4dd88ae2b4f49Jin Cao return mEnableSwipe && v.canChildBeDismissed(); 204f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 205f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 206f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 2076c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira public void onChildDismissed(SwipeableItemView v) { 2080760bfbf8259e4161ce7737fc980b6b9297885ccmindyp if (v != null) { 2090760bfbf8259e4161ce7737fc980b6b9297885ccmindyp v.dismiss(); 2100760bfbf8259e4161ce7737fc980b6b9297885ccmindyp } 211f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 212f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 2138937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira // Call this whenever a new action is taken; this forces a commit of any 2148937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira // existing destructive actions. 215c6adce3cf6887c4c6dd5005724565702751843d0mindyp public void commitDestructiveActions(boolean animate) { 2160fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira final AnimatedAdapter adapter = getAnimatedAdapter(); 2178937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira if (adapter != null) { 218c6adce3cf6887c4c6dd5005724565702751843d0mindyp adapter.commitLeaveBehindItems(animate); 2198937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira } 2208937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira } 2218937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira 222a538984fcc19e7624f2650b119ede39bf1f35846mindyp public void dismissChild(final ConversationItemView target) { 2237c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein // Notifies the SwipeListener that a swipe has ended. 2247c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein if (mSwipeListener != null) { 2257c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein mSwipeListener.onEndSwipe(); 2267c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein } 2277c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein 228d3367499e56116854ed637b1036fd71057ac0f49Mindy Pereira final ToastBarOperation undoOp; 229866d319dd23ec8b7b7d5476c65f7f83469d55d2dMindy Pereira 2306a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy undoOp = new ToastBarOperation(1, mSwipeAction, ToastBarOperation.UNDO, false /* batch */, 2316a3d5ce0b18f58fcfa1af0315dc8ddc7331c2c5fScott Kennedy mFolder); 2326c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira Conversation conv = target.getConversation(); 23313e6243683cc8cb998a43d06f25d6ff1aab9d93bMindy Pereira target.getConversation().position = findConversation(target, conv); 2340fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira final AnimatedAdapter adapter = getAnimatedAdapter(); 23509f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira if (adapter == null) { 23609f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira return; 23709f1ae9a9f209436c0c6b44a6e76b32b27937a01Mindy Pereira } 238370f868c834861e7732faaa9bdd07a0fa0105596Andy Huang adapter.setupLeaveBehind(conv, undoOp, conv.position, target.getHeight()); 23900ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira ConversationCursor cc = (ConversationCursor) adapter.getCursor(); 2409365a826b46b0e274df88e92534f7d871eef2aa2mindyp Collection<Conversation> convList = Conversation.listOf(conv); 2415cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp ArrayList<Uri> folderUris; 2425cc0ab20009100e3ef259fe3d2e3ddc357f79285mindyp ArrayList<Boolean> adds; 243042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang 2442b55549d4fbe25e91f673a0727fc89ff755d9327Andy Huang Analytics.getInstance().sendMenuItemEvent("list_swipe", mSwipeAction, null, 0); 245042a530b2296487fa5899a3e871214ac4a47e3d8Andy Huang 2462b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy if (mSwipeAction == R.id.remove_folder) { 2472b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy FolderOperation folderOp = new FolderOperation(mFolder, false); 2482b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy HashMap<Uri, Folder> targetFolders = Folder 2492b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy .hashMapForFolders(conv.getRawFolders()); 2502b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy targetFolders.remove(folderOp.mFolder.folderUri.fullUri); 2512b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final FolderList folders = FolderList.copyOf(targetFolders.values()); 2522b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy conv.setRawFolders(folders); 2532b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy final ContentValues values = new ContentValues(); 2542b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy folderUris = new ArrayList<Uri>(); 2552b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy folderUris.add(mFolder.folderUri.fullUri); 2562b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy adds = new ArrayList<Boolean>(); 2572b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy adds.add(Boolean.FALSE); 2582b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy ConversationCursor.addFolderUpdates(folderUris, adds, values); 2592b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy ConversationCursor.addTargetFolders(targetFolders.values(), values); 2602b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy cc.mostlyDestructiveUpdate(Conversation.listOf(conv), values); 2612b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mSwipeAction == R.id.archive) { 2622b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy cc.mostlyArchive(convList); 2632b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy } else if (mSwipeAction == R.id.delete) { 2642b9d80eb16156173f11a02eae4f770d8c975927cScott Kennedy cc.mostlyDelete(convList); 265512821c11d89d49908f3cfdee0b582601f500f3dJin Cao } else if (mSwipeAction == R.id.discard_outbox) { 266512821c11d89d49908f3cfdee0b582601f500f3dJin Cao cc.moveFailedIntoDrafts(convList); 2676c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira } 2689365a826b46b0e274df88e92534f7d871eef2aa2mindyp if (mSwipedListener != null) { 2699365a826b46b0e274df88e92534f7d871eef2aa2mindyp mSwipedListener.onListItemSwiped(convList); 2709365a826b46b0e274df88e92534f7d871eef2aa2mindyp } 2716c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira adapter.notifyDataSetChanged(); 272ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao if (mConvCheckedSet != null && !mConvCheckedSet.isEmpty() 273ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao && mConvCheckedSet.contains(conv)) { 274ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao mConvCheckedSet.toggle(conv); 27554f120f6ada40c7191811dfff99b151e9e192c78mindyp // Don't commit destructive actions if the item we just removed from 27654f120f6ada40c7191811dfff99b151e9e192c78mindyp // the selection set is the item we just destroyed! 277ec0fa48764bede0772e9c711f3e33361b62f3608Jin Cao if (!conv.isMostlyDead() && mConvCheckedSet.isEmpty()) { 27854f120f6ada40c7191811dfff99b151e9e192c78mindyp commitDestructiveActions(true); 27954f120f6ada40c7191811dfff99b151e9e192c78mindyp } 280cff4a2b2e92258c6c85ed4af15bc13101aa71170Mindy Pereira } 281f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 282f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 283f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 284f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira public void onBeginDrag(View v) { 285f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira // We do this so the underlying ScrollView knows that it won't get 286f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira // the chance to intercept events anymore 287f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira requestDisallowInterceptTouchEvent(true); 2883b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp cancelDismissCounter(); 289e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang 2907c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein // Notifies the SwipeListener that a swipe has begun. 291e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang if (mSwipeListener != null) { 292e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang mSwipeListener.onBeginSwipe(); 293e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang } 294f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 295f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 296f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira @Override 2976c72a787b58a0bc3afcb71093eddf8c29d1cf5edMindy Pereira public void onDragCancelled(SwipeableItemView v) { 2983b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp final AnimatedAdapter adapter = getAnimatedAdapter(); 2993b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp if (adapter != null) { 3003b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp adapter.startDismissCounter(); 3014d4531a63cff536d2ee1a2929d0820981df8516amindyp adapter.cancelFadeOutLastLeaveBehindItemText(); 3023b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp } 3037c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein 3047c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein // Notifies the SwipeListener that a swipe has ended. 3057c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein if (mSwipeListener != null) { 3067c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein mSwipeListener.onEndSwipe(); 3077c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein } 308f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira } 309f6a6b50c6b45f36b9317e1688f8b87310a67b037Mindy Pereira 31007118a01f7183645957010779222b84930f75b4eMindy Pereira /** 31107118a01f7183645957010779222b84930f75b4eMindy Pereira * Archive items using the swipe away animation before shrinking them away. 31207118a01f7183645957010779222b84930f75b4eMindy Pereira */ 313cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook public boolean destroyItems(Collection<Conversation> convs, 31484f7d32bdc79263004ed5241480988e02f8e618cmindyp final ListItemsRemovedListener listener) { 31584f7d32bdc79263004ed5241480988e02f8e618cmindyp if (convs == null) { 316cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook LogUtils.e(LOG_TAG, "SwipeableListView.destroyItems: null conversations."); 317cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook return false; 31884f7d32bdc79263004ed5241480988e02f8e618cmindyp } 319a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal final AnimatedAdapter adapter = getAnimatedAdapter(); 320a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal if (adapter == null) { 321a8e4318bb9921e2ec6045c5f7187a4b78c55fe10Vikram Aggarwal LogUtils.e(LOG_TAG, "SwipeableListView.destroyItems: Cannot destroy: adapter is null."); 322cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook return false; 323067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } 32484f7d32bdc79263004ed5241480988e02f8e618cmindyp adapter.swipeDelete(convs, listener); 325cec3e0b9c90173e0bdb2d072046b38714fc9186ePaul Westbrook return true; 326067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } 327067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira 328cc2f9296ad63ed681c200feb118c5caace36e72emindyp public int findConversation(ConversationItemView view, Conversation conv) { 329dbb587f15c723ae80edb33f65c29cc2b6c15eba0Scott Kennedy int position = INVALID_POSITION; 330067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira long convId = conv.id; 331067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira try { 332dbb587f15c723ae80edb33f65c29cc2b6c15eba0Scott Kennedy position = getPositionForView(view); 333067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } catch (Exception e) { 334067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira position = INVALID_POSITION; 335599e7f8bf95d2f21a966cbff1bf72adf77a90a33Andy Huang LogUtils.w(LOG_TAG, e, "Exception finding position; using alternate strategy"); 336067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } 337067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira if (position == INVALID_POSITION) { 338067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira // Try the other way! 339067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira Conversation foundConv; 340067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira long foundId; 341067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira for (int i = 0; i < getChildCount(); i++) { 342067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira View child = getChildAt(i); 343067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira if (child instanceof SwipeableConversationItemView) { 344067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira foundConv = ((SwipeableConversationItemView) child).getSwipeableItemView() 345067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira .getConversation(); 346067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira foundId = foundConv.id; 347067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira if (foundId == convId) { 348599e7f8bf95d2f21a966cbff1bf72adf77a90a33Andy Huang position = i + getFirstVisiblePosition(); 349067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira break; 350067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } 351067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } 352067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira } 353c79aec78d06928b3fa1464d6aed60019f9b4843bMindy Pereira } 354067ef97264240a2c3f9172a9ab88ba43fef7c475Mindy Pereira return position; 35507118a01f7183645957010779222b84930f75b4eMindy Pereira } 35607118a01f7183645957010779222b84930f75b4eMindy Pereira 3570fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira private AnimatedAdapter getAnimatedAdapter() { 3580fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira return (AnimatedAdapter) getAdapter(); 3590fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira } 3600fb551891757ecddccb299d9df770bb1675e3fd2Mindy Pereira 3618937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira @Override 3628937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira public boolean performItemClick(View view, int pos, long id) { 3636126d72ae2769bd39451872f45781cadb5b90515Mark Wei // Superclass method modifies the selection set 364f69d0394f7de5c0681b8d5d5ca0c60b55c55f815Vikram Aggarwal final boolean handled = super.performItemClick(view, pos, id); 3656126d72ae2769bd39451872f45781cadb5b90515Mark Wei 36600ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira // Commit any existing destructive actions when the user selects a 36700ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira // conversation to view. 368c6adce3cf6887c4c6dd5005724565702751843d0mindyp commitDestructiveActions(true); 369dd9d3a16148b178cb95fd4db4168a67c64eb944fMindy Pereira return handled; 3708937bf1552a86853efc798a4d8df34c01115cdfdMindy Pereira } 3715254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp 3725254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp @Override 373d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp public void onScroll() { 374d064972c4a032f3c5cfcb236aa470273f7ac2ce0mindyp commitDestructiveActions(true); 3755254486a8c37cdf2b579aa7a3b9c8eb7324062bcmindyp } 3769365a826b46b0e274df88e92534f7d871eef2aa2mindyp 3779365a826b46b0e274df88e92534f7d871eef2aa2mindyp public interface ListItemsRemovedListener { 3789365a826b46b0e274df88e92534f7d871eef2aa2mindyp public void onListItemsRemoved(); 3799365a826b46b0e274df88e92534f7d871eef2aa2mindyp } 3809365a826b46b0e274df88e92534f7d871eef2aa2mindyp 3819365a826b46b0e274df88e92534f7d871eef2aa2mindyp public interface ListItemSwipedListener { 3829365a826b46b0e274df88e92534f7d871eef2aa2mindyp public void onListItemSwiped(Collection<Conversation> conversations); 3839365a826b46b0e274df88e92534f7d871eef2aa2mindyp } 38469b440141f402669fe44dfd8924a94fd22ebccf7mindyp 38569b440141f402669fe44dfd8924a94fd22ebccf7mindyp @Override 38679c3e1ed9cb1e1660c5d34b7bf3f3ab5c5dd5162Andy Huang public final void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 387479505d71969e26b0785d8e0e1b81108731cf827Mark Wei int totalItemCount) { 38869b440141f402669fe44dfd8924a94fd22ebccf7mindyp } 38969b440141f402669fe44dfd8924a94fd22ebccf7mindyp 39069b440141f402669fe44dfd8924a94fd22ebccf7mindyp @Override 39181aea35d45b3d0191ec595562a2fcf67009845d5Mark Wei public void onScrollStateChanged(final AbsListView view, final int scrollState) { 392479505d71969e26b0785d8e0e1b81108731cf827Mark Wei mScrolling = scrollState != OnScrollListener.SCROLL_STATE_IDLE; 393479505d71969e26b0785d8e0e1b81108731cf827Mark Wei 39448ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang if (!mScrolling) { 39548ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang final Context c = getContext(); 39648ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang if (c instanceof ControllableActivity) { 39748ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang final ControllableActivity activity = (ControllableActivity) c; 39848ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang activity.onAnimationEnd(null /* adapter */); 39948ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang } else { 40048ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang LogUtils.wtf(LOG_TAG, "unexpected context=%s", c); 40148ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang } 40248ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang } 40348ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang } 40448ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang 40548ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang public boolean isScrolling() { 40648ccbc53ef90bf6420f831f63e6243008e02a346Andy Huang return mScrolling; 40769b440141f402669fe44dfd8924a94fd22ebccf7mindyp } 4083b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp 4093b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp @Override 4103b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp public void cancelDismissCounter() { 4113b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp AnimatedAdapter adapter = getAnimatedAdapter(); 4123b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp if (adapter != null) { 4133b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp adapter.cancelDismissCounter(); 4143b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp } 4153b5e82b06a0af3f5ddf3667de9a2aa26eeb5f24bmindyp } 4167af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp 4177af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp @Override 4187af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp public LeaveBehindItem getLastSwipedItem() { 4197af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp AnimatedAdapter adapter = getAnimatedAdapter(); 4207af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp if (adapter != null) { 4217af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp return adapter.getLastLeaveBehindItem(); 4227af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp } 4237af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp return null; 4247af43c93d4ca90bb0a43ec790a434c95128cc99fmindyp } 425e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang 426e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang public void setSwipeListener(SwipeListener swipeListener) { 427e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang mSwipeListener = swipeListener; 428e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang } 429e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang 430e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang public interface SwipeListener { 431e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang public void onBeginSwipe(); 4327c411aafd9ef059f881b7532426e61d1def54a07Andrew Sapperstein public void onEndSwipe(); 433e6f4ddc19c205796cde91d58483fa39c3cc13f1aAlice Yang } 43400ffece08e94ff5774b2a53c0adeb2f3d0815d66Mindy Pereira} 435