mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
b421b5f4bd
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
156 lines
5.9 KiB
Java
156 lines
5.9 KiB
Java
/**
|
|
* 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;
|
|
}
|
|
}
|