Permalink
Browse files

Open source Fabric android

Summary: This diff open sources Fabric Android implementation and it extracts ComponentDescriptorFactory into a function that can be "injected" per application

Reviewed By: shergin

Differential Revision: D13616172

fbshipit-source-id: 7b7a6461216740b5a1ad5ebbead9e37de4570221
  • Loading branch information...
mdvacca authored and facebook-github-bot committed Jan 16, 2019
1 parent cfbb227 commit b421b5f4bd856f8a79f887c6a9197663316ffdbf
Showing with 2,738 additions and 52 deletions.
  1. +2 −1 React/Fabric/RCTScheduler.mm
  2. +14 −7 ReactAndroid/src/main/java/com/facebook/react/fabric/BUCK
  3. +5 −2 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricBinding.java
  4. +155 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricEventEmitter.java
  5. +69 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricJSIModuleProvider.java
  6. +422 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java
  7. +34 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/GuardedFrameCallback.java
  8. +72 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/Binding.java
  9. +27 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentFactoryDelegate.java
  10. +25 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/ComponentRegistry.java
  11. +61 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventBeatManager.java
  12. +49 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/EventEmitterWrapper.java
  13. +28 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/FabricSoLoader.java
  14. +59 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/AsyncEventBeat.h
  15. +47 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/BUCK
  16. +376 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.cpp
  17. +60 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/Binding.h
  18. +27 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.cpp
  19. +38 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/ComponentFactoryDelegate.h
  20. +47 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.cpp
  21. +50 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventBeatManager.h
  22. +30 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.cpp
  23. +34 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/EventEmitterWrapper.h
  24. +20 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/jsi/jni/OnLoad.cpp
  25. +53 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ContextBasedViewPool.java
  26. +57 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/LayoutMetricsConversions.java
  27. +334 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/MountingManager.java
  28. +63 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/ViewPool.java
  29. +52 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/BatchMountItem.java
  30. +47 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/CreateMountItem.java
  31. +28 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/DeleteMountItem.java
  32. +37 −0 ...Android/src/main/java/com/facebook/react/fabric/mounting/mountitems/DispatchCommandMountItem.java
  33. +45 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/InsertMountItem.java
  34. +17 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/MountItem.java
  35. +45 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/RemoveMountItem.java
  36. +31 −0 ...roid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateEventEmitterMountItem.java
  37. +61 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLayoutMountItem.java
  38. +36 −0 ...Android/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdateLocalDataMountItem.java
  39. +31 −0 ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/UpdatePropsMountItem.java
  40. +6 −5 ReactCommon/fabric/sample/SampleComponentDescriptorFactor.cpp
  41. +1 −1 ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp
  42. +6 −6 ReactCommon/fabric/uimanager/ComponentDescriptorFactory.h
  43. +5 −5 ReactCommon/fabric/uimanager/Scheduler.cpp
  44. +4 −1 ReactCommon/fabric/uimanager/Scheduler.h
  45. +28 −24 ReactCommon/fabric/uimanager/tests/UITemplateProcessorTest.cpp
@@ -7,6 +7,7 @@

#import "RCTScheduler.h"

#import <react/uimanager/ComponentDescriptorFactory.h>
#import <react/uimanager/ContextContainer.h>
#import <react/uimanager/Scheduler.h>
#import <react/uimanager/SchedulerDelegate.h>
@@ -49,7 +50,7 @@ - (instancetype)initWithContextContainer:(std::shared_ptr<void>)contextContatine
{
if (self = [super init]) {
_delegateProxy = std::make_shared<SchedulerDelegateProxy>((__bridge void *)self);
_scheduler = std::make_shared<Scheduler>(std::static_pointer_cast<ContextContainer>(contextContatiner));
_scheduler = std::make_shared<Scheduler>(std::static_pointer_cast<ContextContainer>(contextContatiner), getDefaultComponentRegistryFactory());
_scheduler->setDelegate(_delegateProxy.get());
}

@@ -4,28 +4,35 @@ rn_android_library(
name = "fabric",
srcs = glob([
"*.java",
"events/*.java",
"jsi/*.java",
"mounting/**/*.java",
]),
provided_deps = [
react_native_dep("third-party/android/support/v4:lib-support-v4"),
react_native_dep("third-party/android/support-new:support-v4"),
],
required_for_source_only_abi = True,
visibility = [
"PUBLIC",
],
deps = [
YOGA_TARGET,
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("java/com/facebook/systrace:systrace"),
react_native_dep("libraries/fbcore/src/main/java/com/facebook/common/logging:logging"),
react_native_dep("third-party/java/infer-annotations:infer-annotations"),
react_native_dep("third-party/java/jsr-305:jsr-305"),
react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"),
react_native_target("java/com/facebook/debug/tags:tags"),
react_native_target("java/com/facebook/debug/holder:holder"),
react_native_target("java/com/facebook/react/bridge:bridge"),
react_native_target("java/com/facebook/react/uimanager:uimanager"),
react_native_target("java/com/facebook/react/uimanager/annotations:annotations"),
react_native_target("java/com/facebook/react/fabric/jsi/jni:jni"),
react_native_target("java/com/facebook/react:react"),
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/modules/core:core"),
react_native_target("java/com/facebook/react/modules/i18nmanager:i18nmanager"),
react_native_target("java/com/facebook/react/common:common"),
react_native_target("java/com/facebook/react/uimanager:uimanager"),
react_native_target("java/com/facebook/react/views/view:view"),
react_native_target("java/com/facebook/react/touch:touch"),
],
exported_deps = [
],
)
@@ -8,15 +8,18 @@

import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.queue.MessageQueueThread;
import com.facebook.react.fabric.jsi.ComponentFactoryDelegate;
import com.facebook.react.fabric.jsi.EventBeatManager;

public interface FabricBinding {

// TODO: T31905686 change types of UIManager and EventBeatManager when moving to OSS
void register(
JavaScriptContextHolder jsContext,
FabricBinder fabricBinder,
Object eventBeatManager,
MessageQueueThread jsMessageQueueThread);
EventBeatManager eventBeatManager,
MessageQueueThread jsMessageQueueThread,
ComponentFactoryDelegate componentFactoryDelegate);

void unregister();
}
@@ -0,0 +1,155 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>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.fabric;

