Merge commit 'e1fa53af2eabc483be2f196ca96bbcd4a8226809' into amgleitman/0.64-merge-head
This commit is contained in:
Коммит
7acf9edcf5
|
@ -35,8 +35,10 @@ let __nativeAnimationIdCount = 1; /* used for started animations */
|
|||
|
||||
let nativeEventEmitter;
|
||||
|
||||
let waitingForQueuedOperations = new Set();
|
||||
let queueOperations = false;
|
||||
let queueConnections = false;
|
||||
let queue = [];
|
||||
let queue: Array<() => void> = [];
|
||||
|
||||
/**
|
||||
* Simple wrappers around NativeAnimatedModule to provide flow and autocomplete support for
|
||||
|
@ -55,38 +57,74 @@ const API = {
|
|||
NativeAnimatedModule.getValue(tag, saveValueCallback);
|
||||
}
|
||||
},
|
||||
setWaitingForIdentifier: function(id: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
waitingForQueuedOperations.add(id);
|
||||
queueOperations = true;
|
||||
queueConnections = true;
|
||||
},
|
||||
unsetWaitingForIdentifier: function(id: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
waitingForQueuedOperations.delete(id);
|
||||
|
||||
if (waitingForQueuedOperations.size === 0) {
|
||||
queueOperations = false;
|
||||
API.disableQueue();
|
||||
}
|
||||
},
|
||||
disableQueue: function(): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
queueConnections = false;
|
||||
for (let q = 0, l = queue.length; q < l; q++) {
|
||||
const args = queue[q];
|
||||
NativeAnimatedModule.connectAnimatedNodes(args[0], args[1]);
|
||||
if (!queueOperations) {
|
||||
for (let q = 0, l = queue.length; q < l; q++) {
|
||||
queue[q]();
|
||||
}
|
||||
queue.length = 0;
|
||||
}
|
||||
},
|
||||
queueConnection: (fn: () => void): void => {
|
||||
if (queueConnections) {
|
||||
queue.push(fn);
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
},
|
||||
queueOperation: (fn: () => void): void => {
|
||||
if (queueOperations) {
|
||||
queue.push(fn);
|
||||
} else {
|
||||
fn();
|
||||
}
|
||||
queue.length = 0;
|
||||
},
|
||||
createAnimatedNode: function(tag: number, config: AnimatedNodeConfig): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.createAnimatedNode(tag, config);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.createAnimatedNode(tag, config),
|
||||
);
|
||||
},
|
||||
startListeningToAnimatedNodeValue: function(tag: number) {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue(tag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.startListeningToAnimatedNodeValue(tag),
|
||||
);
|
||||
},
|
||||
stopListeningToAnimatedNodeValue: function(tag: number) {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag),
|
||||
);
|
||||
},
|
||||
connectAnimatedNodes: function(parentTag: number, childTag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
if (queueConnections) {
|
||||
queue.push([parentTag, childTag]);
|
||||
return;
|
||||
}
|
||||
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag);
|
||||
API.queueConnection(() =>
|
||||
NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag),
|
||||
);
|
||||
},
|
||||
disconnectAnimatedNodes: function(parentTag: number, childTag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag),
|
||||
);
|
||||
},
|
||||
startAnimatingNode: function(
|
||||
animationId: number,
|
||||
|
@ -95,54 +133,70 @@ const API = {
|
|||
endCallback: EndCallback,
|
||||
): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.startAnimatingNode(
|
||||
animationId,
|
||||
nodeTag,
|
||||
config,
|
||||
endCallback,
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.startAnimatingNode(
|
||||
animationId,
|
||||
nodeTag,
|
||||
config,
|
||||
endCallback,
|
||||
),
|
||||
);
|
||||
},
|
||||
stopAnimation: function(animationId: number) {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.stopAnimation(animationId);
|
||||
API.queueOperation(() => NativeAnimatedModule.stopAnimation(animationId));
|
||||
},
|
||||
setAnimatedNodeValue: function(nodeTag: number, value: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value),
|
||||
);
|
||||
},
|
||||
setAnimatedNodeOffset: function(nodeTag: number, offset: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset),
|
||||
);
|
||||
},
|
||||
flattenAnimatedNodeOffset: function(nodeTag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag),
|
||||
);
|
||||
},
|
||||
extractAnimatedNodeOffset: function(nodeTag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag),
|
||||
);
|
||||
},
|
||||
connectAnimatedNodeToView: function(nodeTag: number, viewTag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag),
|
||||
);
|
||||
},
|
||||
disconnectAnimatedNodeFromView: function(
|
||||
nodeTag: number,
|
||||
viewTag: number,
|
||||
): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag),
|
||||
);
|
||||
},
|
||||
restoreDefaultValues: function(nodeTag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
// Backwards compat with older native runtimes, can be removed later.
|
||||
if (NativeAnimatedModule.restoreDefaultValues != null) {
|
||||
NativeAnimatedModule.restoreDefaultValues(nodeTag);
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.restoreDefaultValues(nodeTag),
|
||||
);
|
||||
}
|
||||
},
|
||||
dropAnimatedNode: function(tag: number): void {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.dropAnimatedNode(tag);
|
||||
API.queueOperation(() => NativeAnimatedModule.dropAnimatedNode(tag));
|
||||
},
|
||||
addAnimatedEventToView: function(
|
||||
viewTag: number,
|
||||
|
@ -150,10 +204,12 @@ const API = {
|
|||
eventMapping: EventMapping,
|
||||
) {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
eventMapping,
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.addAnimatedEventToView(
|
||||
viewTag,
|
||||
eventName,
|
||||
eventMapping,
|
||||
),
|
||||
);
|
||||
},
|
||||
removeAnimatedEventFromView(
|
||||
|
@ -162,10 +218,12 @@ const API = {
|
|||
animatedNodeTag: number,
|
||||
) {
|
||||
invariant(NativeAnimatedModule, 'Native animated module is not available');
|
||||
NativeAnimatedModule.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
animatedNodeTag,
|
||||
API.queueOperation(() =>
|
||||
NativeAnimatedModule.removeAnimatedEventFromView(
|
||||
viewTag,
|
||||
eventName,
|
||||
animatedNodeTag,
|
||||
),
|
||||
);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -11,13 +11,17 @@
|
|||
'use strict';
|
||||
|
||||
const View = require('../../Components/View/View');
|
||||
const Platform = require('../../Utilities/Platform');
|
||||
const {AnimatedEvent} = require('./AnimatedEvent');
|
||||
const AnimatedProps = require('./nodes/AnimatedProps');
|
||||
const React = require('react');
|
||||
const NativeAnimatedHelper = require('./NativeAnimatedHelper');
|
||||
|
||||
const invariant = require('invariant');
|
||||
const setAndForwardRef = require('../../Utilities/setAndForwardRef');
|
||||
|
||||
let animatedComponentNextId = 1;
|
||||
|
||||
export type AnimatedComponentType<
|
||||
Props: {+[string]: mixed, ...},
|
||||
Instance,
|
||||
|
@ -51,6 +55,9 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
|||
_propsAnimated: AnimatedProps;
|
||||
_eventDetachers: Array<Function> = [];
|
||||
|
||||
// Only to be used in this file, and only in Fabric.
|
||||
_animatedComponentId: number = -1;
|
||||
|
||||
_attachNativeEvents() {
|
||||
// Make sure to get the scrollable node for components that implement
|
||||
// `ScrollResponder.Mixin`.
|
||||
|
@ -72,25 +79,11 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
|||
this._eventDetachers = [];
|
||||
}
|
||||
|
||||
// The system is best designed when setNativeProps is implemented. It is
|
||||
// able to avoid re-rendering and directly set the attributes that changed.
|
||||
// However, setNativeProps can only be implemented on leaf native
|
||||
// components. If you want to animate a composite component, you need to
|
||||
// re-render it. In this case, we have a fallback that uses forceUpdate.
|
||||
// This fallback is also called in Fabric.
|
||||
_animatedPropsCallback = () => {
|
||||
_isFabric = (): boolean => {
|
||||
if (this._component == null) {
|
||||
// AnimatedProps is created in will-mount because it's used in render.
|
||||
// But this callback may be invoked before mount in async mode,
|
||||
// In which case we should defer the setNativeProps() call.
|
||||
// React may throw away uncommitted work in async mode,
|
||||
// So a deferred call won't always be invoked.
|
||||
this._invokeAnimatedPropsCallbackOnMount = true;
|
||||
} else if (
|
||||
process.env.NODE_ENV === 'test' ||
|
||||
// For animating properties of non-leaf/non-native components
|
||||
typeof this._component.setNativeProps !== 'function' ||
|
||||
// In Fabric, force animations to go through forceUpdate and skip setNativeProps
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
// eslint-disable-next-line dot-notation
|
||||
this._component['_internalInstanceHandle']?.stateNode?.canonical !=
|
||||
null ||
|
||||
|
@ -114,6 +107,54 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
|||
// eslint-disable-next-line dot-notation
|
||||
'_internalInstanceHandle'
|
||||
]?.stateNode?.canonical != null)
|
||||
);
|
||||
};
|
||||
|
||||
_waitForUpdate = (): void => {
|
||||
// If this works well on iOS, we should remove this check
|
||||
if (Platform.OS === 'android') {
|
||||
if (this._isFabric()) {
|
||||
if (this._animatedComponentId === -1) {
|
||||
this._animatedComponentId = animatedComponentNextId++;
|
||||
}
|
||||
NativeAnimatedHelper.API.setWaitingForIdentifier(
|
||||
this._animatedComponentId,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_markUpdateComplete = (): void => {
|
||||
// If this works well on iOS, we should remove this check
|
||||
if (Platform.OS === 'android') {
|
||||
if (this._isFabric()) {
|
||||
NativeAnimatedHelper.API.unsetWaitingForIdentifier(
|
||||
this._animatedComponentId,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The system is best designed when setNativeProps is implemented. It is
|
||||
// able to avoid re-rendering and directly set the attributes that changed.
|
||||
// However, setNativeProps can only be implemented on leaf native
|
||||
// components. If you want to animate a composite component, you need to
|
||||
// re-render it. In this case, we have a fallback that uses forceUpdate.
|
||||
// This fallback is also called in Fabric.
|
||||
_animatedPropsCallback = () => {
|
||||
if (this._component == null) {
|
||||
// AnimatedProps is created in will-mount because it's used in render.
|
||||
// But this callback may be invoked before mount in async mode,
|
||||
// In which case we should defer the setNativeProps() call.
|
||||
// React may throw away uncommitted work in async mode,
|
||||
// So a deferred call won't always be invoked.
|
||||
this._invokeAnimatedPropsCallbackOnMount = true;
|
||||
} else if (
|
||||
process.env.NODE_ENV === 'test' ||
|
||||
// For animating properties of non-leaf/non-native components
|
||||
typeof this._component.setNativeProps !== 'function' ||
|
||||
// In Fabric, force animations to go through forceUpdate and skip setNativeProps
|
||||
this._isFabric()
|
||||
) {
|
||||
this.forceUpdate();
|
||||
} else if (!this._propsAnimated.__isNative) {
|
||||
|
@ -199,6 +240,7 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
|||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this._waitForUpdate();
|
||||
this._attachProps(this.props);
|
||||
}
|
||||
|
||||
|
@ -210,9 +252,11 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
|||
|
||||
this._propsAnimated.setNativeView(this._component);
|
||||
this._attachNativeEvents();
|
||||
this._markUpdateComplete();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps(newProps) {
|
||||
this._waitForUpdate();
|
||||
this._attachProps(newProps);
|
||||
}
|
||||
|
||||
|
@ -224,11 +268,13 @@ function createAnimatedComponent<Props: {+[string]: mixed, ...}, Instance>(
|
|||
this._detachNativeEvents();
|
||||
this._attachNativeEvents();
|
||||
}
|
||||
this._markUpdateComplete();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this._propsAnimated && this._propsAnimated.__detach();
|
||||
this._detachNativeEvents();
|
||||
this._markUpdateComplete();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -510,8 +510,8 @@ SPEC CHECKSUMS:
|
|||
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
|
||||
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
|
||||
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
|
||||
FBLazyVector: 4b23de6e6b7e7d5d026b09c25d36d97b67bb40de
|
||||
FBReactNativeSpec: 2d2a213b4c164af442698ea6af7bcb080ea5ee02
|
||||
FBLazyVector: 732869c0b909e8bf216314da06e817522d65cc1b
|
||||
FBReactNativeSpec: f179c5379aa50218c6d52b5327b3225bc8e86f08
|
||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
||||
|
@ -522,33 +522,33 @@ SPEC CHECKSUMS:
|
|||
glog: 789873d01e4b200777d0a09bc23d548446758699
|
||||
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
||||
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
|
||||
RCTRequired: de797b1acb93dcd075319a38597b11cce2a4cd5c
|
||||
RCTTypeSafety: de700bd81b3504c1aa247caa96f1b01750ec4f52
|
||||
React: d557fabc871c1588c2031ff3ffc96490aaef7b71
|
||||
React-callinvoker: a783f0ebf49dac341c433c97fb7bca87078aaa25
|
||||
React-Core: bfb26c530d4596a5b6273c74a7067442b1415c27
|
||||
React-CoreModules: afbf75c2fae3b05d9c6009d380deee06f156e5e8
|
||||
React-cxxreact: 288c6b6b9348d3a4082a2ab1da9d1d15f0c12ece
|
||||
React-jsi: 75157aabfeaf837ddf7a07bc740d2e2c85301ebb
|
||||
React-jsiexecutor: 9e2055f1447d920ad59d3b7fee510fa8b472c298
|
||||
React-jsinspector: acd6b8cf323b3c93dcb550d8040361cb00117101
|
||||
React-perflogger: 18ee540a8500d2000fa88990df5d8eaa74cd9475
|
||||
React-RCTActionSheet: be55a83ef4643278266c646d7d814367ec7f9563
|
||||
React-RCTAnimation: 29742b09e5867180a5a1fa6e1e71633c7483ea85
|
||||
React-RCTBlob: 483018994f6e2b6d015ba89f86435fbcea3d4210
|
||||
React-RCTImage: d49d1af581a65f205f73eaa56b106e3f11c70435
|
||||
React-RCTLinking: d4318ff788dd65c2149ce5ac919f4a27913b760d
|
||||
React-RCTNetwork: 5525944a8d7e70263d6895fac8490c0d731dd1c4
|
||||
React-RCTPushNotification: dc897506a895c979644b2127bb1bcab03ce88a59
|
||||
React-RCTSettings: fb77ce3170f9b83d6f4b76e33eef729e712fd28d
|
||||
React-RCTTest: 4a6f82fec5b33fd14d0ccb3dc91c0a9d585f1736
|
||||
React-RCTText: e0b62bb2c46a2250a663da6a9cbfd4bbef790e61
|
||||
React-RCTVibration: 04622c45021de9eb94873ca0a2d28b1b08d85c70
|
||||
React-runtimeexecutor: 4b592cc4b6d41a06a25ebffad55a0a5b4a752c73
|
||||
RCTRequired: e57c96e9043b32eb039c3be36b0323c9c0cc78b3
|
||||
RCTTypeSafety: d89d63062f5f3880bc142a8115a9d7488f96f6e6
|
||||
React: ffa956ca111517bdbac4adbda38f392ff1b24655
|
||||
React-callinvoker: f8688c196a51ed024f2f2e5ed964f48fb0ccc104
|
||||
React-Core: 23f3d8f877a3d838ba407ff8c4122d5ae5f2675b
|
||||
React-CoreModules: c584baf382fa2fdd751c272fd8169b478ee9d16a
|
||||
React-cxxreact: 8182b61c40331f2bab4861a01a148b75ce6d6a25
|
||||
React-jsi: b40a0b755266eef1ccd36be376598e6b8deeeb65
|
||||
React-jsiexecutor: 9082a6492e0786ee05b7c896b8d013dd14d6a7f5
|
||||
React-jsinspector: ace5eb00f739058c1639de2cfa34d4723090c1d6
|
||||
React-perflogger: ecc9e8fa74a3fed810ca23be9677dc488a7aa293
|
||||
React-RCTActionSheet: f39b0fb0af5750509f1aa86b2ed56955ab9071d7
|
||||
React-RCTAnimation: 83c410e9886788e0bad11c15552274bacce10296
|
||||
React-RCTBlob: d0391ea7685afe50564c3221445c8b1c911fc1dc
|
||||
React-RCTImage: 5490eb14709285403f30bb55aa53bb64e1d4183b
|
||||
React-RCTLinking: 55ec860467d76a01f28284aaaf7bfd406524da93
|
||||
React-RCTNetwork: f18683923b0396a68f028cf5a9810777cac4010c
|
||||
React-RCTPushNotification: 33a883d3e6f10a1842b6b3f7fb592854a6f69676
|
||||
React-RCTSettings: 7f8ec2893fa4129a7c7dc3db7fac421fb0a96c5a
|
||||
React-RCTTest: 18046d93f0b48a7eacf50afb54ff7c7ac75e85e8
|
||||
React-RCTText: 1f3470878a4ce51821a83640d6b4e310c8f7e1fc
|
||||
React-RCTVibration: 0b7cef95d0b04c778c6751ff638c47e190cee7c5
|
||||
React-runtimeexecutor: 14a8a45de8e02b8895afae7f38cc5aaf5ea90b5a
|
||||
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
|
||||
React-TurboModuleCxx-WinRTPort: 7c3bbced514dbd1d0a43e226606987e2bce7ada6
|
||||
ReactCommon: df708ad127837db8167616488e556ff3c90b365e
|
||||
Yoga: f5c8b1a2347133d81ac2d765c26c62300f7581f0
|
||||
React-TurboModuleCxx-WinRTPort: c4538e76df5bdf83edd892a8919c7202ac790ed1
|
||||
ReactCommon: 6d574adf7fdd5d0e7e2e892b95c75ea167d3a725
|
||||
Yoga: af7ff9d5087d827aa8dd130c1e2b1c3062494887
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: d3ddf54cbfd92c34f45d8fb0c9166fe4730df5c0
|
||||
|
|
|
@ -88,16 +88,6 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
|
||||
private abstract class UIThreadOperation {
|
||||
abstract void execute(NativeAnimatedNodesManager animatedNodesManager);
|
||||
|
||||
long mFrameNumber = -1;
|
||||
|
||||
public void setFrameNumber(long frameNumber) {
|
||||
mFrameNumber = frameNumber;
|
||||
}
|
||||
|
||||
public long getFrameNumber() {
|
||||
return mFrameNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull private final GuardedFrameCallback mAnimatedFrameCallback;
|
||||
|
@ -113,8 +103,6 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
|
||||
private @Nullable NativeAnimatedNodesManager mNodesManager;
|
||||
|
||||
private volatile long mFrameNumber = 0;
|
||||
private long mDispatchedFrameNumber = 0;
|
||||
private boolean mInitializedForFabric = false;
|
||||
private boolean mInitializedForNonFabric = false;
|
||||
private @UIManagerType int mUIManagerType = UIManagerType.DEFAULT;
|
||||
|
@ -169,25 +157,13 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
}
|
||||
|
||||
private void addOperation(UIThreadOperation operation) {
|
||||
operation.setFrameNumber(mFrameNumber);
|
||||
mOperations.add(operation);
|
||||
}
|
||||
|
||||
private void addPreOperation(UIThreadOperation operation) {
|
||||
operation.setFrameNumber(mFrameNumber);
|
||||
mPreOperations.add(operation);
|
||||
}
|
||||
|
||||
// For FabricUIManager only
|
||||
@Override
|
||||
public void didScheduleMountItems(UIManager uiManager) {
|
||||
if (mUIManagerType != UIManagerType.FABRIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
mFrameNumber++;
|
||||
}
|
||||
|
||||
// For FabricUIManager only
|
||||
@Override
|
||||
@UiThread
|
||||
|
@ -196,22 +172,6 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
return;
|
||||
}
|
||||
|
||||
// The problem we're trying to solve here: we could be in the middle of queueing
|
||||
// a batch of related animation operations when Fabric flushes a batch of MountItems.
|
||||
// It's visually bad if we execute half of the animation ops and then wait another frame
|
||||
// (or more) to execute the rest.
|
||||
// See mFrameNumber. If the dispatchedFrameNumber drifts too far - that
|
||||
// is, if no MountItems are scheduled for a while, which can happen if a tree
|
||||
// is committed but there are no changes - bring these counts back in sync and
|
||||
// execute any queued operations. This number is arbitrary, but we want it low
|
||||
// enough that the user shouldn't be able to see this delay in most cases.
|
||||
mDispatchedFrameNumber++;
|
||||
long currentFrameNo = mFrameNumber - 1;
|
||||
if ((mDispatchedFrameNumber - mFrameNumber) > 2) {
|
||||
mFrameNumber = mDispatchedFrameNumber;
|
||||
currentFrameNo = mFrameNumber;
|
||||
}
|
||||
|
||||
// This will execute all operations and preOperations queued
|
||||
// since the last time this was run, and will race with anything
|
||||
// being queued from the JS thread. That is, if the JS thread
|
||||
|
@ -222,35 +182,13 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
// is that `scheduleMountItems` happens as close to the JS commit as
|
||||
// possible, whereas execution of those same items might happen sometime
|
||||
// later on the UI thread while the JS thread keeps plugging along.
|
||||
executeAllOperations(mPreOperations, currentFrameNo);
|
||||
executeAllOperations(mOperations, currentFrameNo);
|
||||
executeAllOperations(mPreOperations);
|
||||
executeAllOperations(mOperations);
|
||||
}
|
||||
|
||||
private void executeAllOperations(Queue<UIThreadOperation> operationQueue, long maxFrameNumber) {
|
||||
private void executeAllOperations(Queue<UIThreadOperation> operationQueue) {
|
||||
NativeAnimatedNodesManager nodesManager = getNodesManager();
|
||||
while (true) {
|
||||
// There is a race condition where `peek` may return a non-null value and isEmpty() is false,
|
||||
// but `poll` returns a null value - it's not clear why since we only peek and poll on the UI
|
||||
// thread, but it might be something that happens during teardown or a crash. Regardless, the
|
||||
// root cause is not currently known so we're extra cautious here.
|
||||
// It happens equally in Fabric and non-Fabric.
|
||||
UIThreadOperation peekedOperation = operationQueue.peek();
|
||||
|
||||
// This is the same as operationQueue.isEmpty()
|
||||
if (peekedOperation == null) {
|
||||
return;
|
||||
}
|
||||
// The rest of the operations are for the next frame.
|
||||
if (peekedOperation.getFrameNumber() > maxFrameNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Since we apparently can't guarantee that there is still an operation on the queue,
|
||||
// much less the same operation, we do a poll and another null check. If this isn't
|
||||
// the same operation as the peeked operation, we can't do anything about it - we still
|
||||
// need to execute it, we have no mechanism to put it at the front of the queue, and it
|
||||
// won't cause any errors to execute it earlier than expected (just a bit of UI jank at worst)
|
||||
// so we just continue happily along.
|
||||
UIThreadOperation polledOperation = operationQueue.poll();
|
||||
if (polledOperation == null) {
|
||||
return;
|
||||
|
@ -270,13 +208,11 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
return;
|
||||
}
|
||||
|
||||
final long frameNo = mFrameNumber++;
|
||||
|
||||
UIBlock preOperationsUIBlock =
|
||||
new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
executeAllOperations(mPreOperations, frameNo);
|
||||
executeAllOperations(mPreOperations);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -284,7 +220,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
new UIBlock() {
|
||||
@Override
|
||||
public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) {
|
||||
executeAllOperations(mOperations, frameNo);
|
||||
executeAllOperations(mOperations);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -734,10 +670,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
"queue connectAnimatedNodeToView: disconnectAnimatedNodeFromView: "
|
||||
+ animatedNodeTag
|
||||
+ " viewTag: "
|
||||
+ viewTag);
|
||||
"queue: disconnectAnimatedNodeFromView: " + animatedNodeTag + " viewTag: " + viewTag);
|
||||
}
|
||||
|
||||
decrementInFlightAnimationsForViewTag(viewTag);
|
||||
|
@ -749,7 +682,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
"execute connectAnimatedNodeToView: disconnectAnimatedNodeFromView: "
|
||||
"execute: disconnectAnimatedNodeFromView: "
|
||||
+ animatedNodeTag
|
||||
+ " viewTag: "
|
||||
+ viewTag);
|
||||
|
@ -826,7 +759,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
"queue addAnimatedEventToView: removeAnimatedEventFromView: "
|
||||
"queue removeAnimatedEventFromView: viewTag: "
|
||||
+ viewTag
|
||||
+ " eventName: "
|
||||
+ eventName
|
||||
|
@ -843,7 +776,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
|||
if (ANIMATED_MODULE_DEBUG) {
|
||||
FLog.d(
|
||||
NAME,
|
||||
"execute addAnimatedEventToView: removeAnimatedEventFromView: "
|
||||
"execute removeAnimatedEventFromView: viewTag: "
|
||||
+ viewTag
|
||||
+ " eventName: "
|
||||
+ eventName
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its 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.bridge;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@DoNotStrip
|
||||
public class BackgroundExecutor {
|
||||
private static final String TAG = "FabricBackgroundExecutor";
|
||||
private final ExecutorService mExecutorService;
|
||||
|
||||
@DoNotStrip
|
||||
private BackgroundExecutor() {
|
||||
mExecutorService = Executors.newFixedThreadPool(1);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
private void queueRunnable(Runnable runnable) {
|
||||
// Very rarely, an NPE is hit here - probably has to do with deallocation
|
||||
// race conditions and the JNI.
|
||||
// It's not clear yet which of these is most prevalent, or if either is a concern.
|
||||
// If we don't find these logs in production then we can probably safely remove the logging,
|
||||
// but it's also cheap to leave it here.
|
||||
|
||||
if (runnable == null) {
|
||||
ReactSoftException.logSoftException(TAG, new ReactNoCrashSoftException("runnable is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
final ExecutorService executorService = mExecutorService;
|
||||
if (executorService == null) {
|
||||
ReactSoftException.logSoftException(
|
||||
TAG, new ReactNoCrashSoftException("executorService is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
executorService.execute(runnable);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,4 @@ public interface UIManagerListener {
|
|||
void willDispatchViewUpdates(UIManager uiManager);
|
||||
/* Called right after view updates are dispatched for a frame. */
|
||||
void didDispatchMountItems(UIManager uiManager);
|
||||
/* Called right after scheduleMountItems is called in Fabric, after a new tree is committed. */
|
||||
void didScheduleMountItems(UIManager uiManager);
|
||||
}
|
||||
|
|
|
@ -587,12 +587,6 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
|||
boolean isBatchMountItem = mountItem instanceof BatchMountItem;
|
||||
boolean shouldSchedule = !(isBatchMountItem && ((BatchMountItem) mountItem).getSize() == 0);
|
||||
|
||||
// In case of sync rendering, this could be called on the UI thread. Otherwise,
|
||||
// it should ~always be called on the JS thread.
|
||||
for (UIManagerListener listener : mListeners) {
|
||||
listener.didScheduleMountItems(this);
|
||||
}
|
||||
|
||||
if (isBatchMountItem) {
|
||||
mCommitStartTime = commitStartTime;
|
||||
mLayoutTime = layoutEndTime - layoutStartTime;
|
||||
|
|
|
@ -278,6 +278,12 @@ void Binding::installFabricUIManager(
|
|||
toolbox.synchronousEventBeatFactory = synchronousBeatFactory;
|
||||
toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory;
|
||||
|
||||
if (reactNativeConfig_->getBool(
|
||||
"react_fabric:enable_background_executor_android")) {
|
||||
backgroundExecutor_ = std::make_unique<JBackgroundExecutor>();
|
||||
toolbox.backgroundExecutor = backgroundExecutor_->get();
|
||||
}
|
||||
|
||||
if (enableLayoutAnimations) {
|
||||
animationDriver_ = std::make_shared<LayoutAnimationDriver>(this);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <mutex>
|
||||
#include "ComponentFactoryDelegate.h"
|
||||
#include "EventBeatManager.h"
|
||||
#include "JBackgroundExecutor.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
@ -115,6 +116,7 @@ class Binding : public jni::HybridClass<Binding>,
|
|||
virtual void onAllAnimationsComplete() override;
|
||||
LayoutAnimationDriver *getAnimationDriver();
|
||||
std::shared_ptr<LayoutAnimationDriver> animationDriver_;
|
||||
std::unique_ptr<JBackgroundExecutor> backgroundExecutor_;
|
||||
|
||||
std::shared_ptr<Scheduler> scheduler_;
|
||||
std::mutex schedulerMutex_;
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/jni/JNativeRunnable.h>
|
||||
|
||||
#include "JBackgroundExecutor.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
using facebook::react::JNativeRunnable;
|
||||
using facebook::react::Runnable;
|
||||
|
||||
BackgroundExecutor JBackgroundExecutor::get() {
|
||||
auto self = JBackgroundExecutor::create();
|
||||
|
||||
return [self](std::function<void()> &&runnable) {
|
||||
static auto method =
|
||||
findClassStatic(JBackgroundExecutor::JBackgroundExecutorJavaDescriptor)
|
||||
->getMethod<void(Runnable::javaobject)>("queueRunnable");
|
||||
|
||||
auto jrunnable = JNativeRunnable::newObjectCxxArgs(std::move(runnable));
|
||||
method(self, static_ref_cast<Runnable>(jrunnable).get());
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fbjni/fbjni.h>
|
||||
#include <react/uimanager/primitives.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
using namespace facebook::jni;
|
||||
|
||||
class JBackgroundExecutor : public JavaClass<JBackgroundExecutor> {
|
||||
public:
|
||||
static auto constexpr kJavaDescriptor =
|
||||
"Lcom/facebook/react/bridge/BackgroundExecutor;";
|
||||
|
||||
constexpr static auto JBackgroundExecutorJavaDescriptor =
|
||||
"com/facebook/react/bridge/BackgroundExecutor";
|
||||
|
||||
static global_ref<javaobject> create() {
|
||||
return make_global(newInstance());
|
||||
}
|
||||
|
||||
BackgroundExecutor get();
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
|
@ -351,6 +351,9 @@ folly::Future<debugger::BreakpointInfo> Inspector::setBreakpoint(
|
|||
debugger::SourceLocation loc,
|
||||
folly::Optional<std::string> condition) {
|
||||
auto promise = std::make_shared<folly::Promise<debugger::BreakpointInfo>>();
|
||||
// Automatically re-enable breakpoints since the user presumably wants this
|
||||
// to start triggering.
|
||||
breakpointsActive_ = true;
|
||||
|
||||
executor_->add([this, loc, condition, promise] {
|
||||
setBreakpointOnExecutor(loc, condition, promise);
|
||||
|
@ -453,6 +456,14 @@ folly::Future<folly::Unit> Inspector::setPauseOnLoads(
|
|||
return promise->getFuture();
|
||||
};
|
||||
|
||||
folly::Future<folly::Unit> Inspector::setBreakpointsActive(bool active) {
|
||||
// Same logic as setPauseOnLoads.
|
||||
auto promise = std::make_shared<folly::Promise<Unit>>();
|
||||
breakpointsActive_ = active;
|
||||
promise->setValue();
|
||||
return promise->getFuture();
|
||||
};
|
||||
|
||||
bool Inspector::shouldPauseOnThisScriptLoad() {
|
||||
switch (pauseOnLoadMode_) {
|
||||
case None:
|
||||
|
|
|
@ -208,6 +208,12 @@ class Inspector : public facebook::hermes::debugger::EventObserver,
|
|||
*/
|
||||
folly::Future<folly::Unit> setPauseOnLoads(const PauseOnLoadMode mode);
|
||||
|
||||
/**
|
||||
* Set whether breakpoints are active (pause when hit). This does not require
|
||||
* runtime modifications, but returns a future for consistency.
|
||||
*/
|
||||
folly::Future<folly::Unit> setBreakpointsActive(bool active);
|
||||
|
||||
/**
|
||||
* If called during a script load event, return true if we should pause.
|
||||
* Assumed to be called from a script load event where we already hold
|
||||
|
@ -326,6 +332,9 @@ class Inspector : public facebook::hermes::debugger::EventObserver,
|
|||
// Whether we should enter a paused state when a script loads.
|
||||
PauseOnLoadMode pauseOnLoadMode_ = PauseOnLoadMode::None;
|
||||
|
||||
// Whether or not we should pause on breakpoints.
|
||||
bool breakpointsActive_ = true;
|
||||
|
||||
// All scripts loaded in to the VM, along with whether we've notified the
|
||||
// client about the script yet.
|
||||
struct LoadedScriptInfo {
|
||||
|
|
|
@ -254,6 +254,12 @@ std::pair<NextStatePtr, CommandPtr> InspectorState::Running::didPause(
|
|||
pendingEvalPromise_->setValue(
|
||||
inspector_.debugger_.getProgramState().getEvalResult());
|
||||
pendingEvalPromise_.reset();
|
||||
} else if (
|
||||
reason == debugger::PauseReason::Breakpoint &&
|
||||
!inspector_.breakpointsActive_) {
|
||||
// We hit a user defined breakpoint, but breakpoints have been deactivated.
|
||||
return std::make_pair<NextStatePtr, CommandPtr>(
|
||||
nullptr, makeContinueCommand());
|
||||
} else /* other cases imply a transition to Pause */ {
|
||||
return std::make_pair<NextStatePtr, CommandPtr>(
|
||||
InspectorState::Paused::make(inspector_), nullptr);
|
||||
|
|
|
@ -81,6 +81,7 @@ class Connection::Impl : public inspector::InspectorObserver,
|
|||
void handle(const m::debugger::ResumeRequest &req) override;
|
||||
void handle(const m::debugger::SetBreakpointRequest &req) override;
|
||||
void handle(const m::debugger::SetBreakpointByUrlRequest &req) override;
|
||||
void handle(const m::debugger::SetBreakpointsActiveRequest &req) override;
|
||||
void handle(
|
||||
const m::debugger::SetInstrumentationBreakpointRequest &req) override;
|
||||
void handle(const m::debugger::SetPauseOnExceptionsRequest &req) override;
|
||||
|
@ -659,6 +660,16 @@ void Connection::Impl::handle(
|
|||
.thenError<std::exception>(sendErrorToClient(req.id));
|
||||
}
|
||||
|
||||
void Connection::Impl::handle(
|
||||
const m::debugger::SetBreakpointsActiveRequest &req) {
|
||||
inspector_->setBreakpointsActive(req.active)
|
||||
.via(executor_.get())
|
||||
.thenValue([this, id = req.id](const Unit &unit) {
|
||||
sendResponseToClient(m::makeOkResponse(id));
|
||||
})
|
||||
.thenError<std::exception>(sendErrorToClient(req.id));
|
||||
}
|
||||
|
||||
bool Connection::Impl::isVirtualBreakpointId(const std::string &id) {
|
||||
return id.rfind(kVirtualBreakpointPrefix, 0) == 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// @generated SignedSource<<f251363b69dd291d2c70e893c3fed04d>>
|
||||
// @generated SignedSource<<addf39d6b92b8dc857e6e5ffe2a441d4>>
|
||||
|
||||
#include "MessageTypes.h"
|
||||
|
||||
|
@ -35,6 +35,8 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
|
|||
{"Debugger.setBreakpoint", makeUnique<debugger::SetBreakpointRequest>},
|
||||
{"Debugger.setBreakpointByUrl",
|
||||
makeUnique<debugger::SetBreakpointByUrlRequest>},
|
||||
{"Debugger.setBreakpointsActive",
|
||||
makeUnique<debugger::SetBreakpointsActiveRequest>},
|
||||
{"Debugger.setInstrumentationBreakpoint",
|
||||
makeUnique<debugger::SetInstrumentationBreakpointRequest>},
|
||||
{"Debugger.setPauseOnExceptions",
|
||||
|
@ -509,6 +511,35 @@ void debugger::SetBreakpointByUrlRequest::accept(
|
|||
handler.handle(*this);
|
||||
}
|
||||
|
||||
debugger::SetBreakpointsActiveRequest::SetBreakpointsActiveRequest()
|
||||
: Request("Debugger.setBreakpointsActive") {}
|
||||
|
||||
debugger::SetBreakpointsActiveRequest::SetBreakpointsActiveRequest(
|
||||
const dynamic &obj)
|
||||
: Request("Debugger.setBreakpointsActive") {
|
||||
assign(id, obj, "id");
|
||||
assign(method, obj, "method");
|
||||
|
||||
dynamic params = obj.at("params");
|
||||
assign(active, params, "active");
|
||||
}
|
||||
|
||||
dynamic debugger::SetBreakpointsActiveRequest::toDynamic() const {
|
||||
dynamic params = dynamic::object;
|
||||
put(params, "active", active);
|
||||
|
||||
dynamic obj = dynamic::object;
|
||||
put(obj, "id", id);
|
||||
put(obj, "method", method);
|
||||
put(obj, "params", std::move(params));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void debugger::SetBreakpointsActiveRequest::accept(
|
||||
RequestHandler &handler) const {
|
||||
handler.handle(*this);
|
||||
}
|
||||
|
||||
debugger::SetInstrumentationBreakpointRequest::
|
||||
SetInstrumentationBreakpointRequest()
|
||||
: Request("Debugger.setInstrumentationBreakpoint") {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// @generated SignedSource<<356df52df2a053b5254f0e039cc36a7b>>
|
||||
// @generated SignedSource<<0563169b47d73a70d7540528f28d1d13>>
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -38,6 +38,7 @@ struct SetBreakpointByUrlRequest;
|
|||
struct SetBreakpointByUrlResponse;
|
||||
struct SetBreakpointRequest;
|
||||
struct SetBreakpointResponse;
|
||||
struct SetBreakpointsActiveRequest;
|
||||
struct SetInstrumentationBreakpointRequest;
|
||||
struct SetInstrumentationBreakpointResponse;
|
||||
struct SetPauseOnExceptionsRequest;
|
||||
|
@ -89,6 +90,7 @@ struct RequestHandler {
|
|||
virtual void handle(const debugger::ResumeRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetBreakpointRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetBreakpointByUrlRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetBreakpointsActiveRequest &req) = 0;
|
||||
virtual void handle(
|
||||
const debugger::SetInstrumentationBreakpointRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetPauseOnExceptionsRequest &req) = 0;
|
||||
|
@ -116,6 +118,7 @@ struct NoopRequestHandler : public RequestHandler {
|
|||
void handle(const debugger::ResumeRequest &req) override {}
|
||||
void handle(const debugger::SetBreakpointRequest &req) override {}
|
||||
void handle(const debugger::SetBreakpointByUrlRequest &req) override {}
|
||||
void handle(const debugger::SetBreakpointsActiveRequest &req) override {}
|
||||
void handle(
|
||||
const debugger::SetInstrumentationBreakpointRequest &req) override {}
|
||||
void handle(const debugger::SetPauseOnExceptionsRequest &req) override {}
|
||||
|
@ -354,6 +357,16 @@ struct debugger::SetBreakpointByUrlRequest : public Request {
|
|||
folly::Optional<std::string> condition;
|
||||
};
|
||||
|
||||
struct debugger::SetBreakpointsActiveRequest : public Request {
|
||||
SetBreakpointsActiveRequest();
|
||||
explicit SetBreakpointsActiveRequest(const folly::dynamic &obj);
|
||||
|
||||
folly::dynamic toDynamic() const override;
|
||||
void accept(RequestHandler &handler) const override;
|
||||
|
||||
bool active{};
|
||||
};
|
||||
|
||||
struct debugger::SetInstrumentationBreakpointRequest : public Request {
|
||||
SetInstrumentationBreakpointRequest();
|
||||
explicit SetInstrumentationBreakpointRequest(const folly::dynamic &obj);
|
||||
|
|
|
@ -750,6 +750,70 @@ TEST(ConnectionTests, testSetBreakpointById) {
|
|||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
}
|
||||
|
||||
TEST(ConnectionTests, testActivateBreakpoints) {
|
||||
TestContext context;
|
||||
AsyncHermesRuntime &asyncRuntime = context.runtime();
|
||||
SyncConnection &conn = context.conn();
|
||||
int msgId = 1;
|
||||
|
||||
asyncRuntime.executeScriptAsync(R"(
|
||||
debugger; // line 1
|
||||
x=100 // 2
|
||||
debugger; // 3
|
||||
x=101; // 4
|
||||
)");
|
||||
|
||||
send<m::debugger::EnableRequest>(conn, ++msgId);
|
||||
expectExecutionContextCreated(conn);
|
||||
auto script = expectNotification<m::debugger::ScriptParsedNotification>(conn);
|
||||
|
||||
expectPaused(conn, "other", {{"global", 1, 1}});
|
||||
|
||||
// Set breakpoint #1
|
||||
m::debugger::SetBreakpointRequest req;
|
||||
req.id = ++msgId;
|
||||
req.location.scriptId = script.scriptId;
|
||||
req.location.lineNumber = 2;
|
||||
conn.send(req.toJson());
|
||||
expectResponse<m::debugger::SetBreakpointResponse>(conn, req.id);
|
||||
|
||||
// Set breakpoint #2
|
||||
req.id = ++msgId;
|
||||
req.location.scriptId = script.scriptId;
|
||||
req.location.lineNumber = 4;
|
||||
conn.send(req.toJson());
|
||||
expectResponse<m::debugger::SetBreakpointResponse>(conn, req.id);
|
||||
|
||||
// Disable breakpoints
|
||||
m::debugger::SetBreakpointsActiveRequest activeReq;
|
||||
activeReq.id = ++msgId;
|
||||
activeReq.active = false;
|
||||
conn.send(activeReq.toJson());
|
||||
expectResponse<m::OkResponse>(conn, activeReq.id);
|
||||
|
||||
// Resume
|
||||
send<m::debugger::ResumeRequest>(conn, ++msgId);
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
|
||||
// Expect first breakpoint to be skipped, now hitting line #3
|
||||
expectPaused(conn, "other", {{"global", 3, 1}});
|
||||
|
||||
// Re-enable breakpoints
|
||||
activeReq.id = ++msgId;
|
||||
activeReq.active = true;
|
||||
conn.send(activeReq.toJson());
|
||||
expectResponse<m::OkResponse>(conn, activeReq.id);
|
||||
|
||||
// Resume and expect breakpoints to trigger again
|
||||
send<m::debugger::ResumeRequest>(conn, ++msgId);
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
expectPaused(conn, "other", {{"global", 4, 1}});
|
||||
|
||||
// Continue and exit
|
||||
send<m::debugger::ResumeRequest>(conn, ++msgId);
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
}
|
||||
|
||||
TEST(ConnectionTests, testSetBreakpointByIdWithColumnInIndenting) {
|
||||
TestContext context;
|
||||
AsyncHermesRuntime &asyncRuntime = context.runtime();
|
||||
|
|
|
@ -10,6 +10,7 @@ Debugger.resumed
|
|||
Debugger.scriptParsed
|
||||
Debugger.setBreakpoint
|
||||
Debugger.setBreakpointByUrl
|
||||
Debugger.setBreakpointsActive
|
||||
Debugger.setInstrumentationBreakpoint
|
||||
Debugger.setPauseOnExceptions
|
||||
Debugger.stepInto
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
load("@fbsource//tools/build_defs:buckconfig.bzl", "read_bool")
|
||||
load("@fbsource//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
|
||||
load("@fbsource//tools/build_defs:platform_defs.bzl", "IOS", "MACOSX")
|
||||
load("@fbsource//tools/build_defs/apple:flag_defs.bzl", "get_preprocessor_flags_for_build_mode")
|
||||
|
@ -184,78 +185,84 @@ def rn_codegen_components(
|
|||
)
|
||||
|
||||
# libs
|
||||
rn_xplat_cxx_library(
|
||||
name = "generated_components-{}".format(name),
|
||||
srcs = [
|
||||
":{}".format(generate_event_emitter_cpp_name),
|
||||
":{}".format(generate_props_cpp_name),
|
||||
":{}".format(generate_shadow_node_cpp_name),
|
||||
],
|
||||
headers = [
|
||||
":{}".format(generate_component_descriptor_h_name),
|
||||
":{}".format(generate_event_emitter_h_name),
|
||||
":{}".format(generate_props_h_name),
|
||||
":{}".format(generate_shadow_node_h_name),
|
||||
],
|
||||
header_namespace = "react/components/{}".format(name),
|
||||
exported_headers = {
|
||||
"ComponentDescriptors.h": ":{}".format(generate_component_descriptor_h_name),
|
||||
"EventEmitters.h": ":{}".format(generate_event_emitter_h_name),
|
||||
"Props.h": ":{}".format(generate_props_h_name),
|
||||
"RCTComponentViewHelpers.h": ":{}".format(generate_component_hobjcpp_name),
|
||||
"ShadowNodes.h": ":{}".format(generate_shadow_node_h_name),
|
||||
},
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
fbobjc_compiler_flags = get_apple_compiler_flags(),
|
||||
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
|
||||
ios_exported_headers = {
|
||||
"ComponentViewHelpers.h": ":{}".format(generate_component_hobjcpp_name),
|
||||
},
|
||||
ios_headers = [
|
||||
":{}".format(generate_component_hobjcpp_name),
|
||||
],
|
||||
labels = ["codegen_rule"],
|
||||
platforms = (ANDROID, APPLE, CXX),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
tests = [":generated_tests-{}".format(name)],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//third-party/glog:glog",
|
||||
"//xplat/fbsystrace:fbsystrace",
|
||||
"//xplat/folly:headers_only",
|
||||
"//xplat/folly:memory",
|
||||
"//xplat/folly:molly",
|
||||
YOGA_CXX_TARGET,
|
||||
react_native_xplat_target("fabric/debug:debug"),
|
||||
react_native_xplat_target("fabric/core:core"),
|
||||
react_native_xplat_target("fabric/graphics:graphics"),
|
||||
react_native_xplat_target("fabric/components/image:image"),
|
||||
react_native_xplat_target("fabric/imagemanager:imagemanager"),
|
||||
react_native_xplat_target("fabric/components/view:view"),
|
||||
],
|
||||
)
|
||||
if is_running_buck_project():
|
||||
rn_xplat_cxx_library(name = "generated_components-{}".format(name), visibility = ["PUBLIC"])
|
||||
else:
|
||||
rn_xplat_cxx_library(
|
||||
name = "generated_components-{}".format(name),
|
||||
srcs = [
|
||||
":{}".format(generate_event_emitter_cpp_name),
|
||||
":{}".format(generate_props_cpp_name),
|
||||
":{}".format(generate_shadow_node_cpp_name),
|
||||
],
|
||||
headers = [
|
||||
":{}".format(generate_component_descriptor_h_name),
|
||||
":{}".format(generate_event_emitter_h_name),
|
||||
":{}".format(generate_props_h_name),
|
||||
":{}".format(generate_shadow_node_h_name),
|
||||
],
|
||||
header_namespace = "react/components/{}".format(name),
|
||||
exported_headers = {
|
||||
"ComponentDescriptors.h": ":{}".format(generate_component_descriptor_h_name),
|
||||
"EventEmitters.h": ":{}".format(generate_event_emitter_h_name),
|
||||
"Props.h": ":{}".format(generate_props_h_name),
|
||||
"RCTComponentViewHelpers.h": ":{}".format(generate_component_hobjcpp_name),
|
||||
"ShadowNodes.h": ":{}".format(generate_shadow_node_h_name),
|
||||
},
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
fbobjc_compiler_flags = get_apple_compiler_flags(),
|
||||
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
|
||||
ios_exported_headers = {
|
||||
"ComponentViewHelpers.h": ":{}".format(generate_component_hobjcpp_name),
|
||||
},
|
||||
ios_headers = [
|
||||
":{}".format(generate_component_hobjcpp_name),
|
||||
],
|
||||
labels = ["codegen_rule"],
|
||||
platforms = (ANDROID, APPLE, CXX),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
tests = [":generated_tests-{}".format(name)],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
"//third-party/glog:glog",
|
||||
"//xplat/fbsystrace:fbsystrace",
|
||||
"//xplat/folly:headers_only",
|
||||
"//xplat/folly:memory",
|
||||
"//xplat/folly:molly",
|
||||
YOGA_CXX_TARGET,
|
||||
react_native_xplat_target("fabric/debug:debug"),
|
||||
react_native_xplat_target("fabric/core:core"),
|
||||
react_native_xplat_target("fabric/graphics:graphics"),
|
||||
react_native_xplat_target("fabric/components/image:image"),
|
||||
react_native_xplat_target("fabric/imagemanager:imagemanager"),
|
||||
react_native_xplat_target("fabric/components/view:view"),
|
||||
],
|
||||
)
|
||||
|
||||
rn_android_library(
|
||||
name = "generated_components_java-{}".format(name),
|
||||
srcs = [
|
||||
":{}".format(zip_generated_java_files),
|
||||
],
|
||||
labels = ["codegen_rule"],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
react_native_dep("third-party/android/androidx:annotation"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
],
|
||||
)
|
||||
if is_running_buck_project():
|
||||
rn_android_library(name = "generated_components_java-{}".format(name))
|
||||
else:
|
||||
rn_android_library(
|
||||
name = "generated_components_java-{}".format(name),
|
||||
srcs = [
|
||||
":{}".format(zip_generated_java_files),
|
||||
],
|
||||
labels = ["codegen_rule"],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
react_native_dep("third-party/android/androidx:annotation"),
|
||||
react_native_target("java/com/facebook/react/bridge:bridge"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
],
|
||||
)
|
||||
|
||||
# Tests
|
||||
fb_xplat_cxx_test(
|
||||
|
@ -308,35 +315,41 @@ def rn_codegen_cxx_modules(
|
|||
labels = ["codegen_rule"],
|
||||
)
|
||||
|
||||
rn_xplat_cxx_library(
|
||||
name = "generated_cxx_modules-{}".format(name),
|
||||
srcs = [
|
||||
":{}".format(generate_module_cpp_name),
|
||||
],
|
||||
headers = [
|
||||
":{}".format(generate_module_h_name),
|
||||
],
|
||||
header_namespace = "react/modules/{}".format(name),
|
||||
exported_headers = {
|
||||
"NativeModules.cpp": ":{}".format(generate_module_cpp_name),
|
||||
"NativeModules.h": ":{}".format(generate_module_h_name),
|
||||
},
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
fbobjc_compiler_flags = get_apple_compiler_flags(),
|
||||
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
|
||||
labels = ["codegen_rule"],
|
||||
platforms = (ANDROID, APPLE),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
exported_deps = [
|
||||
react_native_xplat_target("turbomodule/core:core"),
|
||||
],
|
||||
)
|
||||
if is_running_buck_project():
|
||||
rn_xplat_cxx_library(name = "generated_cxx_modules-{}".format(name))
|
||||
else:
|
||||
rn_xplat_cxx_library(
|
||||
name = "generated_cxx_modules-{}".format(name),
|
||||
srcs = [
|
||||
":{}".format(generate_module_cpp_name),
|
||||
],
|
||||
headers = [
|
||||
":{}".format(generate_module_h_name),
|
||||
],
|
||||
header_namespace = "react/modules/{}".format(name),
|
||||
exported_headers = {
|
||||
"NativeModules.cpp": ":{}".format(generate_module_cpp_name),
|
||||
"NativeModules.h": ":{}".format(generate_module_h_name),
|
||||
},
|
||||
compiler_flags = [
|
||||
"-fexceptions",
|
||||
"-frtti",
|
||||
"-std=c++14",
|
||||
"-Wall",
|
||||
],
|
||||
fbobjc_compiler_flags = get_apple_compiler_flags(),
|
||||
fbobjc_preprocessor_flags = get_preprocessor_flags_for_build_mode() + get_apple_inspector_flags(),
|
||||
labels = ["codegen_rule"],
|
||||
platforms = (ANDROID, APPLE),
|
||||
preprocessor_flags = [
|
||||
"-DLOG_TAG=\"ReactNative\"",
|
||||
"-DWITH_FBSYSTRACE=1",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
exported_deps = [
|
||||
react_native_xplat_target("turbomodule/core:core"),
|
||||
],
|
||||
)
|
||||
|
||||
def is_running_buck_project():
|
||||
return read_bool("fbandroid", "is_running_buck_project", False)
|
||||
|
|
Загрузка…
Ссылка в новой задаче