Migrate AnimatedNode.java to Kotlin (#45601)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/45601

AnimatedNode.java  -> AnimatedNode.kt

changelog: [internal] internal

Reviewed By: tdn120

Differential Revision: D60076481

fbshipit-source-id: a969b05e9e339457526a454c13a9584363772d85
This commit is contained in:
Arushi Kesarwani
2024-07-28 06:01:14 -07:00
committed by Facebook GitHub Bot
parent 7dec080545
commit 377352d956
18 changed files with 135 additions and 122 deletions
@@ -439,6 +439,23 @@ public abstract interface class com/facebook/react/ViewManagerOnDemandReactPacka
public abstract fun getViewManagerNames (Lcom/facebook/react/bridge/ReactApplicationContext;)Ljava/util/Collection;
}
public abstract class com/facebook/react/animated/AnimatedNode {
public static final field Companion Lcom/facebook/react/animated/AnimatedNode$Companion;
public static final field DEFAULT_ANIMATED_NODE_CHILD_COUNT I
public static final field INITIAL_BFS_COLOR I
public fun <init> ()V
public final fun addChild (Lcom/facebook/react/animated/AnimatedNode;)V
public fun onAttachedToNode (Lcom/facebook/react/animated/AnimatedNode;)V
public fun onDetachedFromNode (Lcom/facebook/react/animated/AnimatedNode;)V
public abstract fun prettyPrint ()Ljava/lang/String;
public final fun prettyPrintWithChildren ()Ljava/lang/String;
public final fun removeChild (Lcom/facebook/react/animated/AnimatedNode;)V
public fun update ()V
}
public final class com/facebook/react/animated/AnimatedNode$Companion {
}
public class com/facebook/react/animated/NativeAnimatedModule : com/facebook/fbreact/specs/NativeAnimatedModuleSpec, com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/bridge/UIManagerListener {
public static final field ANIMATED_MODULE_DEBUG Z
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
@@ -47,7 +47,7 @@ import com.facebook.react.bridge.ReadableMap;
@Override
public String prettyPrint() {
return "AdditionAnimatedNode["
+ mTag
+ tag
+ "]: input nodes: "
+ (mInputNodes != null ? mInputNodes.toString() : "null")
+ " - super: "
@@ -1,78 +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.animated;
import androidx.annotation.Nullable;
import com.facebook.infer.annotation.Assertions;
import com.facebook.infer.annotation.Nullsafe;
import java.util.ArrayList;
import java.util.List;
/** Base class for all Animated.js library node types that can be created on the "native" side. */
/*package*/ @Nullsafe(Nullsafe.Mode.LOCAL)
abstract class AnimatedNode {
public static final int INITIAL_BFS_COLOR = 0;
private static final int DEFAULT_ANIMATED_NODE_CHILD_COUNT = 1;
/*package*/ @Nullable List<AnimatedNode> mChildren; /* lazy-initialized when a child is added */
/*package*/ int mActiveIncomingNodes = 0;
/*package*/ int mBFSColor = INITIAL_BFS_COLOR;
/*package*/ int mTag = -1;
public final void addChild(AnimatedNode child) {
if (mChildren == null) {
mChildren = new ArrayList<>(DEFAULT_ANIMATED_NODE_CHILD_COUNT);
}
Assertions.assertNotNull(mChildren).add(child);
child.onAttachedToNode(this);
}
public final void removeChild(AnimatedNode child) {
if (mChildren == null) {
return;
}
child.onDetachedFromNode(this);
mChildren.remove(child);
}
/**
* Subclasses may want to override this method in order to store a reference to the parent of a
* given node that can then be used to calculate current node's value in {@link #update}. In that
* case it is important to also override {@link #onDetachedFromNode} to clear that reference once
* current node gets detached.
*/
public void onAttachedToNode(AnimatedNode parent) {}
/** See {@link #onAttachedToNode} */
public void onDetachedFromNode(AnimatedNode parent) {}
/**
* This method will be run on each node at most once every repetition of the animation loop. It
* will be executed on a node only when all the node's parent has already been updated. Therefore
* it can be used to calculate node's value.
*/
public void update() {}
/**
* Pretty-printer for the AnimatedNode. Only called in production pre-crash for debug diagnostics.
*/
public abstract String prettyPrint();
public String prettyPrintWithChildren() {
String children = "";
if (mChildren != null && mChildren.size() > 0) {
for (AnimatedNode child : mChildren) {
children += " " + child.mTag;
}
}
return prettyPrint() + (children.length() > 0 ? " children: " + children : "");
}
}
@@ -0,0 +1,74 @@
/*
* 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.animated
import java.util.ArrayList
/** Base class for all Animated.js library node types that can be created on the "native" side. */
public abstract class AnimatedNode {
public companion object {
public const val INITIAL_BFS_COLOR: Int = 0
public const val DEFAULT_ANIMATED_NODE_CHILD_COUNT: Int = 1
}
// TODO: T196787278 Reduce the visibility of these fields to package once we have
// converted the whole module to Kotlin
@JvmField
internal var children: MutableList<AnimatedNode>? =
null /* lazy-initialized when a child is added */
@JvmField internal var activeIncomingNodes: Int = 0
@JvmField internal var BFSColor: Int = INITIAL_BFS_COLOR
@JvmField internal var tag: Int = -1
public fun addChild(child: AnimatedNode): Unit {
val currentChildren =
children
?: ArrayList<AnimatedNode>(DEFAULT_ANIMATED_NODE_CHILD_COUNT).also { children = it }
currentChildren.add(child)
child.onAttachedToNode(this)
}
public fun removeChild(child: AnimatedNode): Unit {
val currentChildren = children ?: return
child.onDetachedFromNode(this)
currentChildren.remove(child)
}
/**
* Subclasses may want to override this method in order to store a reference to the parent of a
* given node that can then be used to calculate current node's value in {@link #update}. In that
* case it is important to also override {@link #onDetachedFromNode} to clear that reference once
* current node gets detached.
*/
public open fun onAttachedToNode(parent: AnimatedNode): Unit = Unit
/** See {@link #onAttachedToNode} */
public open fun onDetachedFromNode(parent: AnimatedNode): Unit = Unit
/**
* This method will be run on each node at most once every repetition of the animation loop. It
* will be executed on a node only when all the node's parent has already been updated. Therefore
* it can be used to calculate node's value.
*/
public open fun update(): Unit = Unit
/**
* Pretty-printer for the AnimatedNode. Only called in production pre-crash for debug diagnostics.
*/
public abstract fun prettyPrint(): String
public fun prettyPrintWithChildren(): String {
val currentChildren = children?.joinToString(" ")
return prettyPrint() +
if (!currentChildren.isNullOrBlank()) " children: $currentChildren" else ""
}
}
@@ -66,7 +66,7 @@ import com.facebook.react.views.view.ColorUtil;
@Override
public String prettyPrint() {
return "ColorAnimatedNode["
+ mTag
+ tag
+ "]: r: "
+ mRNodeId
+ " g: "
@@ -116,8 +116,8 @@ import com.facebook.react.views.view.ColorUtil;
private static Context getContextHelper(AnimatedNode node) {
// Search children depth-first until we get to a PropsAnimatedNode, from which we can
// get the view and its context
if (node.mChildren != null) {
for (AnimatedNode child : node.mChildren) {
if (node.children != null) {
for (AnimatedNode child : node.children) {
if (child instanceof PropsAnimatedNode) {
View view = ((PropsAnimatedNode) child).getConnectedView();
return view != null ? view.getContext() : null;
@@ -46,6 +46,6 @@ internal class DiffClampAnimatedNode(
}
override fun prettyPrint(): String =
"DiffClampAnimatedNode[$mTag]: InputNodeTag: $inputNodeTag min: $minValue " +
"DiffClampAnimatedNode[$tag]: InputNodeTag: $inputNodeTag min: $minValue " +
"max: $maxValue lastValue: $lastValue super: ${super.prettyPrint()}"
}
@@ -42,12 +42,12 @@ import com.facebook.react.bridge.ReadableMap;
}
if (value == 0) {
throw new JSApplicationCausedNativeException(
"Detected a division by zero in Animated.divide node with Animated ID " + mTag);
"Detected a division by zero in Animated.divide node with Animated ID " + tag);
}
mValue /= value;
} else {
throw new JSApplicationCausedNativeException(
"Illegal node ID set as an input for Animated.divide node with Animated ID " + mTag);
"Illegal node ID set as an input for Animated.divide node with Animated ID " + tag);
}
}
}
@@ -55,7 +55,7 @@ import com.facebook.react.bridge.ReadableMap;
@Override
public String prettyPrint() {
return "DivisionAnimatedNode["
+ mTag
+ tag
+ "]: input nodes: "
+ (mInputNodes != null ? mInputNodes.toString() : "null")
+ " - super: "
@@ -306,6 +306,6 @@ import java.util.regex.Pattern;
@Override
public String prettyPrint() {
return "InterpolationAnimatedNode[" + mTag + "] super: " + super.prettyPrint();
return "InterpolationAnimatedNode[" + tag + "] super: " + super.prettyPrint();
}
}
@@ -30,6 +30,6 @@ internal class ModulusAnimatedNode(
}
override public fun prettyPrint(): String {
return "NativeAnimatedNodesManager[$mTag] inputNode: $inputNode modulus: $modulus super: ${super.prettyPrint()}"
return "NativeAnimatedNodesManager[$tag] inputNode: $inputNode modulus: $modulus super: ${super.prettyPrint()}"
}
}
@@ -47,7 +47,7 @@ import com.facebook.react.bridge.ReadableMap;
@Override
public String prettyPrint() {
return "MultiplicationAnimatedNode["
+ mTag
+ tag
+ "]: input nodes: "
+ (mInputNodes != null ? mInputNodes.toString() : "null")
+ " - super: "
@@ -149,7 +149,7 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
} else {
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
}
node.mTag = tag;
node.tag = tag;
mAnimatedNodes.put(tag, node);
mUpdatedNodes.put(tag, node);
}
@@ -565,7 +565,7 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
EventAnimationDriver driver = it.next();
if (eventName.equals(driver.mEventName)
&& viewTag == driver.mViewTag
&& animatedValueTag == driver.mValueNode.mTag) {
&& animatedValueTag == driver.mValueNode.tag) {
it.remove();
break;
}
@@ -632,7 +632,7 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
* <p>First BFS starts with nodes that are in {@code mUpdatedNodes} (that is, their value have
* been modified from JS in the last batch of JS operations) or directly attached to an active
* animation (hence linked to objects from {@code mActiveAnimations}). In that step we calculate
* an attribute {@code mActiveIncomingNodes}. The second BFS runs in topological order over the
* an attribute {@code activeIncomingNodes}. The second BFS runs in topological order over the
* sub-graph of *active* nodes. This is done by adding node to the BFS queue only if all its
* "predecessors" have already been visited.
*/
@@ -706,9 +706,9 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
if (driver != null) {
if (eventName.equals(driver.mEventName) && tag == driver.mViewTag) {
tags.add(driver.mViewTag);
if (driver.mValueNode != null && driver.mValueNode.mChildren != null) {
for (AnimatedNode node : driver.mValueNode.mChildren) {
tags.add(node.mTag);
if (driver.mValueNode != null && driver.mValueNode.children != null) {
for (AnimatedNode node : driver.mValueNode.children) {
tags.add(node.tag);
}
}
}
@@ -737,8 +737,8 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
Queue<AnimatedNode> nodesQueue = new ArrayDeque<>();
for (AnimatedNode node : nodes) {
if (node.mBFSColor != mAnimatedGraphBFSColor) {
node.mBFSColor = mAnimatedGraphBFSColor;
if (node.BFSColor != mAnimatedGraphBFSColor) {
node.BFSColor = mAnimatedGraphBFSColor;
activeNodesCount++;
nodesQueue.add(node);
}
@@ -746,12 +746,12 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
while (!nodesQueue.isEmpty()) {
AnimatedNode nextNode = nodesQueue.poll();
if (nextNode.mChildren != null) {
for (int i = 0; i < nextNode.mChildren.size(); i++) {
AnimatedNode child = nextNode.mChildren.get(i);
child.mActiveIncomingNodes++;
if (child.mBFSColor != mAnimatedGraphBFSColor) {
child.mBFSColor = mAnimatedGraphBFSColor;
if (nextNode.children != null) {
for (int i = 0; i < nextNode.children.size(); i++) {
AnimatedNode child = nextNode.children.get(i);
child.activeIncomingNodes++;
if (child.BFSColor != mAnimatedGraphBFSColor) {
child.BFSColor = mAnimatedGraphBFSColor;
activeNodesCount++;
nodesQueue.add(child);
}
@@ -764,7 +764,7 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
// "predecessors" in the graph have already been visited. It is important to visit nodes in that
// order as they may often use values of their predecessors in order to calculate "next state"
// of their own. We start by determining the starting set of nodes by looking for nodes with
// `mActiveIncomingNodes = 0` (those can only be the ones that we start BFS in the previous
// `activeIncomingNodes = 0` (those can only be the ones that we start BFS in the previous
// step). We store number of visited nodes in this step in `updatedNodesCount`
mAnimatedGraphBFSColor++;
@@ -776,8 +776,8 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
// find nodes with zero "incoming nodes", those can be either nodes from `mUpdatedNodes` or
// ones connected to active animations
for (AnimatedNode node : nodes) {
if (node.mActiveIncomingNodes == 0 && node.mBFSColor != mAnimatedGraphBFSColor) {
node.mBFSColor = mAnimatedGraphBFSColor;
if (node.activeIncomingNodes == 0 && node.BFSColor != mAnimatedGraphBFSColor) {
node.BFSColor = mAnimatedGraphBFSColor;
updatedNodesCount++;
nodesQueue.add(node);
}
@@ -807,15 +807,15 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
// Potentially send events to JS when the node's value is updated
((ValueAnimatedNode) nextNode).onValueUpdate();
}
if (nextNode.mChildren != null) {
for (int i = 0; i < nextNode.mChildren.size(); i++) {
AnimatedNode child = nextNode.mChildren.get(i);
child.mActiveIncomingNodes--;
if (child.mBFSColor != mAnimatedGraphBFSColor && child.mActiveIncomingNodes == 0) {
child.mBFSColor = mAnimatedGraphBFSColor;
if (nextNode.children != null) {
for (int i = 0; i < nextNode.children.size(); i++) {
AnimatedNode child = nextNode.children.get(i);
child.activeIncomingNodes--;
if (child.BFSColor != mAnimatedGraphBFSColor && child.activeIncomingNodes == 0) {
child.BFSColor = mAnimatedGraphBFSColor;
updatedNodesCount++;
nodesQueue.add(child);
} else if (child.mBFSColor == mAnimatedGraphBFSColor) {
} else if (child.BFSColor == mAnimatedGraphBFSColor) {
cyclesDetected++;
}
}
@@ -825,7 +825,7 @@ public class NativeAnimatedNodesManager implements EventDispatcherListener {
// Verify that we've visited *all* active nodes. Throw otherwise as this could mean there is a
// cycle in animated node graph, or that the graph is only partially set up. We also take
// advantage of the fact that all active nodes are visited in the step above so that all the
// nodes properties `mActiveIncomingNodes` are set to zero.
// nodes properties `activeIncomingNodes` are set to zero.
// In Fabric there can be race conditions between the JS thread setting up or tearing down
// animated nodes, and Fabric executing them on the UI thread, leading to temporary inconsistent
// states.
@@ -154,7 +154,7 @@ class ObjectAnimatedNode extends AnimatedNode {
@Override
public String prettyPrint() {
return "ObjectAnimatedNode["
+ mTag
+ tag
+ "]: mConfig: "
+ (mConfig != null ? mConfig.toString() : "null");
}
@@ -49,7 +49,7 @@ import java.util.Map;
public void connectToView(int viewTag, UIManager uiManager) {
if (mConnectedViewTag != -1) {
throw new JSApplicationIllegalArgumentException(
"Animated node " + mTag + " is " + "already attached to a view: " + mConnectedViewTag);
"Animated node " + tag + " is " + "already attached to a view: " + mConnectedViewTag);
}
mConnectedViewTag = viewTag;
mUIManager = uiManager;
@@ -134,7 +134,7 @@ import java.util.Map;
public String prettyPrint() {
return "PropsAnimatedNode["
+ mTag
+ tag
+ "] connectedViewTag: "
+ mConnectedViewTag
+ " mPropNodeMapping: "
@@ -63,7 +63,7 @@ import java.util.Map;
public String prettyPrint() {
return "StyleAnimatedNode["
+ mTag
+ tag
+ "] mPropMapping: "
+ (mPropMapping != null ? mPropMapping.toString() : "null");
}
@@ -51,7 +51,7 @@ import com.facebook.react.bridge.ReadableMap;
@Override
public String prettyPrint() {
return "SubtractionAnimatedNode["
+ mTag
+ tag
+ "]: input nodes: "
+ (mInputNodes != null ? mInputNodes.toString() : "null")
+ " - super: "
@@ -37,7 +37,7 @@ import com.facebook.react.bridge.ReadableMap;
@Override
public String prettyPrint() {
return "TrackingAnimatedNode["
+ mTag
+ tag
+ "]: animationID: "
+ mAnimationId
+ " toValueNode: "
@@ -86,7 +86,7 @@ import java.util.List;
@Override
public String prettyPrint() {
return "TransformAnimatedNode["
+ mTag
+ tag
+ "]: mTransformConfigs: "
+ (mTransformConfigs != null ? mTransformConfigs.toString() : "null");
}
@@ -61,6 +61,6 @@ import com.facebook.react.bridge.ReadableMap;
}
public String prettyPrint() {
return "ValueAnimatedNode[" + mTag + "]: value: " + mValue + " offset: " + mOffset;
return "ValueAnimatedNode[" + tag + "]: value: " + mValue + " offset: " + mOffset;
}
}