import static com.facebook.react.uimanager.events.TouchesHelper.CHANGED_TOUCHES_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_CANCEL_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TOP_TOUCH_END_KEY;
import static com.facebook.react.uimanager.events.TouchesHelper.TOUCHES_KEY;

import android.annotation.TargetApi;
import android.os.Build;
import android.util.Pair;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.facebook.systrace.Systrace;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nullable;

@TargetApi(Build.VERSION_CODES.ECLAIR)
public class FabricEventEmitter implements RCTEventEmitter {

private static final String TAG = FabricEventEmitter.class.getSimpleName();

private final FabricUIManager mUIManager;

public FabricEventEmitter(FabricUIManager uiManager) {
mUIManager = uiManager;
}

@Override
public void receiveEvent(int reactTag, String eventName, @Nullable WritableMap params) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
"FabricEventEmitter.receiveEvent('" + eventName + "')");
mUIManager.receiveEvent(reactTag, eventName, params);
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
}

@Override
public void receiveTouches(
String eventTopLevelType, WritableArray touches, WritableArray changedIndices) {
Pair<WritableArray, WritableArray> result =
TOP_TOUCH_END_KEY.equalsIgnoreCase(eventTopLevelType)
|| TOP_TOUCH_CANCEL_KEY.equalsIgnoreCase(eventTopLevelType)
? removeTouchesAtIndices(touches, changedIndices)
: touchSubsequence(touches, changedIndices);

WritableArray changedTouches = result.first;
touches = result.second;

for (int jj = 0; jj < changedTouches.size(); jj++) {
WritableMap touch = getWritableMap(changedTouches.getMap(jj));
// Touch objects can fulfill the role of `DOM` `Event` objects if we set
// the `changedTouches`/`touches`. This saves allocations.

touch.putArray(CHANGED_TOUCHES_KEY, copyWritableArray(changedTouches));
touch.putArray(TOUCHES_KEY, copyWritableArray(touches));
WritableMap nativeEvent = touch;
int rootNodeID = 0;
int target = nativeEvent.getInt(TARGET_KEY);
if (target < 1) {
FLog.e(TAG, "A view is reporting that a touch occurred on tag zero.");
} else {
rootNodeID = target;
}

receiveEvent(rootNodeID, eventTopLevelType, touch);
}
}

/** TODO T31905686 optimize this to avoid copying arrays */
private WritableArray copyWritableArray(WritableArray array) {
WritableNativeArray ret = new WritableNativeArray();
for (int i = 0; i < array.size(); i++) {
ret.pushMap(getWritableMap(array.getMap(i)));
}
return ret;
}

