mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Expose resolveCustomDirectEventName from UIManager interface
Summary: Expose `resolveCustomDirectEventName` from UIManager interface for Bridgeless Mode+NativeAnimatedModule. We cannot remove the interface from the Non-Fabric UIManagerModule yet, as it would break downstream open-source dependencies, so I just marked it deprecated. Note that this still doesn't totally fix issues with Bridgeless mode: generally I have to navigate to a Bridgeless surface, exit it, and then navigate back, and only on the 2nd navigation does everything seem to work properly... Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D22483508 fbshipit-source-id: 685126e7e51aa5d0fd60ad5d4ecc44e8c6c3029d
This commit is contained in:
committed by
Facebook GitHub Bot
parent
95d05fc415
commit
80f13412e5
@@ -304,6 +304,10 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||
mNumNonFabricAnimations++;
|
||||
}
|
||||
|
||||
if (mNodesManager != null) {
|
||||
mNodesManager.initializeEventListenerForUIManagerType(mUIManagerType);
|
||||
}
|
||||
|
||||
// Subscribe to UIManager (Fabric or non-Fabric) lifecycle events if we haven't yet
|
||||
if ((mInitializedForFabric && mUIManagerType == UIManagerType.FABRIC)
|
||||
|| (mInitializedForNonFabric && mUIManagerType == UIManagerType.DEFAULT)) {
|
||||
|
||||
+74
-10
@@ -9,8 +9,8 @@ package com.facebook.react.animated;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.JSApplicationCausedNativeException;
|
||||
@@ -25,7 +25,7 @@ import com.facebook.react.bridge.UiThreadUtil;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.UIManagerHelper;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.uimanager.events.EventDispatcherListener;
|
||||
@@ -62,23 +62,51 @@ import java.util.Queue;
|
||||
// Mapping of a view tag and an event name to a list of event animation drivers. 99% of the time
|
||||
// there will be only one driver per mapping so all code code should be optimized around that.
|
||||
private final Map<String, List<EventAnimationDriver>> mEventDrivers = new HashMap<>();
|
||||
private final UIManagerModule.CustomEventNamesResolver mCustomEventNamesResolver;
|
||||
private final ReactApplicationContext mReactApplicationContext;
|
||||
private int mAnimatedGraphBFSColor = 0;
|
||||
private int mNumInconsistentFrames = 0;
|
||||
// Used to avoid allocating a new array on every frame in `runUpdates` and `onEventDispatch`.
|
||||
private final List<AnimatedNode> mRunUpdateNodeList = new LinkedList<>();
|
||||
|
||||
private boolean mEventListenerInitializedForFabric = false;
|
||||
private boolean mEventListenerInitializedForNonFabric = false;
|
||||
|
||||
public NativeAnimatedNodesManager(ReactApplicationContext reactApplicationContext) {
|
||||
mReactApplicationContext = reactApplicationContext;
|
||||
}
|
||||
|
||||
UIManagerModule uiManager =
|
||||
Assertions.assertNotNull(reactApplicationContext.getNativeModule(UIManagerModule.class));
|
||||
/**
|
||||
* Initialize event listeners for Fabric UIManager or non-Fabric UIManager, exactly once. Once
|
||||
* Fabric is the only UIManager, this logic can be simplified. This is only called on the JS
|
||||
* thread.
|
||||
*
|
||||
* @param uiManagerType
|
||||
*/
|
||||
@UiThread
|
||||
public void initializeEventListenerForUIManagerType(@UIManagerType final int uiManagerType) {
|
||||
if ((uiManagerType == UIManagerType.FABRIC && mEventListenerInitializedForFabric)
|
||||
|| (uiManagerType == UIManagerType.DEFAULT && mEventListenerInitializedForNonFabric)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uiManager.<EventDispatcher>getEventDispatcher().addListener(this);
|
||||
// TODO T64216139 Remove dependency of UIManagerModule when the Constants are not in Native
|
||||
// anymore
|
||||
mCustomEventNamesResolver = uiManager.getDirectEventNamesResolver();
|
||||
final NativeAnimatedNodesManager self = this;
|
||||
mReactApplicationContext.runOnUiQueueThread(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
UIManager uiManager =
|
||||
UIManagerHelper.getUIManager(mReactApplicationContext, uiManagerType);
|
||||
if (uiManager != null) {
|
||||
uiManager.<EventDispatcher>getEventDispatcher().addListener(self);
|
||||
|
||||
if (uiManagerType == UIManagerType.FABRIC) {
|
||||
mEventListenerInitializedForFabric = true;
|
||||
} else {
|
||||
mEventListenerInitializedForNonFabric = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*package*/ @Nullable
|
||||
@@ -90,6 +118,7 @@ import java.util.Queue;
|
||||
return mActiveAnimations.size() > 0 || mUpdatedNodes.size() > 0;
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void createAnimatedNode(int tag, ReadableMap config) {
|
||||
if (mAnimatedNodes.get(tag) != null) {
|
||||
throw new JSApplicationIllegalArgumentException(
|
||||
@@ -129,11 +158,13 @@ import java.util.Queue;
|
||||
mUpdatedNodes.put(tag, node);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void dropAnimatedNode(int tag) {
|
||||
mAnimatedNodes.remove(tag);
|
||||
mUpdatedNodes.remove(tag);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void startListeningToAnimatedNodeValue(int tag, AnimatedNodeValueListener listener) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -143,6 +174,7 @@ import java.util.Queue;
|
||||
((ValueAnimatedNode) node).setValueListener(listener);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void stopListeningToAnimatedNodeValue(int tag) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -152,6 +184,7 @@ import java.util.Queue;
|
||||
((ValueAnimatedNode) node).setValueListener(null);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void setAnimatedNodeValue(int tag, double value) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -163,6 +196,7 @@ import java.util.Queue;
|
||||
mUpdatedNodes.put(tag, node);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void setAnimatedNodeOffset(int tag, double offset) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -173,6 +207,7 @@ import java.util.Queue;
|
||||
mUpdatedNodes.put(tag, node);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void flattenAnimatedNodeOffset(int tag) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -182,6 +217,7 @@ import java.util.Queue;
|
||||
((ValueAnimatedNode) node).flattenOffset();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void extractAnimatedNodeOffset(int tag) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -191,6 +227,7 @@ import java.util.Queue;
|
||||
((ValueAnimatedNode) node).extractOffset();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void startAnimatingNode(
|
||||
int animationId, int animatedNodeTag, ReadableMap animationConfig, Callback endCallback) {
|
||||
AnimatedNode node = mAnimatedNodes.get(animatedNodeTag);
|
||||
@@ -228,6 +265,7 @@ import java.util.Queue;
|
||||
mActiveAnimations.put(animationId, animation);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void stopAnimationsForNode(AnimatedNode animatedNode) {
|
||||
// in most of the cases there should never be more than a few active animations running at the
|
||||
// same time. Therefore it does not make much sense to create an animationId -> animation
|
||||
@@ -248,6 +286,7 @@ import java.util.Queue;
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void stopAnimation(int animationId) {
|
||||
// in most of the cases there should never be more than a few active animations running at the
|
||||
// same time. Therefore it does not make much sense to create an animationId -> animation
|
||||
@@ -272,6 +311,7 @@ import java.util.Queue;
|
||||
// when the animation is already over.
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void connectAnimatedNodes(int parentNodeTag, int childNodeTag) {
|
||||
AnimatedNode parentNode = mAnimatedNodes.get(parentNodeTag);
|
||||
if (parentNode == null) {
|
||||
@@ -302,6 +342,7 @@ import java.util.Queue;
|
||||
mUpdatedNodes.put(childNodeTag, childNode);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void connectAnimatedNodeToView(int animatedNodeTag, int viewTag) {
|
||||
AnimatedNode node = mAnimatedNodes.get(animatedNodeTag);
|
||||
if (node == null) {
|
||||
@@ -336,6 +377,7 @@ import java.util.Queue;
|
||||
mUpdatedNodes.put(animatedNodeTag, node);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void disconnectAnimatedNodeFromView(int animatedNodeTag, int viewTag) {
|
||||
AnimatedNode node = mAnimatedNodes.get(animatedNodeTag);
|
||||
if (node == null) {
|
||||
@@ -352,6 +394,7 @@ import java.util.Queue;
|
||||
propsAnimatedNode.disconnectFromView(viewTag);
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void getValue(int tag, Callback callback) {
|
||||
AnimatedNode node = mAnimatedNodes.get(tag);
|
||||
if (node == null || !(node instanceof ValueAnimatedNode)) {
|
||||
@@ -361,6 +404,7 @@ import java.util.Queue;
|
||||
callback.invoke(((ValueAnimatedNode) node).getValue());
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void restoreDefaultValues(int animatedNodeTag) {
|
||||
AnimatedNode node = mAnimatedNodes.get(animatedNodeTag);
|
||||
// Restoring default values needs to happen before UIManager operations so it is
|
||||
@@ -380,6 +424,7 @@ import java.util.Queue;
|
||||
propsAnimatedNode.restoreDefaultValues();
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void addAnimatedEventToView(int viewTag, String eventName, ReadableMap eventMapping) {
|
||||
int nodeTag = eventMapping.getInt("animatedValueTag");
|
||||
AnimatedNode node = mAnimatedNodes.get(nodeTag);
|
||||
@@ -411,6 +456,7 @@ import java.util.Queue;
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
public void removeAnimatedEventFromView(int viewTag, String eventName, int animatedValueTag) {
|
||||
String key = viewTag + eventName;
|
||||
if (mEventDrivers.containsKey(key)) {
|
||||
@@ -429,6 +475,7 @@ import java.util.Queue;
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
@Override
|
||||
public void onEventDispatch(final Event event) {
|
||||
// Events can be dispatched from any thread so we have to make sure handleEvent is run from the
|
||||
@@ -446,10 +493,25 @@ import java.util.Queue;
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void handleEvent(Event event) {
|
||||
if (!mEventDrivers.isEmpty()) {
|
||||
// If the event has a different name in native convert it to it's JS name.
|
||||
String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName());
|
||||
// TODO T64216139 Remove dependency of UIManagerModule when the Constants are not in Native
|
||||
// anymore
|
||||
if (mReactApplicationContext == null) {
|
||||
return;
|
||||
}
|
||||
UIManager uiManager =
|
||||
UIManagerHelper.getUIManagerForReactTag(mReactApplicationContext, event.getViewTag());
|
||||
if (uiManager == null) {
|
||||
return;
|
||||
}
|
||||
String eventName = uiManager.resolveCustomDirectEventName(event.getEventName());
|
||||
if (eventName == null) {
|
||||
eventName = "";
|
||||
}
|
||||
|
||||
List<EventAnimationDriver> driversForKey = mEventDrivers.get(event.getViewTag() + eventName);
|
||||
if (driversForKey != null) {
|
||||
for (EventAnimationDriver driver : driversForKey) {
|
||||
@@ -475,6 +537,7 @@ import java.util.Queue;
|
||||
* sub-graph of *active* nodes. This is done by adding node to the BFS queue only if all its
|
||||
* "predecessors" have already been visited.
|
||||
*/
|
||||
@UiThread
|
||||
public void runUpdates(long frameTimeNanos) {
|
||||
UiThreadUtil.assertOnUiThread();
|
||||
boolean hasFinishedAnimations = false;
|
||||
@@ -517,6 +580,7 @@ import java.util.Queue;
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
private void updateNodes(List<AnimatedNode> nodes) {
|
||||
int activeNodesCount = 0;
|
||||
int updatedNodesCount = 0;
|
||||
|
||||
@@ -123,4 +123,9 @@ public interface UIManager extends JSIModule, PerformanceCounter {
|
||||
* @param event parameters
|
||||
*/
|
||||
void receiveEvent(int reactTag, String eventName, @Nullable WritableMap event);
|
||||
|
||||
/** Resolves Direct Event name exposed to JS from the one known to the Native side. */
|
||||
@Deprecated
|
||||
@Nullable
|
||||
String resolveCustomDirectEventName(@Nullable String eventName);
|
||||
}
|
||||
|
||||
@@ -1056,6 +1056,19 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||
// TODO T31905686: Remove this method and add support for multi-threading performance counters
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public String resolveCustomDirectEventName(@Nullable String eventName) {
|
||||
if (eventName == null) {
|
||||
return null;
|
||||
}
|
||||
if (eventName.substring(0, 3).equals("top")) {
|
||||
return "on" + eventName.substring(3);
|
||||
}
|
||||
return eventName;
|
||||
}
|
||||
|
||||
// Called from Binding.cpp
|
||||
@DoNotStrip
|
||||
@AnyThread
|
||||
|
||||
@@ -357,20 +357,30 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||
}
|
||||
|
||||
/** Resolves Direct Event name exposed to JS from the one known to the Native side. */
|
||||
@Deprecated
|
||||
public CustomEventNamesResolver getDirectEventNamesResolver() {
|
||||
return new CustomEventNamesResolver() {
|
||||
@Override
|
||||
public @Nullable String resolveCustomEventName(String eventName) {
|
||||
Map<String, String> customEventType =
|
||||
(Map<String, String>) mCustomDirectEvents.get(eventName);
|
||||
if (customEventType != null) {
|
||||
return customEventType.get("registrationName");
|
||||
}
|
||||
return eventName;
|
||||
public @Nullable String resolveCustomEventName(@Nullable String eventName) {
|
||||
return resolveCustomDirectEventName(eventName);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public String resolveCustomDirectEventName(@Nullable String eventName) {
|
||||
if (eventName != null) {
|
||||
Map<String, String> customEventType =
|
||||
(Map<String, String>) mCustomDirectEvents.get(eventName);
|
||||
if (customEventType != null) {
|
||||
return customEventType.get("registrationName");
|
||||
}
|
||||
}
|
||||
return eventName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void profileNextBatch() {
|
||||
mUIImplementation.profileNextBatch();
|
||||
|
||||
Reference in New Issue
Block a user