Skip to content

Commit d7448b4

Browse files
committed
Start native impl for Android
1 parent 21ce55c commit d7448b4

File tree

12 files changed

+1062
-3
lines changed

12 files changed

+1062
-3
lines changed

Example/android/app/src/main/java/com/swmansion/gesturehandler/react/example/MainApplication.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
import android.app.Application;
44

55
import com.facebook.react.ReactApplication;
6-
import com.oblador.vectoricons.VectorIconsPackage;
76
import com.facebook.react.ReactNativeHost;
87
import com.facebook.react.ReactPackage;
98
import com.facebook.react.shell.MainReactPackage;
109
import com.facebook.soloader.SoLoader;
10+
import com.oblador.vectoricons.VectorIconsPackage;
1111
import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;
12+
import com.swmansion.reanimated.ReanimatedPackage;
1213

1314
import java.util.Arrays;
1415
import java.util.List;
@@ -25,8 +26,9 @@ public boolean getUseDeveloperSupport() {
2526
protected List<ReactPackage> getPackages() {
2627
return Arrays.<ReactPackage>asList(
2728
new MainReactPackage(),
28-
new VectorIconsPackage(),
29-
new RNGestureHandlerPackage()
29+
new VectorIconsPackage(),
30+
new RNGestureHandlerPackage(),
31+
new ReanimatedPackage()
3032
);
3133
}
3234
};
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
package com.swmansion.reanimated;
2+
3+
import android.util.Log;
4+
import android.util.SparseArray;
5+
6+
import com.facebook.infer.annotation.Assertions;
7+
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
8+
import com.facebook.react.bridge.ReactContext;
9+
import com.facebook.react.bridge.ReadableMap;
10+
import com.facebook.react.modules.core.ReactChoreographer;
11+
import com.facebook.react.uimanager.GuardedFrameCallback;
12+
import com.facebook.react.uimanager.UIImplementation;
13+
import com.facebook.react.uimanager.UIManagerModule;
14+
import com.facebook.react.uimanager.events.Event;
15+
import com.facebook.react.uimanager.events.EventDispatcherListener;
16+
import com.swmansion.reanimated.nodes.Node;
17+
import com.swmansion.reanimated.nodes.PropsNode;
18+
import com.swmansion.reanimated.nodes.StyleNode;
19+
import com.swmansion.reanimated.nodes.TransformNode;
20+
import com.swmansion.reanimated.nodes.ValueNode;
21+
22+
import javax.annotation.Nullable;
23+
24+
public class NodesManager implements EventDispatcherListener {
25+
26+
private final SparseArray<Node> mAnimatedNodes = new SparseArray<>();
27+
private final UIImplementation mUIImplementation;
28+
private final ReactChoreographer mReactChoreographer;
29+
private final GuardedFrameCallback mFrameCallbck;
30+
private boolean mCallbackPosted;
31+
private boolean mWantRunUpdates;
32+
33+
public final UpdateContext updateContext;
34+
35+
public NodesManager(ReactContext context) {
36+
UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
37+
updateContext = new UpdateContext();
38+
mUIImplementation = uiManager.getUIImplementation();
39+
uiManager.getEventDispatcher().addListener(this);
40+
41+
mReactChoreographer = ReactChoreographer.getInstance();
42+
mFrameCallbck = new GuardedFrameCallback(context) {
43+
@Override
44+
protected void doFrameGuarded(long frameTimeNanos) {
45+
onAnimationFrame(frameTimeNanos);
46+
}
47+
};
48+
}
49+
50+
public void onHostPause() {
51+
if (mCallbackPosted) {
52+
stopUpdatingOnAnimationFrame();
53+
mCallbackPosted = true;
54+
}
55+
}
56+
57+
public void onHostResume() {
58+
if (mCallbackPosted) {
59+
mCallbackPosted = false;
60+
startUpdatingOnAnimationFrame();
61+
}
62+
}
63+
64+
private void startUpdatingOnAnimationFrame() {
65+
if (!mCallbackPosted) {
66+
mCallbackPosted = true;
67+
mReactChoreographer.postFrameCallback(
68+
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE,
69+
mFrameCallbck);
70+
}
71+
}
72+
73+
private void stopUpdatingOnAnimationFrame() {
74+
if (mCallbackPosted) {
75+
mCallbackPosted = false;
76+
mReactChoreographer.removeFrameCallback(
77+
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE,
78+
mFrameCallbck);
79+
}
80+
}
81+
82+
private void onAnimationFrame(long frameTimeNanos) {
83+
// TODO: process enqueued events
84+
Log.e("CAT", "FRAME");
85+
86+
if (mWantRunUpdates) {
87+
Node.runUpdates(updateContext);
88+
}
89+
90+
mCallbackPosted = false;
91+
mWantRunUpdates = false;
92+
}
93+
94+
public @Nullable Node findNodeById(int id) {
95+
return mAnimatedNodes.get(id);
96+
}
97+
98+
public void createNode(int nodeID, ReadableMap config) {
99+
if (mAnimatedNodes.get(nodeID) != null) {
100+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + nodeID +
101+
" already exists");
102+
}
103+
String type = config.getString("type");
104+
final Node node;
105+
if ("props".equals(type)) {
106+
node = new PropsNode(nodeID, config, this, mUIImplementation);
107+
} else if ("style".equals(type)) {
108+
node = new StyleNode(nodeID, config, this);
109+
} else if ("transform".equals(type)) {
110+
node = new TransformNode(nodeID, config, this);
111+
} else if ("value".equals(type)) {
112+
node = new ValueNode(nodeID, config, this);
113+
} else if ("block".equals(type)) {
114+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
115+
} else if ("cond".equals(type)) {
116+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
117+
} else if ("op".equals(type)) {
118+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
119+
} else if ("set".equals(type)) {
120+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
121+
} else if ("debug".equals(type)) {
122+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
123+
} else if ("clock".equals(type)) {
124+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
125+
} else if ("clockStart".equals(type)) {
126+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
127+
} else if ("clockStop".equals(type)) {
128+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
129+
} else if ("clockTest".equals(type)) {
130+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
131+
} else if ("call".equals(type)) {
132+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
133+
} else if ("bezier".equals(type)) {
134+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
135+
} else if ("event".equals(type)) {
136+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
137+
} else {
138+
throw new JSApplicationIllegalArgumentException("Unsupported node type: " + type);
139+
}
140+
mAnimatedNodes.put(nodeID, node);
141+
}
142+
143+
public void dropNode(int tag) {
144+
mAnimatedNodes.remove(tag);
145+
}
146+
147+
public void connectNodes(int parentID, int childID) {
148+
Node parentNode = mAnimatedNodes.get(parentID);
149+
if (parentNode == null) {
150+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + parentID +
151+
" does not exists");
152+
}
153+
Node childNode = mAnimatedNodes.get(childID);
154+
if (childNode == null) {
155+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + childID +
156+
" does not exists");
157+
}
158+
parentNode.addChild(childNode);
159+
}
160+
161+
public void disconnectNodes(int parentID, int childID) {
162+
Node parentNode = mAnimatedNodes.get(parentID);
163+
if (parentNode == null) {
164+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + parentID +
165+
" does not exists");
166+
}
167+
Node childNode = mAnimatedNodes.get(childID);
168+
if (childNode == null) {
169+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + childID +
170+
" does not exists");
171+
}
172+
parentNode.removeChild(childNode);
173+
}
174+
175+
public void connectNodeToView(int nodeID, int viewTag) {
176+
Node node = mAnimatedNodes.get(nodeID);
177+
if (node == null) {
178+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + nodeID +
179+
" does not exists");
180+
}
181+
if (!(node instanceof PropsNode)) {
182+
throw new JSApplicationIllegalArgumentException("Animated node connected to view should be" +
183+
"of type " + PropsNode.class.getName());
184+
}
185+
((PropsNode) node).connectToView(viewTag);
186+
}
187+
188+
public void disconnectNodeFromView(int nodeID, int viewTag) {
189+
Node node = mAnimatedNodes.get(nodeID);
190+
if (node == null) {
191+
throw new JSApplicationIllegalArgumentException("Animated node with ID " + nodeID +
192+
" does not exists");
193+
}
194+
if (!(node instanceof PropsNode)) {
195+
throw new JSApplicationIllegalArgumentException("Animated node connected to view should be" +
196+
"of type " + PropsNode.class.getName());
197+
}
198+
((PropsNode) node).disconnectFromView(viewTag);
199+
}
200+
201+
public void attachEvent(int viewTag, String eventName, int eventNodeID) {
202+
// int nodeTag = eventMapping.getInt("animatedValueTag");
203+
// AnimatedNode node = mAnimatedNodes.get(nodeTag);
204+
// if (node == null) {
205+
// throw new JSApplicationIllegalArgumentException("Animated node with tag " + nodeTag +
206+
// " does not exists");
207+
// }
208+
// if (!(node instanceof ValueAnimatedNode)) {
209+
// throw new JSApplicationIllegalArgumentException("Animated node connected to event should be" +
210+
// "of type " + ValueAnimatedNode.class.getName());
211+
// }
212+
//
213+
// ReadableArray path = eventMapping.getArray("nativeEventPath");
214+
// List<String> pathList = new ArrayList<>(path.size());
215+
// for (int i = 0; i < path.size(); i++) {
216+
// pathList.add(path.getString(i));
217+
// }
218+
//
219+
// EventAnimationDriver event = new EventAnimationDriver(pathList, (ValueAnimatedNode) node);
220+
// String key = viewTag + eventName;
221+
// if (mEventDrivers.containsKey(key)) {
222+
// mEventDrivers.get(key).add(event);
223+
// } else {
224+
// List<EventAnimationDriver> drivers = new ArrayList<>(1);
225+
// drivers.add(event);
226+
// mEventDrivers.put(key, drivers);
227+
// }
228+
}
229+
230+
public void detachEvent(int viewTag, String eventName, int eventNodeID) {
231+
// String key = viewTag + eventName;
232+
// if (mEventDrivers.containsKey(key)) {
233+
// List<EventAnimationDriver> driversForKey = mEventDrivers.get(key);
234+
// if (driversForKey.size() == 1) {
235+
// mEventDrivers.remove(viewTag + eventName);
236+
// } else {
237+
// ListIterator<EventAnimationDriver> it = driversForKey.listIterator();
238+
// while (it.hasNext()) {
239+
// if (it.next().mValueNode.mTag == animatedValueTag) {
240+
// it.remove();
241+
// break;
242+
// }
243+
// }
244+
// }
245+
// }
246+
}
247+
248+
249+
public void postRunUpdatesAfterAnimation() {
250+
Log.e("CAT", "POST RUN UPDATES");
251+
mWantRunUpdates = true;
252+
startUpdatingOnAnimationFrame();
253+
}
254+
255+
// public void restoreDefaultValues(int animatedNodeTag, int viewTag) {
256+
// AnimatedNode node = mAnimatedNodes.get(animatedNodeTag);
257+
// // Restoring default values needs to happen before UIManager operations so it is
258+
// // possible the node hasn't been created yet if it is being connected and
259+
// // disconnected in the same batch. In that case we don't need to restore
260+
// // default values since it will never actually update the view.
261+
// if (node == null) {
262+
// return;
263+
// }
264+
// if (!(node instanceof PropsAnimatedNode)) {
265+
// throw new JSApplicationIllegalArgumentException("Animated node connected to view should be" +
266+
// "of type " + PropsAnimatedNode.class.getName());
267+
// }
268+
// PropsAnimatedNode propsAnimatedNode = (PropsAnimatedNode) node;
269+
// propsAnimatedNode.restoreDefaultValues();
270+
// }
271+
//
272+
273+
@Override
274+
public void onEventDispatch(final Event event) {
275+
// // Events can be dispatched from any thread so we have to make sure handleEvent is run from the
276+
// // UI thread.
277+
// if (UiThreadUtil.isOnUiThread()) {
278+
// handleEvent(event);
279+
// } else {
280+
// UiThreadUtil.runOnUiThread(new Runnable() {
281+
// @Override
282+
// public void run() {
283+
// handleEvent(event);
284+
// }
285+
// });
286+
// }
287+
// }
288+
//
289+
// private void handleEvent(Event event) {
290+
// if (!mEventDrivers.isEmpty()) {
291+
// // If the event has a different name in native convert it to it's JS name.
292+
// String eventName = mCustomEventNamesResolver.resolveCustomEventName(event.getEventName());
293+
// List<EventAnimationDriver> driversForKey = mEventDrivers.get(event.getViewTag() + eventName);
294+
// if (driversForKey != null) {
295+
// for (EventAnimationDriver driver : driversForKey) {
296+
// stopAnimationsForNode(driver.mValueNode);
297+
// event.dispatch(driver);
298+
// mRunUpdateNodeList.add(driver.mValueNode);
299+
// }
300+
// updateNodes(mRunUpdateNodeList);
301+
// mRunUpdateNodeList.clear();
302+
// }
303+
// }
304+
}
305+
306+
public void runUpdates(long frameTimeNanos) {
307+
// UiThreadUtil.assertOnUiThread();
308+
// boolean hasFinishedAnimations = false;
309+
//
310+
// for (int i = 0; i < mUpdatedNodes.size(); i++) {
311+
// AnimatedNode node = mUpdatedNodes.valueAt(i);
312+
// mRunUpdateNodeList.add(node);
313+
// }
314+
//
315+
// // Clean mUpdatedNodes queue
316+
// mUpdatedNodes.clear();
317+
//
318+
// for (int i = 0; i < mActiveAnimations.size(); i++) {
319+
// AnimationDriver animation = mActiveAnimations.valueAt(i);
320+
// animation.runAnimationStep(frameTimeNanos);
321+
// AnimatedNode valueNode = animation.mAnimatedValue;
322+
// mRunUpdateNodeList.add(valueNode);
323+
// if (animation.mHasFinished) {
324+
// hasFinishedAnimations = true;
325+
// }
326+
// }
327+
//
328+
// updateNodes(mRunUpdateNodeList);
329+
// mRunUpdateNodeList.clear();
330+
//
331+
// // Cleanup finished animations. Iterate over the array of animations and override ones that has
332+
// // finished, then resize `mActiveAnimations`.
333+
// if (hasFinishedAnimations) {
334+
// for (int i = mActiveAnimations.size() - 1; i >= 0; i--) {
335+
// AnimationDriver animation = mActiveAnimations.valueAt(i);
336+
// if (animation.mHasFinished) {
337+
// if (animation.mEndCallback != null) {
338+
// WritableMap endCallbackResponse = Arguments.createMap();
339+
// endCallbackResponse.putBoolean("finished", true);
340+
// animation.mEndCallback.invoke(endCallbackResponse);
341+
// }
342+
// mActiveAnimations.removeAt(i);
343+
// }
344+
// }
345+
// }
346+
}
347+
}

0 commit comments

Comments
 (0)