/**
* Destroys `touches` by removing touch objects at indices `indices`. This is to maintain
* compatibility with W3C touch "end" events, where the active touches don't include the set that
* has just been "ended".
*
* <p>This method was originally in ReactNativeRenderer.js
*
* <p>TODO: this method is a copy from ReactNativeRenderer.removeTouchesAtIndices and it needs to
* be rewritten in a more efficient way,
*
* @param touches {@link WritableArray} Deserialized touch objects.
* @param indices {WritableArray} Indices to remove from `touches`.
* @return {Array<Touch>} Subsequence of removed touch objects.
*/
private Pair<WritableArray, WritableArray> removeTouchesAtIndices(
WritableArray touches, WritableArray indices) {
WritableArray rippedOut = new WritableNativeArray();
// use an unsafe downcast to alias to nullable elements,
// so we can delete and then compact.
WritableArray tempTouches = new WritableNativeArray();
Set<Integer> rippedOutIndices = new HashSet<>();
for (int i = 0; i < indices.size(); i++) {
int index = indices.getInt(i);
rippedOut.pushMap(getWritableMap(touches.getMap(index)));
rippedOutIndices.add(index);
}
for (int j = 0; j < touches.size(); j++) {
if (!rippedOutIndices.contains(j)) {
tempTouches.pushMap(getWritableMap(touches.getMap(j)));
}
}

return new Pair<>(rippedOut, tempTouches);
}

/**
* Selects a subsequence of `Touch`es, without destroying `touches`.
*
* <p>This method was originally in ReactNativeRenderer.js
*
* @param touches {@link WritableArray} Deserialized touch objects.
* @param changedIndices {@link WritableArray} Indices by which to pull subsequence.
* @return {Array<Touch>} Subsequence of touch objects.
*/
private Pair<WritableArray, WritableArray> touchSubsequence(
WritableArray touches, WritableArray changedIndices) {
WritableArray result = new WritableNativeArray();
for (int i = 0; i < changedIndices.size(); i++) {
result.pushMap(getWritableMap(touches.getMap(changedIndices.getInt(i))));
}
return new Pair<>(result, touches);
}

/**
* TODO: this is required because the WritableNativeArray.getMap() returns a ReadableMap instead
* of the original writableMap. this will change in the near future.
*
* @param readableMap {@link ReadableMap} source map
*/
private WritableMap getWritableMap(ReadableMap readableMap) {
WritableNativeMap map = new WritableNativeMap();
map.merge(readableMap);
return map;
}
}
@@ -0,0 +1,69 @@
// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react.fabric;

import com.facebook.react.fabric.jsi.Binding;
import com.facebook.react.fabric.jsi.ComponentFactoryDelegate;
import com.facebook.react.fabric.jsi.EventBeatManager;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.JSIModuleProvider;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.bridge.queue.MessageQueueThread;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.systrace.Systrace;

public class FabricJSIModuleProvider implements JSIModuleProvider<UIManager> {

private final ReactInstanceManager mReactInstanceManager;
private final JavaScriptContextHolder mJSContext;
private final ReactApplicationContext mReactApplicationContext;
private final ComponentFactoryDelegate mComponentFactoryDelegate;

public FabricJSIModuleProvider(
ReactInstanceManager reactInstanceManager,
ReactApplicationContext reactApplicationContext,
JavaScriptContextHolder jsContext,
ComponentFactoryDelegate componentFactoryDelegate) {
mReactInstanceManager = reactInstanceManager;
mReactApplicationContext = reactApplicationContext;
mJSContext = jsContext;
mComponentFactoryDelegate = componentFactoryDelegate;
}

@Override
public UIManager get() {
final EventBeatManager eventBeatManager =
new EventBeatManager(mJSContext, mReactApplicationContext);
final UIManager uiManager = createUIManager(eventBeatManager);
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricJSIModuleProvider.registerBinding");
final FabricBinding binding = new Binding();
MessageQueueThread jsMessageQueueThread =
mReactApplicationContext
.getCatalystInstance()
.getReactQueueConfiguration()
.getJSQueueThread();
binding.register(mJSContext, (FabricBinder) uiManager, eventBeatManager, jsMessageQueueThread,
mComponentFactoryDelegate);
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
return uiManager;
}

private UIManager createUIManager(EventBeatManager eventBeatManager) {
Systrace.beginSection(
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "FabricJSIModuleProvider.createUIManager");
UIManagerModule nativeModule = mReactApplicationContext.getNativeModule(UIManagerModule.class);
EventDispatcher eventDispatcher = nativeModule.getEventDispatcher();
FabricUIManager fabricUIManager =
new FabricUIManager(
mReactApplicationContext,
nativeModule.getViewManagerRegistry_DO_NOT_USE(),
eventDispatcher,
eventBeatManager);

Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
return fabricUIManager;
}
}
Oops, something went wrong.

3 comments on commit b421b5f

@dulmandakh

This comment has been minimized.

Copy link
Collaborator

dulmandakh replied Jan 17, 2019

@mdvacca this broke Android CI

@EvanBacon

This comment has been minimized.

Copy link
Contributor

EvanBacon replied Jan 17, 2019

😍😍😍😍😍😍😍😍

@mdvacca

This comment has been minimized.

Copy link
Contributor Author

mdvacca replied Jan 17, 2019

@dulmandakh, I will fix that tomorrow

Please sign in to comment.