7
7
8
8
import android .os .SystemClock ;
9
9
import android .util .Log ;
10
- import android .view .MotionEvent ;
11
- import android .view .InputDevice ;
12
10
import android .util .SparseArray ;
11
+ import android .view .InputDevice ;
12
+ import android .view .MotionEvent ;
13
13
14
14
import org .mozilla .vrbrowser .ui .widgets .Widget ;
15
15
import org .mozilla .vrbrowser .utils .SystemUtils ;
16
16
17
17
import java .util .Arrays ;
18
- import java .util .List ;
19
18
20
19
public class MotionEventGenerator {
21
20
static final String LOGTAG = SystemUtils .createLogtag (MotionEventGenerator .class );
@@ -53,11 +52,11 @@ static class Device {
53
52
private static SparseArray <Device > devices = new SparseArray <>();
54
53
55
54
56
- private static void generateEvent (Widget aWidget , Device aDevice , int aAction , boolean aGeneric ) {
57
- generateEvent (aWidget , aDevice , aAction , aGeneric , aDevice .mCoords );
55
+ private static void generateEvent (Widget aWidget , Device aDevice , boolean aFocused , int aAction , boolean aGeneric ) {
56
+ generateEvent (aWidget , aDevice , aFocused , aAction , aGeneric , aDevice .mCoords );
58
57
}
59
58
60
- private static void generateEvent (Widget aWidget , Device aDevice , int aAction , boolean aGeneric , MotionEvent .PointerCoords [] aCoords ) {
59
+ private static void generateEvent (Widget aWidget , Device aDevice , boolean aFocused , int aAction , boolean aGeneric , MotionEvent .PointerCoords [] aCoords ) {
61
60
MotionEvent event = MotionEvent .obtain (
62
61
/*mDownTime*/ aDevice .mDownTime ,
63
62
/*eventTime*/ SystemClock .uptimeMillis (),
@@ -69,19 +68,24 @@ private static void generateEvent(Widget aWidget, Device aDevice, int aAction, b
69
68
/*buttonState*/ 0 ,
70
69
/*xPrecision*/ 0 ,
71
70
/*yPrecision*/ 0 ,
72
- /*deviceId*/ 0 , // aDevice.mDevice,
71
+ /*deviceId*/ aDevice .mDevice ,
73
72
/*edgeFlags*/ 0 ,
74
73
/*source*/ InputDevice .SOURCE_TOUCHSCREEN ,
75
74
/*flags*/ 0 );
76
75
if (aGeneric ) {
77
- aWidget .handleHoverEvent (event );
76
+ if (aWidget .supportsMultipleInputDevices ()) {
77
+ aWidget .handleHoverEvent (event );
78
+
79
+ } else if (aFocused ) {
80
+ aWidget .handleHoverEvent (event );
81
+ }
78
82
} else {
79
83
aWidget .handleTouchEvent (event );
80
84
}
81
85
event .recycle ();
82
86
}
83
87
84
- public static void dispatch (Widget aWidget , int aDevice , boolean aPressed , float aX , float aY ) {
88
+ public static void dispatch (Widget aWidget , int aDevice , boolean aFocused , boolean aPressed , float aX , float aY ) {
85
89
Device device = devices .get (aDevice );
86
90
if (device == null ) {
87
91
device = new Device (aDevice );
@@ -99,41 +103,66 @@ public static void dispatch(Widget aWidget, int aDevice, boolean aPressed, float
99
103
}
100
104
if (!aPressed && (device .mPreviousWidget != null ) && (device .mPreviousWidget != aWidget )) {
101
105
if (device .mWasPressed ) {
102
- generateEvent (device .mPreviousWidget , device , MotionEvent .ACTION_CANCEL , false );
106
+ generateEvent (device .mPreviousWidget , device , aFocused , MotionEvent .ACTION_CANCEL , false );
103
107
device .mWasPressed = false ;
104
108
}
105
- generateEvent (device .mPreviousWidget , device , MotionEvent .ACTION_HOVER_EXIT , true , device .mMouseOutCoords );
109
+ generateEvent (device .mPreviousWidget , device , aFocused , MotionEvent .ACTION_HOVER_EXIT , true , device .mMouseOutCoords );
106
110
device .mPreviousWidget = null ;
107
111
}
108
112
if (aWidget == null ) {
109
113
device .mPreviousWidget = null ;
110
114
return ;
111
115
}
112
116
if (aWidget != device .mPreviousWidget && !aPressed ) {
113
- generateEvent (aWidget , device , MotionEvent .ACTION_HOVER_ENTER , true );
117
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_HOVER_ENTER , true );
114
118
}
115
119
if (aPressed && !device .mWasPressed ) {
116
120
device .mDownTime = SystemClock .uptimeMillis ();
117
121
device .mWasPressed = true ;
118
- generateEvent (aWidget , device , MotionEvent .ACTION_HOVER_EXIT , true );
119
- generateEvent (aWidget , device , MotionEvent .ACTION_DOWN , false );
122
+ if (!isOtherDeviceDown (device .mDevice )) {
123
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_HOVER_EXIT , true );
124
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_DOWN , false );
125
+ }
120
126
device .mTouchStartWidget = aWidget ;
121
127
} else if (!aPressed && device .mWasPressed ) {
122
128
device .mWasPressed = false ;
123
- generateEvent (device .mTouchStartWidget , device , MotionEvent .ACTION_UP , false );
124
- generateEvent (aWidget , device , MotionEvent .ACTION_HOVER_ENTER , true );
129
+ if (!isOtherDeviceDown (device .mDevice )) {
130
+ generateEvent (device .mTouchStartWidget , device , aFocused , MotionEvent .ACTION_UP , false );
131
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_HOVER_ENTER , true );
132
+ }
133
+ device .mTouchStartWidget = null ;
125
134
} else if (moving && aPressed ) {
126
- generateEvent (aWidget , device , MotionEvent .ACTION_MOVE , false );
135
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_MOVE , false );
127
136
} else if (moving ) {
128
- generateEvent (aWidget , device , MotionEvent .ACTION_HOVER_MOVE , true );
137
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_HOVER_MOVE , true );
129
138
} else {
130
139
Log .e ("VRB" , "Unknown touch event action" );
131
140
return ;
132
141
}
133
142
device .mPreviousWidget = aWidget ;
134
143
}
135
144
136
- public static void dispatchScroll (Widget aWidget , int aDevice , float aX , float aY ) {
145
+ /**
146
+ * Checks if any other device has an ongoing touch down event.
147
+ * Android throw away all previous state when starting a new touch gesture
148
+ * and this seem to make the previous touch to be sent up the view hierarchy.
149
+ * To avoid this we check if any other device has a button down before sending
150
+ * touch down/up event.
151
+ * @param deviceId Device Id to filter
152
+ * @return true if any other device has a button down, false otherwise
153
+ */
154
+ private static boolean isOtherDeviceDown (int deviceId ) {
155
+ boolean result = false ;
156
+ for (int i =0 ; i <devices .size (); i ++) {
157
+ if (i != deviceId ) {
158
+ result |= devices .get (i ).mTouchStartWidget != null ;
159
+ }
160
+ }
161
+
162
+ return result ;
163
+ }
164
+
165
+ public static void dispatchScroll (Widget aWidget , int aDevice , boolean aFocused , float aX , float aY ) {
137
166
Device device = devices .get (aDevice );
138
167
if (device == null ) {
139
168
device = new Device (aDevice );
@@ -142,7 +171,7 @@ public static void dispatchScroll(Widget aWidget, int aDevice, float aX, float a
142
171
device .mPreviousWidget = aWidget ;
143
172
device .mCoords [0 ].setAxisValue (MotionEvent .AXIS_VSCROLL , aY );
144
173
device .mCoords [0 ].setAxisValue (MotionEvent .AXIS_HSCROLL , aX );
145
- generateEvent (aWidget , device , MotionEvent .ACTION_SCROLL , true );
174
+ generateEvent (aWidget , device , aFocused , MotionEvent .ACTION_SCROLL , true );
146
175
device .mCoords [0 ].setAxisValue (MotionEvent .AXIS_VSCROLL , 0.0f );
147
176
device .mCoords [0 ].setAxisValue (MotionEvent .AXIS_HSCROLL , 0.0f );
148
177
}
0 commit comments