mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Kotlinify ReactSurfaceView (#43964)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/43964 ## Changelog: [Internal] - As in the title. Reviewed By: alanleedev Differential Revision: D55869113 fbshipit-source-id: 650304aee8aedc147b4f27b7c490fb4f64160c96
This commit is contained in:
committed by
Facebook GitHub Bot
parent
a7e9a222e7
commit
2fcdab47f5
@@ -3755,10 +3755,8 @@ public class com/facebook/react/runtime/ReactSurfaceImpl : com/facebook/react/in
|
||||
public fun updateInitProps (Landroid/os/Bundle;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/runtime/ReactSurfaceView : com/facebook/react/ReactRootView {
|
||||
public final class com/facebook/react/runtime/ReactSurfaceView : com/facebook/react/ReactRootView {
|
||||
public fun <init> (Landroid/content/Context;Lcom/facebook/react/runtime/ReactSurfaceImpl;)V
|
||||
protected fun dispatchJSPointerEvent (Landroid/view/MotionEvent;Z)V
|
||||
protected fun dispatchJSTouchEvent (Landroid/view/MotionEvent;)V
|
||||
public fun getCurrentReactContext ()Lcom/facebook/react/bridge/ReactContext;
|
||||
public fun getUIManagerType ()I
|
||||
public fun handleException (Ljava/lang/Throwable;)V
|
||||
@@ -3767,8 +3765,6 @@ public class com/facebook/react/runtime/ReactSurfaceView : com/facebook/react/Re
|
||||
public fun isViewAttachedToReactInstance ()Z
|
||||
public fun onChildEndedNativeGesture (Landroid/view/View;Landroid/view/MotionEvent;)V
|
||||
public fun onChildStartedNativeGesture (Landroid/view/View;Landroid/view/MotionEvent;)V
|
||||
protected fun onLayout (ZIIII)V
|
||||
protected fun onMeasure (II)V
|
||||
public fun requestDisallowInterceptTouchEvent (Z)V
|
||||
public fun setIsFabric (Z)V
|
||||
}
|
||||
|
||||
-248
@@ -1,248 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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.runtime;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewParent;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.config.ReactFeatureFlags;
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException;
|
||||
import com.facebook.react.uimanager.JSPointerDispatcher;
|
||||
import com.facebook.react.uimanager.JSTouchDispatcher;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import java.util.Objects;
|
||||
|
||||
/** A view created by {@link ReactSurface} that's responsible for rendering a React component. */
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class ReactSurfaceView extends ReactRootView {
|
||||
|
||||
private static final String TAG = "ReactSurfaceView";
|
||||
|
||||
private final ReactSurfaceImpl mSurface;
|
||||
|
||||
private final JSTouchDispatcher mJSTouchDispatcher;
|
||||
private @Nullable JSPointerDispatcher mJSPointerDispatcher;
|
||||
|
||||
private boolean mWasMeasured = false;
|
||||
private int mWidthMeasureSpec = 0;
|
||||
private int mHeightMeasureSpec = 0;
|
||||
|
||||
public ReactSurfaceView(Context context, ReactSurfaceImpl surface) {
|
||||
super(context);
|
||||
mSurface = surface;
|
||||
mJSTouchDispatcher = new JSTouchDispatcher(this);
|
||||
if (ReactFeatureFlags.dispatchPointerEvents) {
|
||||
mJSPointerDispatcher = new JSPointerDispatcher(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactSurfaceView.onMeasure");
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
View child = getChildAt(i);
|
||||
int childSize =
|
||||
child.getLeft()
|
||||
+ child.getMeasuredWidth()
|
||||
+ child.getPaddingLeft()
|
||||
+ child.getPaddingRight();
|
||||
width = Math.max(width, childSize);
|
||||
}
|
||||
} else {
|
||||
width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
}
|
||||
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
View child = getChildAt(i);
|
||||
int childSize =
|
||||
child.getTop()
|
||||
+ child.getMeasuredHeight()
|
||||
+ child.getPaddingTop()
|
||||
+ child.getPaddingBottom();
|
||||
height = Math.max(height, childSize);
|
||||
}
|
||||
} else {
|
||||
height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
}
|
||||
setMeasuredDimension(width, height);
|
||||
|
||||
mWasMeasured = true;
|
||||
mWidthMeasureSpec = widthMeasureSpec;
|
||||
mHeightMeasureSpec = heightMeasureSpec;
|
||||
|
||||
Point viewportOffset = getViewportOffset();
|
||||
|
||||
mSurface.updateLayoutSpecs(
|
||||
mWidthMeasureSpec, mHeightMeasureSpec, viewportOffset.x, viewportOffset.y);
|
||||
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
// Call updateLayoutSpecs to update locationOnScreen offsets, in case they've changed
|
||||
if (mWasMeasured && changed) {
|
||||
Point viewportOffset = getViewportOffset();
|
||||
mSurface.updateLayoutSpecs(
|
||||
mWidthMeasureSpec, mHeightMeasureSpec, viewportOffset.x, viewportOffset.y);
|
||||
}
|
||||
}
|
||||
|
||||
private Point getViewportOffset() {
|
||||
int[] locationOnScreen = new int[2];
|
||||
getLocationOnScreen(locationOnScreen);
|
||||
|
||||
// we need to subtract visibleWindowCoords - to subtract possible window insets, split
|
||||
// screen or multi window
|
||||
Rect visibleWindowFrame = new Rect();
|
||||
getWindowVisibleDisplayFrame(visibleWindowFrame);
|
||||
locationOnScreen[0] -= visibleWindowFrame.left;
|
||||
locationOnScreen[1] -= visibleWindowFrame.top;
|
||||
|
||||
return new Point(locationOnScreen[0], locationOnScreen[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
// Override in order to still receive events to onInterceptTouchEvent even when some other
|
||||
// views disallow that, but propagate it up the tree if possible.
|
||||
ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a child starts a native gesture (e.g. a scroll in a ScrollView). Should be called
|
||||
* from the child's onTouchIntercepted implementation.
|
||||
*/
|
||||
@Override
|
||||
public void onChildStartedNativeGesture(View childView, MotionEvent ev) {
|
||||
EventDispatcher eventDispatcher = mSurface.getEventDispatcher();
|
||||
if (eventDispatcher == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mJSTouchDispatcher != null) {
|
||||
mJSTouchDispatcher.onChildStartedNativeGesture(ev, eventDispatcher);
|
||||
}
|
||||
if (childView != null && mJSPointerDispatcher != null) {
|
||||
mJSPointerDispatcher.onChildStartedNativeGesture(childView, ev, eventDispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildEndedNativeGesture(View childView, MotionEvent ev) {
|
||||
EventDispatcher eventDispatcher = mSurface.getEventDispatcher();
|
||||
if (eventDispatcher == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mJSTouchDispatcher != null && mSurface.getEventDispatcher() != null) {
|
||||
mJSTouchDispatcher.onChildEndedNativeGesture(ev, mSurface.getEventDispatcher());
|
||||
}
|
||||
if (mJSPointerDispatcher != null) {
|
||||
mJSPointerDispatcher.onChildStartedNativeGesture(childView, ev, eventDispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleException(Throwable t) {
|
||||
ReactHostImpl reactHost = mSurface.getReactHost();
|
||||
if (reactHost != null) {
|
||||
String errorMessage = Objects.toString(t.getMessage(), "");
|
||||
Exception e = new IllegalViewOperationException(errorMessage, this, t);
|
||||
reactHost.handleHostException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIsFabric(boolean isFabric) {
|
||||
// This surface view is always on Fabric regardless.
|
||||
super.setIsFabric(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @UIManagerType int getUIManagerType() {
|
||||
// This surface view is always on Fabric.
|
||||
return UIManagerType.FABRIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchJSTouchEvent(MotionEvent event) {
|
||||
if (mJSTouchDispatcher == null) {
|
||||
FLog.w(TAG, "Unable to dispatch touch events to JS before the dispatcher is available");
|
||||
return;
|
||||
}
|
||||
EventDispatcher eventDispatcher = mSurface.getEventDispatcher();
|
||||
if (eventDispatcher != null) {
|
||||
mJSTouchDispatcher.handleTouchEvent(event, eventDispatcher);
|
||||
} else {
|
||||
FLog.w(
|
||||
TAG, "Unable to dispatch touch events to JS as the React instance has not been attached");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchJSPointerEvent(MotionEvent event, boolean isCapture) {
|
||||
if (mJSPointerDispatcher == null) {
|
||||
if (!ReactFeatureFlags.dispatchPointerEvents) {
|
||||
return;
|
||||
}
|
||||
FLog.w(TAG, "Unable to dispatch pointer events to JS before the dispatcher is available");
|
||||
return;
|
||||
}
|
||||
EventDispatcher eventDispatcher = mSurface.getEventDispatcher();
|
||||
if (eventDispatcher != null) {
|
||||
mJSPointerDispatcher.handleMotionEvent(event, eventDispatcher, isCapture);
|
||||
} else {
|
||||
FLog.w(
|
||||
TAG,
|
||||
"Unable to dispatch pointer events to JS as the React instance has not been attached");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActiveReactContext() {
|
||||
return mSurface.isAttached() && mSurface.getReactHost().getCurrentReactContext() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasActiveReactInstance() {
|
||||
return mSurface.isAttached() && mSurface.getReactHost().isInstanceInitialized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ReactContext getCurrentReactContext() {
|
||||
if (mSurface.isAttached()) {
|
||||
return mSurface.getReactHost().getCurrentReactContext();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewAttachedToReactInstance() {
|
||||
return mSurface.isAttached();
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.facebook.react.runtime
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import android.graphics.Rect
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.react.ReactRootView
|
||||
import com.facebook.react.bridge.ReactContext
|
||||
import com.facebook.react.config.ReactFeatureFlags
|
||||
import com.facebook.react.uimanager.IllegalViewOperationException
|
||||
import com.facebook.react.uimanager.JSPointerDispatcher
|
||||
import com.facebook.react.uimanager.JSTouchDispatcher
|
||||
import com.facebook.react.uimanager.common.UIManagerType
|
||||
import com.facebook.systrace.Systrace
|
||||
import java.util.Objects
|
||||
|
||||
/** A view created by [ReactSurface] that's responsible for rendering a React component. */
|
||||
public class ReactSurfaceView(context: Context?, private val surface: ReactSurfaceImpl) :
|
||||
ReactRootView(context) {
|
||||
private val jsTouchDispatcher: JSTouchDispatcher = JSTouchDispatcher(this)
|
||||
private var jsPointerDispatcher: JSPointerDispatcher? = null
|
||||
private var wasMeasured = false
|
||||
private var widthMeasureSpec = 0
|
||||
private var heightMeasureSpec = 0
|
||||
|
||||
init {
|
||||
if (ReactFeatureFlags.dispatchPointerEvents) {
|
||||
jsPointerDispatcher = JSPointerDispatcher(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactSurfaceView.onMeasure")
|
||||
var width = 0
|
||||
var height = 0
|
||||
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
|
||||
if (widthMode == MeasureSpec.AT_MOST || widthMode == MeasureSpec.UNSPECIFIED) {
|
||||
for (i in 0 until childCount) {
|
||||
val child = getChildAt(i)
|
||||
val childSize = (child.left + child.measuredWidth + child.paddingLeft + child.paddingRight)
|
||||
width = Math.max(width, childSize)
|
||||
}
|
||||
} else {
|
||||
width = MeasureSpec.getSize(widthMeasureSpec)
|
||||
}
|
||||
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
|
||||
if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
for (i in 0 until childCount) {
|
||||
val child = getChildAt(i)
|
||||
val childSize = (child.top + child.measuredHeight + child.paddingTop + child.paddingBottom)
|
||||
height = Math.max(height, childSize)
|
||||
}
|
||||
} else {
|
||||
height = MeasureSpec.getSize(heightMeasureSpec)
|
||||
}
|
||||
setMeasuredDimension(width, height)
|
||||
wasMeasured = true
|
||||
this.widthMeasureSpec = widthMeasureSpec
|
||||
this.heightMeasureSpec = heightMeasureSpec
|
||||
val viewportOffset = viewportOffset
|
||||
surface.updateLayoutSpecs(
|
||||
widthMeasureSpec, heightMeasureSpec, viewportOffset.x, viewportOffset.y)
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE)
|
||||
}
|
||||
|
||||
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
|
||||
// Call updateLayoutSpecs to update locationOnScreen offsets, in case they've changed
|
||||
if (wasMeasured && changed) {
|
||||
val viewportOffset = viewportOffset
|
||||
surface.updateLayoutSpecs(
|
||||
widthMeasureSpec, heightMeasureSpec, viewportOffset.x, viewportOffset.y)
|
||||
}
|
||||
}
|
||||
|
||||
private val viewportOffset: Point
|
||||
get() {
|
||||
val locationOnScreen = IntArray(2)
|
||||
getLocationOnScreen(locationOnScreen)
|
||||
|
||||
// we need to subtract visibleWindowCoords - to subtract possible window insets, split
|
||||
// screen or multi window
|
||||
val visibleWindowFrame = Rect()
|
||||
getWindowVisibleDisplayFrame(visibleWindowFrame)
|
||||
locationOnScreen[0] -= visibleWindowFrame.left
|
||||
locationOnScreen[1] -= visibleWindowFrame.top
|
||||
return Point(locationOnScreen[0], locationOnScreen[1])
|
||||
}
|
||||
|
||||
override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
|
||||
// Override in order to still receive events to onInterceptTouchEvent even when some other
|
||||
// views disallow that, but propagate it up the tree if possible.
|
||||
parent?.requestDisallowInterceptTouchEvent(disallowIntercept)
|
||||
}
|
||||
/**
|
||||
* Called when a child starts a native gesture (e.g. a scroll in a ScrollView). Should be called
|
||||
* from the child's onTouchIntercepted implementation.
|
||||
*/
|
||||
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
|
||||
val eventDispatcher = surface.eventDispatcher ?: return
|
||||
jsTouchDispatcher.onChildStartedNativeGesture(ev, eventDispatcher)
|
||||
childView?.let { jsPointerDispatcher?.onChildStartedNativeGesture(it, ev, eventDispatcher) }
|
||||
}
|
||||
|
||||
override fun onChildEndedNativeGesture(childView: View, ev: MotionEvent) {
|
||||
val eventDispatcher = surface.eventDispatcher ?: return
|
||||
jsTouchDispatcher.onChildEndedNativeGesture(ev, eventDispatcher)
|
||||
jsPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
|
||||
}
|
||||
|
||||
override fun handleException(t: Throwable) {
|
||||
val reactHost = surface.reactHost
|
||||
val errorMessage = Objects.toString(t.message, "")
|
||||
val e: Exception = IllegalViewOperationException(errorMessage, this, t)
|
||||
reactHost.handleHostException(e)
|
||||
}
|
||||
|
||||
override fun setIsFabric(isFabric: Boolean) {
|
||||
// This surface view is always on Fabric regardless.
|
||||
super.setIsFabric(true)
|
||||
}
|
||||
|
||||
// This surface view is always on Fabric.
|
||||
@UIManagerType override fun getUIManagerType(): Int = UIManagerType.FABRIC
|
||||
|
||||
override fun dispatchJSTouchEvent(event: MotionEvent) {
|
||||
val eventDispatcher = surface.eventDispatcher
|
||||
if (eventDispatcher != null) {
|
||||
jsTouchDispatcher.handleTouchEvent(event, eventDispatcher)
|
||||
} else {
|
||||
FLog.w(
|
||||
TAG, "Unable to dispatch touch events to JS as the React instance has not been attached")
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchJSPointerEvent(event: MotionEvent, isCapture: Boolean) {
|
||||
if (jsPointerDispatcher == null) {
|
||||
if (!ReactFeatureFlags.dispatchPointerEvents) {
|
||||
return
|
||||
}
|
||||
FLog.w(TAG, "Unable to dispatch pointer events to JS before the dispatcher is available")
|
||||
return
|
||||
}
|
||||
val eventDispatcher = surface.eventDispatcher
|
||||
if (eventDispatcher != null) {
|
||||
jsPointerDispatcher?.handleMotionEvent(event, eventDispatcher, isCapture)
|
||||
} else {
|
||||
FLog.w(
|
||||
TAG,
|
||||
"Unable to dispatch pointer events to JS as the React instance has not been attached")
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasActiveReactContext(): Boolean =
|
||||
surface.isAttached && surface.reactHost.currentReactContext != null
|
||||
|
||||
override fun hasActiveReactInstance(): Boolean =
|
||||
surface.isAttached && surface.reactHost.isInstanceInitialized
|
||||
|
||||
override fun getCurrentReactContext(): ReactContext? =
|
||||
if (surface.isAttached) {
|
||||
surface.reactHost.currentReactContext
|
||||
} else null
|
||||
|
||||
override fun isViewAttachedToReactInstance(): Boolean = surface.isAttached
|
||||
|
||||
private companion object {
|
||||
private const val TAG = "ReactSurfaceView"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user