Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from facebook:master #834

Merged
merged 1 commit into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.JSTouchDispatcher;
import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.ReactClippingProhibitedView;
import com.facebook.react.uimanager.ReactRoot;
import com.facebook.react.uimanager.RootView;
import com.facebook.react.uimanager.RootViewUtil;
Expand Down Expand Up @@ -329,9 +330,29 @@ private void removeOnGlobalLayoutListener() {
}

@Override
public void onViewAdded(View child) {
public void onViewAdded(final View child) {
super.onViewAdded(child);

// See comments in {@code ReactRootViewProhibitedChildView} for why we want this mechanism.
if (child instanceof ReactClippingProhibitedView) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!child.isShown()) {
ReactSoftException.logSoftException(
TAG,
new IllegalViewOperationException(
"A view was illegally added as a child of a ReactRootView. "
+ "This View should not be a direct child of a ReactRootView, because it is not visible and will never be reachable. Child: "
+ child.getClass().getCanonicalName().toString()
+ " child ID: "
+ child.getId()));
}
}
});
}

if (mShouldLogContentAppeared) {
mShouldLogContentAppeared = false;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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.uimanager;

/**
* Some Views may not function if added directly to a ViewGroup that clips them. For example, TTRC
* markers may rely on `onDraw` functionality to work properly, and will break if they're clipped
* out of the View hierarchy for any resaon.
*
* <p>This situation can occur more often in Fabric with View Flattening. We may prevent this sort
* of View Flattening from occurring in the future, but the connection is not entirely certain.
*
* <p>This can occur either because ReactViewGroup clips them out, using the ordinarary subview
* clipping feature. It is also possible if a View is added directly to a ReactRootView below the
* fold of the screen.
*
* <p>Generally the solution is to prevent View flattening in JS by adding `collapsable=false` to a
* parent component of the clipped view, and/or move the View higher up in the hierarchy so it is
* always rendered within the first page of the screen.
*/
public interface ReactClippingProhibitedView {}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactSoftException;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.annotations.VisibleForTesting;
import com.facebook.react.modules.i18nmanager.I18nUtil;
Expand All @@ -38,6 +39,7 @@
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.facebook.react.uimanager.MeasureSpecAssertions;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.ReactClippingProhibitedView;
import com.facebook.react.uimanager.ReactClippingViewGroup;
import com.facebook.react.uimanager.ReactClippingViewGroupHelper;
import com.facebook.react.uimanager.ReactPointerEventsView;
Expand Down Expand Up @@ -549,7 +551,7 @@ protected void dispatchSetPressed(boolean pressed) {
}

/*package*/ void addViewWithSubviewClippingEnabled(
View child, int index, ViewGroup.LayoutParams params) {
final View child, int index, ViewGroup.LayoutParams params) {
Assertions.assertCondition(mRemoveClippedSubviews);
Assertions.assertNotNull(mClippingRect);
Assertions.assertNotNull(mAllChildren);
Expand All @@ -564,6 +566,29 @@ protected void dispatchSetPressed(boolean pressed) {
}
updateSubviewClipStatus(mClippingRect, index, clippedSoFar);
child.addOnLayoutChangeListener(mChildrenLayoutChangeListener);

if (child instanceof ReactClippingProhibitedView) {
UiThreadUtil.runOnUiThread(
new Runnable() {
@Override
public void run() {
if (!child.isShown()) {
ReactSoftException.logSoftException(
TAG,
new IllegalViewOperationException(
"Child view has been added to Parent view in which it is clipped and not visible."
+ " This is not legal for this particular child view. Child: ["
+ child.getId()
+ "] "
+ child.toString()
+ " Parent: ["
+ getId()
+ "] "
+ toString()));
}
}
});
}
}

/*package*/ void removeViewWithSubviewClippingEnabled(View view) {
Expand Down