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
@@ -812,6 +840,39 @@ public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
812
840
super .requestDisallowInterceptTouchEvent (disallowIntercept );
813
841
}
814
842
843
+ final class CheckForTap implements Runnable {
844
+ public void run () {
845
+ if (mTouchMode == TOUCH_MODE_DOWN ) {
846
+ mTouchMode = TOUCH_MODE_TAP ;
847
+ final View child = getChildAt (mMotionPosition );
848
+ if (child != null && !child .hasFocusable ()) {
849
+ mLayoutMode = LAYOUT_NORMAL ;
850
+
851
+ if (!mDataChanged ) {
852
+ layoutChildren ();
853
+ child .setPressed (true );
854
+ setPressed (true );
855
+
856
+ final int longPressTimeout = ViewConfiguration .getLongPressTimeout ();
857
+ final boolean longClickable = isLongClickable ();
858
+
859
+ if (longClickable ) {
860
+ if (mPendingCheckForLongPress == null ) {
861
+ mPendingCheckForLongPress = new CheckForLongPress ();
862
+ }
863
+ mPendingCheckForLongPress .rememberWindowAttachCount ();
864
+ postDelayed (mPendingCheckForLongPress , longPressTimeout );
865
+ } else {
866
+ mTouchMode = TOUCH_MODE_DONE_WAITING ;
867
+ }
868
+ } else {
869
+ mTouchMode = TOUCH_MODE_DONE_WAITING ;
870
+ }
871
+ }
872
+ }
873
+ }
874
+ }
875
+
815
876
private boolean onTouchDown (final MotionEvent event ) {
816
877
final int x = (int ) event .getX ();
817
878
final int y = (int ) event .getY ();
@@ -831,7 +892,10 @@ private boolean onTouchDown(final MotionEvent event) {
831
892
// is it a tap or a scroll .. we don't know yet!
832
893
mTouchMode = TOUCH_MODE_DOWN ;
833
894
834
- // TODO : add handling for a click removed from here
895
+ if (mPendingCheckForTap == null ) {
896
+ mPendingCheckForTap = new CheckForTap ();
897
+ }
898
+ postDelayed (mPendingCheckForTap , ViewConfiguration .getTapTimeout ());
835
899
836
900
if (event .getEdgeFlags () != 0 && motionPosition < 0 ) {
837
901
// If we couldn't find a view to click on, but the down event was touching
@@ -891,6 +955,12 @@ private boolean onTouchCancel(final MotionEvent event) {
891
955
mTouchMode = TOUCH_MODE_IDLE ;
892
956
setPressed (false );
893
957
invalidate (); // redraw selector
958
+ final Handler handler = getHandler ();
959
+
960
+ if (handler != null ) {
961
+ handler .removeCallbacks (mPendingCheckForLongPress );
962
+ }
963
+
894
964
recycleVelocityTracker ();
895
965
mActivePointerId = INVALID_POINTER ;
896
966
return true ;
@@ -909,7 +979,14 @@ private boolean onTouchUp(final MotionEvent event) {
909
979
910
980
setPressed (false );
911
981
invalidate (); // redraw selector
982
+
983
+ final Handler handler = getHandler ();
984
+ if (handler != null ) {
985
+ handler .removeCallbacks (mPendingCheckForLongPress );
986
+ }
987
+
912
988
recycleVelocityTracker ();
989
+
913
990
mActivePointerId = INVALID_POINTER ;
914
991
return true ;
915
992
}
@@ -945,17 +1022,58 @@ private boolean onTouchUpScrolling(final MotionEvent event) {
945
1022
}
946
1023
947
1024
private boolean onTouchUpTap (final MotionEvent event ) {
948
- if (mPerformClick == null ) {
949
- invalidate ();
950
- mPerformClick = new PerformClick ();
951
- }
952
1025
final int motionPosition = mMotionPosition ;
953
- if (!mDataChanged && motionPosition >= 0 && mAdapter .isEnabled (motionPosition )) {
954
- final PerformClick performClick = mPerformClick ;
955
- performClick .mClickMotionPosition = motionPosition ;
956
- performClick .rememberWindowAttachCount ();
957
- performClick .run ();
1026
+ if (motionPosition >= 0 ) {
1027
+ final View child = getChildAt (motionPosition );
1028
+ if (child != null && !child .hasFocusable ()) {
1029
+ if (mTouchMode != TOUCH_MODE_DOWN ) {
1030
+ child .setPressed (false );
1031
+ }
1032
+
1033
+ if (mPerformClick == null ) {
1034
+ invalidate ();
1035
+ mPerformClick = new PerformClick ();
1036
+ }
1037
+
1038
+ final PerformClick performClick = mPerformClick ;
1039
+ performClick .mClickMotionPosition = motionPosition ;
1040
+ performClick .rememberWindowAttachCount ();
1041
+
1042
+ // mResurrectToPosition = motionPosition;
1043
+
1044
+ if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP ) {
1045
+ final Handler handler = getHandler ();
1046
+ if (handler != null ) {
1047
+ handler .removeCallbacks (mTouchMode == TOUCH_MODE_DOWN ?
1048
+ mPendingCheckForTap : mPendingCheckForLongPress );
1049
+ }
1050
+ mLayoutMode = LAYOUT_NORMAL ;
1051
+ if (!mDataChanged && motionPosition >= 0 && mAdapter .isEnabled (motionPosition )) {
1052
+ mTouchMode = TOUCH_MODE_TAP ;
1053
+ layoutChildren ();
1054
+ child .setPressed (true );
1055
+ setPressed (true );
1056
+ postDelayed (new Runnable () {
1057
+ public void run () {
1058
+ child .setPressed (false );
1059
+ setPressed (false );
1060
+ if (!mDataChanged ) {
1061
+ post (performClick );
1062
+ }
1063
+ mTouchMode = TOUCH_MODE_IDLE ;
1064
+ }
1065
+ }, ViewConfiguration .getPressedStateDuration ());
1066
+ } else {
1067
+ mTouchMode = TOUCH_MODE_IDLE ;
1068
+ }
1069
+ return true ;
1070
+ } else if (!mDataChanged && motionPosition >= 0 && mAdapter .isEnabled (motionPosition )) {
1071
+ post (performClick );
1072
+ }
1073
+ }
958
1074
}
1075
+ mTouchMode = TOUCH_MODE_IDLE ;
1076
+
959
1077
return true ;
960
1078
}
961
1079
@@ -1011,7 +1129,10 @@ private boolean startScrollIfNeeded(final int y) {
1011
1129
mMotionCorrection = deltaY > 0 ? mTouchSlop : -mTouchSlop ;
1012
1130
}
1013
1131
1014
- // TODO : LONG PRESS
1132
+ final Handler handler = getHandler ();
1133
+ if (handler != null ) {
1134
+ handler .removeCallbacks (mPendingCheckForLongPress );
1135
+ }
1015
1136
setPressed (false );
1016
1137
View motionView = getChildAt (mMotionPosition - mFirstPosition );
1017
1138
if (motionView != null ) {
@@ -2754,6 +2875,25 @@ public void run() {
2754
2875
}
2755
2876
}
2756
2877
}
2878
+
2879
+ private boolean performLongPress (final View child ,
2880
+ final int longPressPosition , final long longPressId ) {
2881
+ boolean handled = false ;
2882
+
2883
+ OnItemLongClickListener onItemLongClickListener = getOnItemLongClickListener ();
2884
+ if (onItemLongClickListener != null ) {
2885
+ handled = onItemLongClickListener .onItemLongClick (ExtendableListView .this , child ,
2886
+ longPressPosition , longPressId );
2887
+ }
2888
+ // if (!handled) {
2889
+ // mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
2890
+ // handled = super.showContextMenuForChild(AbsListView.this);
2891
+ // }
2892
+ if (handled ) {
2893
+ performHapticFeedback (HapticFeedbackConstants .LONG_PRESS );
2894
+ }
2895
+ return handled ;
2896
+ }
2757
2897
2758
2898
/**
2759
2899
* A base class for Runnables that will check that their view is still attached to
0 commit comments