You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Description
After updating from 1.8.0 to 1.10.3 some of my users reported problems about buttons getting stuck on Android.
In #1172 an override for `onTouchEvent` was introduced to block subsequent calls. A check for event times was added with the assumption that every event will have a different event time. You can find further information in #1172 (comment) and in the Javadoc of `onTouchEvent`.
Unfortunately, events with the same event time can indeed occur on some devices for different actions, which has glaring consequences. Some of my users and myself experienced situations where - after a quick touch - the ripple effect was halted, the onPress was not fired, no touch sound was played and no other button was accepting any inputs. It seemed like the app thought the finger was still on the button.
This is due to the following sequence of events sometimes happening (fictional event times):
1. `ACTION_DOWN` is sent at EventTime 1000
2. `ACTION_MOVE` is sent at EventTime 2000 (Android sends at least one, even without a move)
3. `ACTION_UP` is **also** sent at EventTime 2000, resulting in not being handled and keeping the button touched
Furthermore, my thesis is confirmed by the fact that touching the same button again is sending another `ACTION_UP` and thus the and all other buttons are unstucked. The problem can even be forced to a certain extent by combining the quick touch with a small swiping gesture, which sends even more `ACTION_MOVE` events.
The only inexplicable part for me is that the frequency of this issue happening varies greatly from device to device. It happened every ~5 touches on a Huawei P30 (and on nearly every touch with the little forced swipe), infrequently but multiple times on a Samsung Galaxy S21, and couldn't be reproduced on an Oppo Find X2 Lite, LG G6, and the Android emulator.
It is also worth mentioning that a reproduction on statically placed buttons is easier, since buttons in scrollable views send an `ACTION_CANCEL` instead of an `ACTION_UP` on the slightest movement in the scrolling direction. I have so far not had a case where those event times were the same.
## How it's fixed
- Analogous to the check of the last event time, I have added another check for the last action.
- Because 0 is a possible value for an action (`ACTION_DOWN` with first pointer), I set the initial value to -1. To keep everything consistent, I've also set the default value of the event time to -1.
- By using `getAction` instead of `getActionMasked`, this solution is also pointer-sensitive.
- Of course I have also expanded the Javadoc. :)
After implementing these changes, I was no longer able to reproduce the issue on the P30 and S21 (or the other devices).
## Considerations
This is kind of an extension to @jakub-gonet's assumption that there will not be two or more events that have the same event time and action in immediate succession. There may still be another way in which unexpected consequences can occur, but my change ensures that the problems that have arisen so far in my app in production under normal use are eliminated. In addition, the check in `onTouchEvent` is much more robust.
Even if it did not happen in my tests, I can also very well imagine that the same event time could occur within scrollable views between `ACTION_MOVE` and `ACTION_CANCEL`. If so, my change would prevent such problems as well.
## Test plan
Tested with the example code of #1172 on the above mentioned 5 devices, where I appended the following `BaseButton` and `RectButton`. The fix naturally applies to all Touchables since they use `BaseButton` internally.
```jsx
import {
BaseButton,
RectButton,
} from 'react-native-gesture-handler';
...
<>
<BaseButton
style={{
width: 200,
height: 50,
backgroundColor: 'lightgreen',
}}
onPress={() => console.log('pressed RNGH BaseButton')}>
<Text>RNGH BaseButton</Text>
</BaseButton>
<RectButton
style={{
width: 200,
height: 50,
backgroundColor: 'lightgreen',
}}
onPress={() => console.log('pressed RNGH RectButton')}>
<Text>RNGH RectButton</Text>
</RectButton>
</>
```
Co-authored-by: Jakub Gonet <jakub.gonet@swmansion.com>
0 commit comments