Skip to content

Commit

Permalink
Set event category for touch events on Android
Browse files Browse the repository at this point in the history
Summary:
Updates event category deduction to match iOS implementation.
The event priority is used by concurrent mode to prioritize certain events, where Cxx part already assigns the correct priority based on the `ContinuousStart` -> `ContinuousEnd` spans. These spans can be deduced from the touch events, which we do in this implementation.

All events that can be "coalesced" (dispatched through `invokeUnique`) are assigned `Continuous` by default in Fabric core, so scroll/slider change events will never be discrete.

Changelog:
[Internal] Add category deduction to Android touch events

Reviewed By: mdvacca

Differential Revision: D31233233

fbshipit-source-id: f5b039aa137f1b4d2e2b15578bfc29ab6903a081
  • Loading branch information
Andrei Shikov authored and facebook-github-bot committed Sep 29, 2021
1 parent bf4c6b3 commit 155a1a8
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import com.facebook.react.common.mapbuffer.ReadableMapBuffer;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.react.fabric.events.EventBeatManager;
import com.facebook.react.fabric.events.EventCategoryDef;
import com.facebook.react.fabric.events.EventEmitterWrapper;
import com.facebook.react.fabric.events.FabricEventEmitter;
import com.facebook.react.fabric.mounting.MountItemDispatcher;
Expand Down Expand Up @@ -829,6 +830,23 @@ public void receiveEvent(
receiveEvent(surfaceId, reactTag, eventName, false, 0, params);
}

public void receiveEvent(
int surfaceId,
int reactTag,
String eventName,
boolean canCoalesceEvent,
int customCoalesceKey,
@Nullable WritableMap params) {
receiveEvent(
surfaceId,
reactTag,
eventName,
canCoalesceEvent,
customCoalesceKey,
params,
EventCategoryDef.UNSPECIFIED);
}

