Track observed pointer-events using a single bitset

Summary:
Noticed that we were using a different tag for each pointer event observed (and that weren't clearing these properly when recyling views).

Each of these tags is a hashmap entry and a boxed boolean, so we can do much better by just using a single (boxed) integer.

Changelog: [Internal]

Reviewed By: rshest

Differential Revision: D40077519

fbshipit-source-id: 130e78c3641eaedfa8787644b98763fd4367bc27
This commit is contained in:
Pieter De Baets
2022-10-07 04:44:48 -07:00
committed by Facebook GitHub Bot
parent 7680bdeb4f
commit 2afcea2b91
3 changed files with 36 additions and 80 deletions
@@ -27,6 +27,7 @@ import com.facebook.react.common.MapBuilder;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.events.PointerEventHelper;
import com.facebook.react.uimanager.util.ReactFindViewUtil;
import java.util.ArrayList;
import java.util.HashMap;
@@ -68,9 +69,7 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
protected T prepareToRecycleView(@NonNull ThemedReactContext reactContext, T view) {
// Reset tags
view.setTag(null);
view.setTag(R.id.pointer_enter, null);
view.setTag(R.id.pointer_leave, null);
view.setTag(R.id.pointer_move, null);
view.setTag(R.id.pointer_events, null);
view.setTag(R.id.react_test_id, null);
view.setTag(R.id.view_tag_native_id, null);
view.setTag(R.id.labelled_by, null);
@@ -639,55 +638,63 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
FLog.w(ReactConstants.TAG, "%s doesn't support property '%s'", getName(), propName);
}
private static void setPointerEventsFlag(
@NonNull View view, PointerEventHelper.EVENT event, boolean isListening) {
Integer tag = (Integer) view.getTag(R.id.pointer_events);
int currentValue = tag != null ? tag.intValue() : 0;
int flag = 1 << event.ordinal();
view.setTag(R.id.pointer_events, isListening ? (currentValue | flag) : (currentValue & ~flag));
}
/* Experimental W3C Pointer events start */
@ReactProp(name = "onPointerEnter")
public void setPointerEnter(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_enter, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.ENTER, value);
}
@ReactProp(name = "onPointerEnterCapture")
public void setPointerEnterCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_enter_capture, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.ENTER_CAPTURE, value);
}
@ReactProp(name = "onPointerOver")
public void setPointerOver(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_over, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.OVER, value);
}
@ReactProp(name = "onPointerOverCapture")
public void setPointerOverCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_over_capture, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.OVER_CAPTURE, value);
}
@ReactProp(name = "onPointerOut")
public void setPointerOut(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_out, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.OUT, value);
}
@ReactProp(name = "onPointerOutCapture")
public void setPointerOutCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_out_capture, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.OUT_CAPTURE, value);
}
@ReactProp(name = "onPointerLeave")
public void setPointerLeave(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_leave, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.LEAVE, value);
}
@ReactProp(name = "onPointerLeaveCapture")
public void setPointerLeaveCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_leave_capture, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.LEAVE_CAPTURE, value);
}
@ReactProp(name = "onPointerMove")
public void setPointerMove(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_move, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.MOVE, value);
}
@ReactProp(name = "onPointerMoveCapture")
public void setPointerMoveCapture(@NonNull T view, boolean value) {
view.setTag(R.id.pointer_move_capture, value);
setPointerEventsFlag(view, PointerEventHelper.EVENT.MOVE_CAPTURE, value);
}
/* Experimental W3C Pointer events end */
@@ -127,7 +127,6 @@ public class PointerEventHelper {
return false;
}
Object value = null;
switch (event) {
case DOWN:
case DOWN_CAPTURE:
@@ -136,44 +135,11 @@ public class PointerEventHelper {
case CANCEL:
case CANCEL_CAPTURE:
return true;
case ENTER:
value = view.getTag(R.id.pointer_enter);
break;
case ENTER_CAPTURE:
value = view.getTag(R.id.pointer_enter_capture);
break;
case LEAVE:
value = view.getTag(R.id.pointer_leave);
break;
case LEAVE_CAPTURE:
value = view.getTag(R.id.pointer_leave_capture);
break;
case MOVE:
value = view.getTag(R.id.pointer_move);
break;
case MOVE_CAPTURE:
value = view.getTag(R.id.pointer_move_capture);
break;
case OVER:
value = view.getTag(R.id.pointer_over);
break;
case OVER_CAPTURE:
value = view.getTag(R.id.pointer_over_capture);
break;
case OUT:
value = view.getTag(R.id.pointer_out);
break;
case OUT_CAPTURE:
value = view.getTag(R.id.pointer_out_capture);
break;
}
if (value == null) {
return false;
}
if (value instanceof Boolean) {
return (Boolean) value;
Integer pointerEvents = (Integer) view.getTag(R.id.pointer_events);
if (pointerEvents != null) {
return (pointerEvents.intValue() & (1 << event.ordinal())) != 0;
}
return false;
}