Fix NativeAnimatedModule timing for Fabric/Venice(?)

Summary:
This is the second part of a rewrite of D15390384, which allows Animated timing to be driven by Paper or Fabric.

The intuition is: we don't care which one drives the animation. We will expect one or both of them to issue a callback that operations are about to be executed, and the first one wins. The blocks will only execute once, the second time will be a noop.

I don't think there's a 100% safe way of reimplementing Native Animated Module for Fabric/Venice (without a new API and implementing in C++) since it's inherently disconnected from the commit process and the tree. This gets us slightly closer to visual functionality, though.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D21698192

fbshipit-source-id: c11d3cebd12cfc8acf4b63c87ccbe62cdbd8b672
This commit is contained in:
Joshua Gross
2020-05-26 11:33:00 -07:00
committed by Facebook GitHub Bot
parent 0b00d92514
commit 8e1348046a
@@ -7,6 +7,7 @@
package com.facebook.react.animated;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.facebook.common.logging.FLog;
@@ -30,6 +31,8 @@ import com.facebook.react.uimanager.NativeViewHierarchyManager;
import com.facebook.react.uimanager.UIBlock;
import com.facebook.react.uimanager.UIManagerModule;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Module that exposes interface for creating and managing animated nodes on the "native" side.
@@ -85,10 +88,13 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
void execute(NativeAnimatedNodesManager animatedNodesManager);
}
private final GuardedFrameCallback mAnimatedFrameCallback;
@NonNull private final GuardedFrameCallback mAnimatedFrameCallback;
private final ReactChoreographer mReactChoreographer;
private ArrayList<UIThreadOperation> mOperations = new ArrayList<>();
private ArrayList<UIThreadOperation> mPreOperations = new ArrayList<>();
@NonNull private List<UIThreadOperation> mOperations = new ArrayList<>();
@NonNull private List<UIThreadOperation> mPreOperations = new ArrayList<>();
@NonNull private List<UIBlock> mPreOperationsUIBlock = new ArrayList<>();
@NonNull private List<UIBlock> mOperationsUIBlock = new ArrayList<>();
private @Nullable NativeAnimatedNodesManager mNodesManager;
@@ -145,12 +151,31 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
// For FabricUIManager
@Override
public void willDispatchPreMountItems() {}
@UiThread
public void willDispatchPreMountItems() {
if (mPreOperationsUIBlock.size() != 0) {
List<UIBlock> preOperations = mPreOperationsUIBlock;
mPreOperationsUIBlock = new ArrayList<>();
for (UIBlock op : preOperations) {
op.execute(null);
}
}
}
// For FabricUIManager
@Override
@UiThread
public void willDispatchMountItems() {}
public void willDispatchMountItems() {
if (mOperationsUIBlock.size() != 0) {
List<UIBlock> operations = mOperationsUIBlock;
mOperationsUIBlock = new ArrayList<>();
for (UIBlock op : operations) {
op.execute(null);
}
}
}
// For non-FabricUIManager
@Override
@@ -159,8 +184,11 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
if (mOperations.isEmpty() && mPreOperations.isEmpty()) {
return;
}
final ArrayList<UIThreadOperation> preOperations = mPreOperations;
final ArrayList<UIThreadOperation> operations = mOperations;
final AtomicBoolean hasRunPreOperations = new AtomicBoolean(false);
final AtomicBoolean hasRunOperations = new AtomicBoolean(false);
final List<UIThreadOperation> preOperations = mPreOperations;
final List<UIThreadOperation> operations = mOperations;
mPreOperations = new ArrayList<>();
mOperations = new ArrayList<>();
@@ -171,26 +199,44 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
// This goes away entirely in Fabric/Venice.
UIManagerModule uiManagerModule = (UIManagerModule) uiManager;
uiManagerModule.prependUIBlock(
UIBlock preOperationsUIBlock =
new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
if (!hasRunPreOperations.compareAndSet(false, true)) {
return;
}
NativeAnimatedNodesManager nodesManager = getNodesManager();
for (UIThreadOperation operation : preOperations) {
operation.execute(nodesManager);
}
}
});
uiManagerModule.addUIBlock(
};
UIBlock operationsUIBlock =
new UIBlock() {
@Override
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
if (!hasRunOperations.compareAndSet(false, true)) {
return;
}
NativeAnimatedNodesManager nodesManager = getNodesManager();
for (UIThreadOperation operation : operations) {
operation.execute(nodesManager);
}
}
});
};
// Queue up operations for Fabric
mPreOperationsUIBlock.add(preOperationsUIBlock);
mOperationsUIBlock.add(operationsUIBlock);
// Here we queue up the UI Blocks for the old, non-Fabric UIManager.
// We queue them in both systems, let them race, and see which wins.
uiManagerModule.prependUIBlock(preOperationsUIBlock);
uiManagerModule.addUIBlock(operationsUIBlock);
}
@Override