Skip to content

Commit dc90534

Browse files
committed
have clicks working to show keyboard on android 7
1 parent edabad5 commit dc90534

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ public class ReactEditText extends AppCompatEditText
122122
private static final KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard();
123123
private @Nullable EventDispatcher mEventDispatcher;
124124

125+
private final ReactEditTextClickDetector clickDetector = new ReactEditTextClickDetector(this);
126+
125127
public ReactEditText(Context context) {
126128
super(context);
127129
setFocusableInTouchMode(false);
@@ -206,6 +208,13 @@ public boolean onTouchEvent(MotionEvent ev) {
206208
// Disallow parent views to intercept touch events, until we can detect if we should be
207209
// capturing these touches or not.
208210
this.getParent().requestDisallowInterceptTouchEvent(true);
211+
clickDetector.handleDown(ev);
212+
break;
213+
case MotionEvent.ACTION_UP:
214+
clickDetector.handleUp(ev);
215+
break;
216+
case MotionEvent.ACTION_CANCEL:
217+
clickDetector.cancelPress();
209218
break;
210219
case MotionEvent.ACTION_MOVE:
211220
if (mDetectScrollMovement) {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.facebook.react.views.textinput;
2+
3+
import android.os.Build;
4+
import android.view.MotionEvent;
5+
import android.view.View;
6+
7+
import androidx.annotation.Nullable;
8+
9+
class ReactEditTextClickDetector {
10+
11+
private static final long MAX_CLICK_DURATION_MS = 250L;
12+
private static final int MAX_CLICK_DISTANCE_DP = 12;
13+
14+
private final ReactEditText reactEditText;
15+
private final float screenDensity;
16+
17+
@Nullable
18+
private TimestampedMotionEvent currentDownEvent;
19+
20+
public ReactEditTextClickDetector(final ReactEditText reactEditText) {
21+
this.reactEditText = reactEditText;
22+
screenDensity = reactEditText.getResources().getDisplayMetrics().density;
23+
}
24+
25+
void handleDown(final MotionEvent downEvent) {
26+
currentDownEvent = new TimestampedMotionEvent(System.currentTimeMillis(), downEvent);
27+
}
28+
29+
void cancelPress() {
30+
currentDownEvent = null;
31+
}
32+
33+
void handleUp(final MotionEvent upEvent) {
34+
if (currentDownEvent == null) {
35+
return;
36+
}
37+
38+
final TimestampedMotionEvent downEvent = currentDownEvent;
39+
currentDownEvent = null;
40+
41+
// for now, if we're not forcing showing the keyboard on clicks, we don't care if it was a
42+
// click. we also early return if the view is not enabled.
43+
if (!(forceShowKeyboardOnClicks() && reactEditText.isEnabled())) {
44+
return;
45+
}
46+
47+
// make sure the press event was close enough in time
48+
final long now = System.currentTimeMillis();
49+
final long timeDelta = now - downEvent.timestamp;
50+
if (timeDelta > MAX_CLICK_DURATION_MS) {
51+
return;
52+
}
53+
54+
// make sure the press event was close enough in distance
55+
final float oldX = downEvent.motionEvent.getRawX();
56+
final float oldY = downEvent.motionEvent.getRawY();
57+
final float newX = upEvent.getRawX();
58+
final float newY = upEvent.getRawY();
59+
60+
// distance = sqrt((x2 − x1)^2 + (y2 − y1)^2)
61+
final double distancePx = Math.sqrt(
62+
Math.pow((newX - oldX), 2) + Math.pow((newY - oldY), 2)
63+
);
64+
65+
double distanceDp = distancePx / screenDensity;
66+
if (distanceDp > MAX_CLICK_DISTANCE_DP) {
67+
return;
68+
}
69+
70+
reactEditText.showSoftKeyboard();
71+
}
72+
73+
/**
74+
* There is a bug on Android 7/8/9 where clicking the view while it is already
75+
* focused does not show the keyboard. On those API levels, we force showing
76+
* the keyboard when we detect a click.
77+
*/
78+
private static boolean forceShowKeyboardOnClicks() {
79+
return Build.VERSION.SDK_INT <= Build.VERSION_CODES.P;
80+
}
81+
82+
private static class TimestampedMotionEvent {
83+
84+
final long timestamp;
85+
final MotionEvent motionEvent;
86+
87+
TimestampedMotionEvent(final long timestamp, final MotionEvent motionEvent) {
88+
this.timestamp = timestamp;
89+
this.motionEvent = motionEvent;
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)