/**
* receiveEvent API that emits an event to C++. If `canCoalesceEvent` is true, that signals that
* C++ may coalesce the event optionally. Otherwise, coalescing can happen in Java before
Expand All @@ -842,14 +860,16 @@ public void receiveEvent(
* @param canCoalesceEvent
* @param customCoalesceKey
* @param params
* @param eventCategory
*/
public void receiveEvent(
int surfaceId,
int reactTag,
String eventName,
boolean canCoalesceEvent,
int customCoalesceKey,
@Nullable WritableMap params) {
@Nullable WritableMap params,
@EventCategoryDef int eventCategory) {
if (ReactBuildConfig.DEBUG && surfaceId == View.NO_ID) {
FLog.d(TAG, "Emitted event without surfaceId: [%d] %s", reactTag, eventName);
}
Expand All @@ -870,7 +890,7 @@ public void receiveEvent(
if (canCoalesceEvent) {
eventEmitter.invokeUnique(eventName, params, customCoalesceKey);
} else {
eventEmitter.invoke(eventName, params);
eventEmitter.invoke(eventName, params, eventCategory);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,15 @@ private native void invokeUniqueEvent(
* @param eventName {@link String} name of the event to execute.
* @param params {@link WritableMap} payload of the event
*/
public synchronized void invoke(@NonNull String eventName, @Nullable WritableMap params) {
public synchronized void invoke(
@NonNull String eventName,
@Nullable WritableMap params,
@EventCategoryDef int eventCategory) {
if (!isValid()) {
return;
}
NativeMap payload = params == null ? new WritableNativeMap() : (NativeMap) params;
invokeEvent(eventName, payload, EventCategoryDef.UNSPECIFIED);
invokeEvent(eventName, payload, eventCategory);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import static com.facebook.react.uimanager.events.TouchesHelper.CHANGED_TOUCHES_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_SURFACE_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_CANCEL_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_END_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TOUCHES_KEY;

import android.util.Pair;
Expand All @@ -25,6 +23,7 @@
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.fabric.FabricUIManager;
import com.facebook.react.uimanager.events.RCTModernEventEmitter;
import com.facebook.react.uimanager.events.TouchEventType;
import com.facebook.systrace.Systrace;
import java.util.HashSet;
import java.util.Set;
Expand Down Expand Up @@ -71,15 +70,23 @@ public void receiveTouches(
@NonNull String eventTopLevelType,
@NonNull WritableArray touches,
@NonNull WritableArray changedIndices) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"FabricEventEmitter.receiveTouches('" + eventTopLevelType + "')");

boolean isPointerEndEvent =
TouchEventType.END.getJsName().equalsIgnoreCase(eventTopLevelType)
|| TouchEventType.CANCEL.getJsName().equalsIgnoreCase(eventTopLevelType);

Pair<WritableArray, WritableArray> result =
TOP_TOUCH_END_KEY.equalsIgnoreCase(eventTopLevelType)
|| TOP_TOUCH_CANCEL_KEY.equalsIgnoreCase(eventTopLevelType)
isPointerEndEvent
? removeTouchesAtIndices(touches, changedIndices)
: touchSubsequence(touches, changedIndices);

WritableArray changedTouches = result.first;
touches = result.second;

int eventCategory = getTouchCategory(eventTopLevelType);
for (int jj = 0; jj < changedTouches.size(); jj++) {
WritableMap touch = getWritableMap(changedTouches.getMap(jj));
// Touch objects can fulfill the role of `DOM` `Event` objects if we set
Expand All @@ -97,8 +104,11 @@ public void receiveTouches(
rootNodeID = targetReactTag;
}

receiveEvent(targetSurfaceId, rootNodeID, eventTopLevelType, false, 0, touch);
mUIManager.receiveEvent(
targetSurfaceId, rootNodeID, eventTopLevelType, false, 0, touch, eventCategory);
}

Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}

/** TODO T31905686 optimize this to avoid copying arrays */
Expand Down Expand Up @@ -174,4 +184,19 @@ private WritableArray copyWritableArray(@NonNull WritableArray array) {
map.merge(readableMap);
return map;
}

@EventCategoryDef
private static int getTouchCategory(String touchEventType) {
int category = EventCategoryDef.UNSPECIFIED;
if (TouchEventType.MOVE.getJsName().equals(touchEventType)) {
category = EventCategoryDef.CONTINUOUS;
} else if (TouchEventType.START.getJsName().equals(touchEventType)) {
category = EventCategoryDef.CONTINUOUS_START;
} else if (TouchEventType.END.getJsName().equals(touchEventType)
|| TouchEventType.CANCEL.getJsName().equals(touchEventType)) {
category = EventCategoryDef.CONTINUOUS_END;
}

return category;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,12 @@ public interface RCTEventEmitter extends JavaScriptModule {
@Deprecated
void receiveEvent(int targetTag, String eventName, @Nullable WritableMap event);

/**
* Receive and process touches
*
* @param eventName JS event name
* @param touches active pointers data
* @param changedIndices indices of changed pointers
*/
void receiveTouches(String eventName, WritableArray touches, WritableArray changedIndices);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,22 @@

/** Touch event types that JS module RCTEventEmitter can understand */
public enum TouchEventType {
START,
END,
MOVE,
CANCEL;
START("topTouchStart"),
END("topTouchEnd"),
MOVE("topTouchMove"),
CANCEL("topTouchCancel");

private final String mJsName;

TouchEventType(String jsName) {
mJsName = jsName;
}

public String getJsName() {
return mJsName;
}

public static String getJSEventName(TouchEventType type) {
switch (type) {
case START:
return "topTouchStart";
case END:
return "topTouchEnd";
case MOVE:
return "topTouchMove";
case CANCEL:
return "topTouchCancel";
default:
throw new IllegalArgumentException("Unexpected type " + type);
}
return type.getJsName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ public class TouchesHelper {
public static final String TARGET_KEY = "target";
public static final String CHANGED_TOUCHES_KEY = "changedTouches";
public static final String TOUCHES_KEY = "touches";
public static final String TOP_TOUCH_END_KEY = "topTouchEnd";
public static final String TOP_TOUCH_CANCEL_KEY = "topTouchCancel";
private static final String PAGE_X_KEY = "pageX";
private static final String PAGE_Y_KEY = "pageY";
private static final String TIMESTAMP_KEY = "timestamp";
Expand Down

0 comments on commit 155a1a8

Please sign in to comment.