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