20
20
import android .content .Context ;
21
21
import android .database .DataSetObserver ;
22
22
import android .graphics .Rect ;
23
+ import android .os .Handler ;
23
24
import android .os .Parcel ;
24
25
import android .os .Parcelable ;
25
26
import android .support .v4 .util .SparseArrayCompat ;
@@ -138,6 +139,33 @@ public abstract class ExtendableListView extends AbsListView {
138
139
139
140
protected boolean mClipToPadding ;
140
141
private PerformClick mPerformClick ;
142
+
143
+ private Runnable mPendingCheckForTap ;
144
+ private CheckForLongPress mPendingCheckForLongPress ;
145
+
146
+ private class CheckForLongPress extends WindowRunnnable implements Runnable {
147
+ public void run () {
148
+ final int motionPosition = mMotionPosition ;
149
+ final View child = getChildAt (motionPosition );
150
+ if (child != null ) {
151
+ final int longPressPosition = mMotionPosition ;
152
+ final long longPressId = mAdapter .getItemId (mMotionPosition + mFirstPosition );
153
+
154
+ boolean handled = false ;
155
+ if (sameWindow () && !mDataChanged ) {
156
+ handled = performLongPress (child , longPressPosition + mFirstPosition , longPressId );
157
+ }
158
+ if (handled ) {
159
+ mTouchMode = TOUCH_MODE_IDLE ;
160
+ setPressed (false );
161
+ child .setPressed (false );
162
+ } else {
163
+ mTouchMode = TOUCH_MODE_DONE_WAITING ;
164
+ }
165
+
166
+ }
167
+ }
168
+ }
141
169
142
170
/**
143
171
* A class that represents a fixed view in a list, for example a header at the top
@@ -806,6 +834,39 @@ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
806
834
super .requestDisallowInterceptTouchEvent (disallowIntercept );
807
835
}
808
836
837
+ final class CheckForTap implements Runnable {
838
+ public void run () {
839
+ if (mTouchMode == TOUCH_MODE_DOWN ) {
840
+ mTouchMode = TOUCH_MODE_TAP ;
841
+ final View child = getChildAt (mMotionPosition );
842
+ if (child != null && !child .hasFocusable ()) {
843
+ mLayoutMode = LAYOUT_NORMAL ;
844
+
845
+ if (!mDataChanged ) {
846
+ layoutChildren ();
847
+ child .setPressed (true );
848
+ setPressed (true );
849
+
850
+ final int longPressTimeout = ViewConfiguration .getLongPressTimeout ();
851
+ final boolean longClickable = isLongClickable ();
852
+
853
+ if (longClickable ) {
854
+ if (mPendingCheckForLongPress == null ) {
855
+ mPendingCheckForLongPress = new CheckForLongPress ();
856
+ }
857
+ mPendingCheckForLongPress .rememberWindowAttachCount ();
858
+ postDelayed (mPendingCheckForLongPress , longPressTimeout );
859
+ } else {
860
+ mTouchMode = TOUCH_MODE_DONE_WAITING ;
861
+ }
862
+ } else {
863
+ mTouchMode = TOUCH_MODE_DONE_WAITING ;
864
+ }
865
+ }
866
+ }
867
+ }
868
+ }
869
+
809
870
private boolean onTouchDown (final MotionEvent event ) {
810
871
final int x = (int ) event .getX ();
811
872
final int y = (int ) event .getY ();
@@ -825,7 +886,10 @@ private boolean onTouchDown(final MotionEvent event) {
825
886
// is it a tap or a scroll .. we don't know yet!
826
887
mTouchMode = TOUCH_MODE_DOWN ;
827
888
828
- // TODO : add handling for a click removed from here
889
+ if (mPendingCheckForTap == null ) {
890
+ mPendingCheckForTap = new CheckForTap ();
891
+ }
892
+ postDelayed (mPendingCheckForTap , ViewConfiguration .getTapTimeout ());
829
893
830
894
if (event .getEdgeFlags () != 0 && motionPosition < 0 ) {
831
895
// If we couldn't find a view to click on, but the down event was touching
@@ -885,6 +949,12 @@ private boolean onTouchCancel(final MotionEvent event) {
885
949
mTouchMode = TOUCH_MODE_IDLE ;
886
950
setPressed (false );
887
951
invalidate (); // redraw selector
952
+ final Handler handler = getHandler ();
953
+
954
+ if (handler != null ) {
955
+ handler .removeCallbacks (mPendingCheckForLongPress );
956
+ }
957
+
888
958
recycleVelocityTracker ();
889
959
mActivePointerId = INVALID_POINTER ;
890
960
return true ;
@@ -903,7 +973,14 @@ private boolean onTouchUp(final MotionEvent event) {
903
973
904
974
setPressed (false );
905
975
invalidate (); // redraw selector
976
+
977
+ final Handler handler = getHandler ();
978
+ if (handler != null ) {
979
+ handler .removeCallbacks (mPendingCheckForLongPress );
980
+ }
981
+
906
982
recycleVelocityTracker ();
983
+
907
984
mActivePointerId = INVALID_POINTER ;
908
985
return true ;
909
986
}
@@ -939,17 +1016,56 @@ private boolean onTouchUpScrolling(final MotionEvent event) {
939
1016
}
940
1017
941
1018
private boolean onTouchUpTap (final MotionEvent event ) {
942
- if (mPerformClick == null ) {
943
- invalidate ();
944
- mPerformClick = new PerformClick ();
945
- }
946
1019
final int motionPosition = mMotionPosition ;
947
- if (!mDataChanged && motionPosition >= 0 && mAdapter .isEnabled (motionPosition )) {
1020
+ final View child = getChildAt (motionPosition );
1021
+ if (child != null && !child .hasFocusable ()) {
1022
+ if (mTouchMode != TOUCH_MODE_DOWN ) {
1023
+ child .setPressed (false );
1024
+ }
1025
+
1026
+ if (mPerformClick == null ) {
1027
+ invalidate ();
1028
+ mPerformClick = new PerformClick ();
1029
+ }
1030
+
948
1031
final PerformClick performClick = mPerformClick ;
949
1032
performClick .mClickMotionPosition = motionPosition ;
950
1033
performClick .rememberWindowAttachCount ();
951
- performClick .run ();
1034
+
1035
+ // mResurrectToPosition = motionPosition;
1036
+
1037
+ if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP ) {
1038
+ final Handler handler = getHandler ();
1039
+ if (handler != null ) {
1040
+ handler .removeCallbacks (mTouchMode == TOUCH_MODE_DOWN ?
1041
+ mPendingCheckForTap : mPendingCheckForLongPress );
1042
+ }
1043
+ mLayoutMode = LAYOUT_NORMAL ;
1044
+ if (!mDataChanged && mAdapter .isEnabled (motionPosition )) {
1045
+ mTouchMode = TOUCH_MODE_TAP ;
1046
+ layoutChildren ();
1047
+ child .setPressed (true );
1048
+ setPressed (true );
1049
+ postDelayed (new Runnable () {
1050
+ public void run () {
1051
+ child .setPressed (false );
1052
+ setPressed (false );
1053
+ if (!mDataChanged ) {
1054
+ post (performClick );
1055
+ }
1056
+ mTouchMode = TOUCH_MODE_IDLE ;
1057
+ }
1058
+ }, ViewConfiguration .getPressedStateDuration ());
1059
+ } else {
1060
+ mTouchMode = TOUCH_MODE_IDLE ;
1061
+ }
1062
+ return true ;
1063
+ } else if (!mDataChanged && mAdapter .isEnabled (motionPosition )) {
1064
+ post (performClick );
1065
+ }
952
1066
}
1067
+ mTouchMode = TOUCH_MODE_IDLE ;
1068
+
953
1069
return true ;
954
1070
}
955
1071
@@ -1005,7 +1121,10 @@ private boolean startScrollIfNeeded(final int y) {
1005
1121
mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop ;
1006
1122
}
1007
1123
1008
- // TODO : LONG PRESS
1124
+ final Handler handler = getHandler ();
1125
+ if (handler != null ) {
1126
+ handler .removeCallbacks (mPendingCheckForLongPress );
1127
+ }
1009
1128
setPressed (false );
1010
1129
View motionView = getChildAt (mMotionPosition - mFirstPosition );
1011
1130
if (motionView != null ) {
@@ -2741,11 +2860,30 @@ public void run() {
2741
2860
final View view = getChildAt (motionPosition ); // a fix by @pboos
2742
2861
2743
2862
if (view != null ) {
2744
- performItemClick (view , motionPosition + mFirstPosition , adapter .getItemId (motionPosition ));
2863
+ performItemClick (view , motionPosition + mFirstPosition , adapter .getItemId (motionPosition + mFirstPosition ));
2745
2864
}
2746
2865
}
2747
2866
}
2748
2867
}
2868
+
2869
+ private boolean performLongPress (final View child ,
2870
+ final int longPressPosition , final long longPressId ) {
2871
+ boolean handled = false ;
2872
+
2873
+ OnItemLongClickListener onItemLongClickListener = getOnItemLongClickListener ();
2874
+ if (onItemLongClickListener != null ) {
2875
+ handled = onItemLongClickListener .onItemLongClick (ExtendableListView .this , child ,
2876
+ longPressPosition , longPressId );
2877
+ }
2878
+ // if (!handled) {
2879
+ // mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
2880
+ // handled = super.showContextMenuForChild(AbsListView.this);
2881
+ // }
2882
+ if (handled ) {
2883
+ performHapticFeedback (HapticFeedbackConstants .LONG_PRESS );
2884
+ }
2885
+ return handled ;
2886
+ }
2749
2887
2750
2888
/**
2751
2889
* A base class for Runnables that will check that their view is still attached to
0 commit comments