From 5ef9e1fffe1415d88dc9cbe78a4d614f75c7e8a8 Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Thu, 2 Jan 2025 11:18:07 -0800 Subject: [PATCH] TouchEventCoalescingKeyHelper -> Kotlin (#48448) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48448 # Changelog: [Internal] - As in the title. Reviewed By: tdn120 Differential Revision: D67759862 fbshipit-source-id: 7a8e133962cdc43aed0bae38a89d37fb7e6031a6 --- .../ReactAndroid/api/ReactAndroid.api | 12 +-- .../events/TouchEventCoalescingKeyHelper.java | 85 ------------------- .../events/TouchEventCoalescingKeyHelper.kt | 77 +++++++++++++++++ 3 files changed, 83 insertions(+), 91 deletions(-) delete mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java create mode 100644 packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.kt diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 74909bcfda3..0f24d4b118b 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -5752,13 +5752,13 @@ public final class com/facebook/react/uimanager/events/TouchEvent$Companion { public final fun obtain (ILcom/facebook/react/uimanager/events/TouchEventType;Landroid/view/MotionEvent;JFFLcom/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper;)Lcom/facebook/react/uimanager/events/TouchEvent; } -public class com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper { +public final class com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper { public fun ()V - public fun addCoalescingKey (J)V - public fun getCoalescingKey (J)S - public fun hasCoalescingKey (J)Z - public fun incrementCoalescingKey (J)V - public fun removeCoalescingKey (J)V + public final fun addCoalescingKey (J)V + public final fun getCoalescingKey (J)S + public final fun hasCoalescingKey (J)Z + public final fun incrementCoalescingKey (J)V + public final fun removeCoalescingKey (J)V } public final class com/facebook/react/uimanager/events/TouchEventType : java/lang/Enum { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java deleted file mode 100644 index c5769fc4b41..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.uimanager.events; - -import android.util.SparseIntArray; -import com.facebook.infer.annotation.Nullsafe; - -/** - * Utility for determining coalescing keys for TouchEvents. To preserve proper ordering of events, - * move events should only be coalesced if there has been no up/down event between them (this - * basically only applies to multitouch since for single touches an up would signal the end of the - * gesture). To illustrate to kind of coalescing we want, imagine we are coalescing the following - * touch stream: - * - *

(U = finger up, D = finger down, M = move) D MMMMM D MMMMMMMMMMMMMM U MMMMM D MMMMMM U U - * - *

We want to make sure to coalesce this as - * - *

D M D M U M D U U - * - *

and *not* - * - *

D D U M D U U - * - *

To accomplish this, this class provides a way to initialize a coalescing key for a gesture and - * then increment it for every pointer up/down that occurs during that single gesture. - * - *

We identify a single gesture based on {@link android.view.MotionEvent#getDownTime()} which - * will stay constant for a given set of related touches on a single view. - * - *

NB: even though down time is a long, we cast as an int using the least significant bits as the - * identifier. In practice, we will not be coalescing over a time range where the most significant - * bits of that time range matter. This would require a gesture that lasts Integer.MAX_VALUE * 2 ms, - * or ~48 days. - * - *

NB: we assume two gestures cannot begin at the same time. - * - *

NB: this class should only be used from the UI thread. - */ -@Nullsafe(Nullsafe.Mode.LOCAL) -public class TouchEventCoalescingKeyHelper { - - private final SparseIntArray mDownTimeToCoalescingKey = new SparseIntArray(); - - /** Starts tracking a new coalescing key corresponding to the gesture with this down time. */ - public void addCoalescingKey(long downTime) { - mDownTimeToCoalescingKey.put((int) downTime, 0); - } - - /** Increments the coalescing key corresponding to the gesture with this down time. */ - public void incrementCoalescingKey(long downTime) { - int currentValue = mDownTimeToCoalescingKey.get((int) downTime, -1); - if (currentValue == -1) { - throw new RuntimeException("Tried to increment non-existent cookie"); - } - mDownTimeToCoalescingKey.put((int) downTime, currentValue + 1); - } - - /** Gets the coalescing key corresponding to the gesture with this down time. */ - public short getCoalescingKey(long downTime) { - int currentValue = mDownTimeToCoalescingKey.get((int) downTime, -1); - if (currentValue == -1) { - throw new RuntimeException("Tried to get non-existent cookie"); - } - return ((short) (0xffff & currentValue)); - } - - /** Stops tracking a new coalescing key corresponding to the gesture with this down time. */ - public void removeCoalescingKey(long downTime) { - mDownTimeToCoalescingKey.delete((int) downTime); - } - - public boolean hasCoalescingKey(long downTime) { - int currentValue = mDownTimeToCoalescingKey.get((int) downTime, -1); - if (currentValue == -1) { - return false; - } - return true; - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.kt new file mode 100644 index 00000000000..5f54ac23443 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/TouchEventCoalescingKeyHelper.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.uimanager.events + +import android.util.SparseIntArray + +/** + * Utility for determining coalescing keys for TouchEvents. To preserve proper ordering of events, + * move events should only be coalesced if there has been no up/down event between them (this + * basically only applies to multitouch since for single touches an up would signal the end of the + * gesture). To illustrate to kind of coalescing we want, imagine we are coalescing the following + * touch stream: + * + * (U = finger up, D = finger down, M = move) D MMMMM D MMMMMMMMMMMMMM U MMMMM D MMMMMM U U + * + * We want to make sure to coalesce this as + * + * D M D M U M D U U + * + * and *not* + * + * D D U M D U U + * + * To accomplish this, this class provides a way to initialize a coalescing key for a gesture and + * then increment it for every pointer up/down that occurs during that single gesture. + * + * We identify a single gesture based on [android.view.MotionEvent.getDownTime] which will stay + * constant for a given set of related touches on a single view. + * + * NB: even though down time is a long, we cast as an int using the least significant bits as the + * identifier. In practice, we will not be coalescing over a time range where the most significant + * bits of that time range matter. This would require a gesture that lasts Integer.MAX_VALUE * 2 ms, + * or ~48 days. + * + * NB: we assume two gestures cannot begin at the same time. + * + * NB: this class should only be used from the UI thread. + */ +public class TouchEventCoalescingKeyHelper { + private val downTimeToCoalescingKey = SparseIntArray() + + /** Starts tracking a new coalescing key corresponding to the gesture with this down time. */ + public fun addCoalescingKey(downTime: Long) { + downTimeToCoalescingKey.put(downTime.toInt(), 0) + } + + /** Increments the coalescing key corresponding to the gesture with this down time. */ + public fun incrementCoalescingKey(downTime: Long) { + val currentValue = downTimeToCoalescingKey[downTime.toInt(), -1] + if (currentValue == -1) { + throw RuntimeException("Tried to increment non-existent cookie") + } + downTimeToCoalescingKey.put(downTime.toInt(), currentValue + 1) + } + + /** Gets the coalescing key corresponding to the gesture with this down time. */ + public fun getCoalescingKey(downTime: Long): Short { + val currentValue = downTimeToCoalescingKey[downTime.toInt(), -1] + if (currentValue == -1) { + throw RuntimeException("Tried to get non-existent cookie") + } + return ((0xffff and currentValue).toShort()) + } + + /** Stops tracking a new coalescing key corresponding to the gesture with this down time. */ + public fun removeCoalescingKey(downTime: Long) { + downTimeToCoalescingKey.delete(downTime.toInt()) + } + + public fun hasCoalescingKey(downTime: Long): Boolean = + downTimeToCoalescingKey[downTime.toInt(), -1] != -1 +}