9191import android .view .MenuItem ;
9292import android .view .MotionEvent ;
9393import android .view .View ;
94+ import android .view .ViewConfiguration ;
9495import android .view .ViewDebug ;
9596import android .view .ViewGroup ;
9697import android .view .ViewGroup .LayoutParams ;
@@ -6820,16 +6821,17 @@ protected void onReceiveResult(int resultCode, Bundle resultData) {
68206821 @ Override
68216822 public boolean onTouchEvent (MotionEvent event ) {
68226823 final int action = event .getActionMasked ();
6823- if (action == MotionEvent .ACTION_DOWN ) {
6824- if (hasInsertionController ()) {
6825- getInsertionController ().onTouchEvent (event );
6826- }
6827- if (hasSelectionController ()) {
6828- getSelectionController ().onTouchEvent (event );
6829- }
68306824
6831- // Reset this state; it will be re-set if super.onTouchEvent
6832- // causes focus to move to the view.
6825+ if (mInsertionPointCursorController != null ) {
6826+ mInsertionPointCursorController .onTouchEvent (event );
6827+ }
6828+ if (mSelectionModifierCursorController != null ) {
6829+ mSelectionModifierCursorController .onTouchEvent (event );
6830+ }
6831+
6832+ if (action == MotionEvent .ACTION_DOWN ) {
6833+ // Reset this state; it will be re-set if super.onTouchEvent
6834+ // causes focus to move to the view.
68336835 mTouchFocusSelected = false ;
68346836 mScrolled = false ;
68356837 }
@@ -6847,13 +6849,6 @@ public boolean onTouchEvent(MotionEvent event) {
68476849 }
68486850
68496851 if ((mMovement != null || onCheckIsTextEditor ()) && mText instanceof Spannable && mLayout != null ) {
6850- if (hasInsertionController ()) {
6851- getInsertionController ().onTouchEvent (event );
6852- }
6853- if (hasSelectionController ()) {
6854- getSelectionController ().onTouchEvent (event );
6855- }
6856-
68576852 boolean handled = false ;
68586853
68596854 // Save previous selection, in case this event is used to show the IME.
@@ -7782,7 +7777,7 @@ public void setOrientation(int pos) {
77827777 }
77837778 mDrawable = mSelectHandleLeft ;
77847779 handleWidth = mDrawable .getIntrinsicWidth ();
7785- mHotspotX = handleWidth / 4 * 3 ;
7780+ mHotspotX = ( handleWidth * 3 ) / 4 ;
77867781 break ;
77877782 }
77887783
@@ -7949,6 +7944,7 @@ public boolean onTouchEvent(MotionEvent ev) {
79497944 mIsDragging = true ;
79507945 break ;
79517946 }
7947+
79527948 case MotionEvent .ACTION_MOVE : {
79537949 final float rawX = ev .getRawX ();
79547950 final float rawY = ev .getRawY ();
@@ -7959,6 +7955,7 @@ public boolean onTouchEvent(MotionEvent ev) {
79597955
79607956 break ;
79617957 }
7958+
79627959 case MotionEvent .ACTION_UP :
79637960 case MotionEvent .ACTION_CANCEL :
79647961 mIsDragging = false ;
@@ -8073,6 +8070,10 @@ private class SelectionModifierCursorController implements CursorController {
80738070 private int mMinTouchOffset , mMaxTouchOffset ;
80748071 // Whether selection anchors are active
80758072 private boolean mIsShowing ;
8073+ // Double tap detection
8074+ private long mPreviousTapUpTime = 0 ;
8075+ private int mPreviousTapPositionX ;
8076+ private int mPreviousTapPositionY ;
80768077
80778078 SelectionModifierCursorController () {
80788079 mStartHandle = new HandleView (this , HandleView .LEFT );
@@ -8167,6 +8168,24 @@ public boolean onTouchEvent(MotionEvent event) {
81678168 // Remember finger down position, to be able to start selection from there
81688169 mMinTouchOffset = mMaxTouchOffset = getOffset (x , y );
81698170
8171+ // Double tap detection
8172+ long duration = SystemClock .uptimeMillis () - mPreviousTapUpTime ;
8173+ if (duration <= ViewConfiguration .getDoubleTapTimeout ()) {
8174+ final int deltaX = x - mPreviousTapPositionX ;
8175+ final int deltaY = y - mPreviousTapPositionY ;
8176+ final int distanceSquared = deltaX * deltaX + deltaY * deltaY ;
8177+ final int doubleTapSlop = ViewConfiguration .get (getContext ()).getScaledDoubleTapSlop ();
8178+ final int slopSquared = doubleTapSlop * doubleTapSlop ;
8179+ if (distanceSquared < slopSquared ) {
8180+ startTextSelectionMode ();
8181+ // Hacky: onTapUpEvent will open a context menu with cut/copy
8182+ // Prevent this by hiding handles which will be revived instead.
8183+ hide ();
8184+ }
8185+ }
8186+ mPreviousTapPositionX = x ;
8187+ mPreviousTapPositionY = y ;
8188+
81708189 break ;
81718190
81728191 case MotionEvent .ACTION_POINTER_DOWN :
@@ -8178,6 +8197,10 @@ public boolean onTouchEvent(MotionEvent event) {
81788197 updateMinAndMaxOffsets (event );
81798198 }
81808199 break ;
8200+
8201+ case MotionEvent .ACTION_UP :
8202+ mPreviousTapUpTime = SystemClock .uptimeMillis ();
8203+ break ;
81818204 }
81828205 }
81838206 return false ;
0 commit comments