From 13dff7cdf2635cb39f70effe3dc1ae2f3dd0131f Mon Sep 17 00:00:00 2001 From: Thomas Nardone Date: Tue, 14 May 2024 09:21:15 -0700 Subject: [PATCH] Nullsafe views/scroll module (#44532) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44532 Changelog: [Internal] Fix nullsafe errors in the module and add the annotation Reviewed By: rshest Differential Revision: D57218666 fbshipit-source-id: 9fc8c6d002bb2c4b53c0874a6d8c38fcf52b9e19 --- .../scroll/ReactHorizontalScrollView.java | 25 ++++++++----------- .../ReactHorizontalScrollViewManager.java | 4 ++- .../react/views/scroll/ReactScrollView.java | 10 +++++--- .../scroll/ReactScrollViewCommandHelper.java | 16 ++++++------ .../views/scroll/ReactScrollViewManager.java | 4 ++- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java index f754b08f873..0c1ef425494 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollView.java @@ -32,6 +32,7 @@ import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; +import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.common.ReactConstants; import com.facebook.react.common.build.ReactBuildConfig; import com.facebook.react.modules.i18nmanager.I18nUtil; @@ -55,6 +56,7 @@ import java.util.ArrayList; import java.util.List; /** Similar to {@link ReactScrollView} but only supports horizontal scrolling. */ +@Nullsafe(Nullsafe.Mode.LOCAL) public class ReactHorizontalScrollView extends HorizontalScrollView implements ReactClippingViewGroup, ViewGroup.OnHierarchyChangeListener, @@ -109,7 +111,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView private boolean mPagedArrowScrolling = false; private int pendingContentOffsetX = UNSET_CONTENT_OFFSET; private int pendingContentOffsetY = UNSET_CONTENT_OFFSET; - private StateWrapper mStateWrapper = null; + private @Nullable StateWrapper mStateWrapper = null; private final ReactScrollViewScrollState mReactScrollViewScrollState; private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollX", 0, 0); private PointerEvents mPointerEvents = PointerEvents.AUTO; @@ -248,7 +250,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView mSnapInterval = snapInterval; } - public void setSnapOffsets(List snapOffsets) { + public void setSnapOffsets(@Nullable List snapOffsets) { mSnapOffsets = snapOffsets; } @@ -268,7 +270,7 @@ public class ReactHorizontalScrollView extends HorizontalScrollView awakenScrollBars(); } - public void setOverflow(String overflow) { + public void setOverflow(@Nullable String overflow) { mOverflow = overflow; invalidate(); } @@ -307,17 +309,10 @@ public class ReactHorizontalScrollView extends HorizontalScrollView if (DEBUG_MODE) { FLog.i(TAG, "onDraw[%d]", getId()); } - getDrawingRect(mRect); - - switch (mOverflow) { - case ViewProps.VISIBLE: - break; - default: - canvas.clipRect(mRect); - break; + if (!ViewProps.VISIBLE.equals(mOverflow)) { + canvas.clipRect(mRect); } - super.onDraw(canvas); } @@ -839,8 +834,10 @@ public class ReactHorizontalScrollView extends HorizontalScrollView } @Override - public void onChildViewRemoved(View parent, View child) { - mContentView.removeOnLayoutChangeListener(this); + public @Nullable void onChildViewRemoved(View parent, View child) { + if (mContentView != null) { + mContentView.removeOnLayoutChangeListener(this); + } mContentView = null; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java index 652039a27a2..579d5ab467b 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactHorizontalScrollViewManager.java @@ -11,6 +11,7 @@ import android.graphics.Color; import android.view.View; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; +import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.RetryableMountingLayerException; @@ -36,6 +37,7 @@ import java.util.List; *

Note that {@link ReactScrollView} and {@link ReactHorizontalScrollView} are exposed to JS as a * single ScrollView component, configured via the {@code horizontal} boolean property. */ +@Nullsafe(Nullsafe.Mode.LOCAL) @ReactModule(name = ReactHorizontalScrollViewManager.REACT_CLASS) public class ReactHorizontalScrollViewManager extends ViewGroupManager implements ReactScrollViewCommandHelper.ScrollCommandHandler { @@ -67,7 +69,7 @@ public class ReactHorizontalScrollViewManager extends ViewGroupManagerReactScrollView only supports vertical scrolling. For horizontal scrolling, use {@link * ReactHorizontalScrollView}. */ +@Nullsafe(Nullsafe.Mode.LOCAL) public class ReactScrollView extends ScrollView implements ReactClippingViewGroup, ViewGroup.OnHierarchyChangeListener, @@ -111,7 +113,7 @@ public class ReactScrollView extends ScrollView private @Nullable ReadableMap mCurrentContentOffset = null; private int pendingContentOffsetX = UNSET_CONTENT_OFFSET; private int pendingContentOffsetY = UNSET_CONTENT_OFFSET; - private StateWrapper mStateWrapper = null; + private @Nullable StateWrapper mStateWrapper = null; private final ReactScrollViewScrollState mReactScrollViewScrollState = new ReactScrollViewScrollState(ViewCompat.LAYOUT_DIRECTION_LTR); private final ValueAnimator DEFAULT_FLING_ANIMATOR = ObjectAnimator.ofInt(this, "scrollY", 0, 0); @@ -237,7 +239,7 @@ public class ReactScrollView extends ScrollView mSnapInterval = snapInterval; } - public void setSnapOffsets(List snapOffsets) { + public void setSnapOffsets(@Nullable List snapOffsets) { mSnapOffsets = snapOffsets; } @@ -257,7 +259,7 @@ public class ReactScrollView extends ScrollView awakenScrollBars(); } - public void setOverflow(String overflow) { + public void setOverflow(@Nullable String overflow) { mOverflow = overflow; invalidate(); } @@ -615,7 +617,7 @@ public class ReactScrollView extends ScrollView } private int getMaxScrollY() { - int contentHeight = mContentView.getHeight(); + int contentHeight = mContentView == null ? 0 : mContentView.getHeight(); int viewportHeight = getHeight() - getPaddingBottom() - getPaddingTop(); return Math.max(0, contentHeight - viewportHeight); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java index 8b6641b25ed..f2e67e66770 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewCommandHelper.java @@ -9,6 +9,7 @@ package com.facebook.react.views.scroll; import androidx.annotation.Nullable; import com.facebook.infer.annotation.Assertions; +import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.PixelUtil; @@ -18,6 +19,7 @@ import java.util.Map; * Helper for view managers to handle commands like 'scrollTo'. Shared by {@link * ReactScrollViewManager} and {@link ReactHorizontalScrollViewManager}. */ +@Nullsafe(Nullsafe.Mode.LOCAL) public class ReactScrollViewCommandHelper { public static final int COMMAND_SCROLL_TO = 1; @@ -70,16 +72,15 @@ public class ReactScrollViewCommandHelper { @Nullable ReadableArray args) { Assertions.assertNotNull(viewManager); Assertions.assertNotNull(scrollView); - Assertions.assertNotNull(args); switch (commandType) { case COMMAND_SCROLL_TO: { - scrollTo(viewManager, scrollView, args); + scrollTo(viewManager, scrollView, Assertions.assertNotNull(args)); return; } case COMMAND_SCROLL_TO_END: { - scrollToEnd(viewManager, scrollView, args); + scrollToEnd(viewManager, scrollView, Assertions.assertNotNull(args)); return; } case COMMAND_FLASH_SCROLL_INDICATORS: @@ -101,16 +102,15 @@ public class ReactScrollViewCommandHelper { @Nullable ReadableArray args) { Assertions.assertNotNull(viewManager); Assertions.assertNotNull(scrollView); - Assertions.assertNotNull(args); switch (commandType) { case "scrollTo": { - scrollTo(viewManager, scrollView, args); + scrollTo(viewManager, scrollView, Assertions.assertNotNull(args)); return; } case "scrollToEnd": { - scrollToEnd(viewManager, scrollView, args); + scrollToEnd(viewManager, scrollView, Assertions.assertNotNull(args)); return; } case "flashScrollIndicators": @@ -126,7 +126,7 @@ public class ReactScrollViewCommandHelper { } private static void scrollTo( - ScrollCommandHandler viewManager, T scrollView, @Nullable ReadableArray args) { + ScrollCommandHandler viewManager, T scrollView, ReadableArray args) { int destX = Math.round(PixelUtil.toPixelFromDIP(args.getDouble(0))); int destY = Math.round(PixelUtil.toPixelFromDIP(args.getDouble(1))); boolean animated = args.getBoolean(2); @@ -134,7 +134,7 @@ public class ReactScrollViewCommandHelper { } private static void scrollToEnd( - ScrollCommandHandler viewManager, T scrollView, @Nullable ReadableArray args) { + ScrollCommandHandler viewManager, T scrollView, ReadableArray args) { boolean animated = args.getBoolean(0); viewManager.scrollToEnd(scrollView, new ScrollToEndCommandData(animated)); } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index 0aec1b1a338..3413383cd5a 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -11,6 +11,7 @@ import android.graphics.Color; import android.view.View; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; +import com.facebook.infer.annotation.Nullsafe; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.RetryableMountingLayerException; @@ -39,6 +40,7 @@ import java.util.Map; *

Note that {@link ReactScrollView} and {@link ReactHorizontalScrollView} are exposed to JS as a * single ScrollView component, configured via the {@code horizontal} boolean property. */ +@Nullsafe(Nullsafe.Mode.LOCAL) @ReactModule(name = ReactScrollViewManager.REACT_CLASS) public class ReactScrollViewManager extends ViewGroupManager implements ReactScrollViewCommandHelper.ScrollCommandHandler { @@ -341,7 +343,7 @@ public class ReactScrollViewManager extends ViewGroupManager } @Override - public Object updateState( + public @Nullable Object updateState( ReactScrollView view, ReactStylesDiffMap props, StateWrapper stateWrapper) { view.setStateWrapper(stateWrapper); return null;