Skip to content

Commit 19ebd4c

Browse files
yungstersfacebook-github-bot
authored andcommitted
VirtualView: Prerender w/o Window Focus (#52240)
Summary: Pull Request resolved: #52240 Changes `VirtualView` to detect when its window is not in a focused window (e.g. scroll position or layout changes when it is blurred) and to instead dispatch an async `Prerender` event instead of a sync `Visible` event. This minimizes unnecessary main thread synchronous work that is needed for a view that is not important to the user experience. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D77261958 fbshipit-source-id: 32acef9bc938005a0d73c5166f1741aebadf23bb
1 parent a2a72e2 commit 19ebd4c

21 files changed

Lines changed: 172 additions & 35 deletions

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlags.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<dee97293bfeab942c9cd0ba8622a5f86>>
7+
* @generated SignedSource<<7d9248932099e75eb56ed8b7409b764e>>
88
*/
99

1010
/**
@@ -258,6 +258,12 @@ public object ReactNativeFeatureFlags {
258258
@JvmStatic
259259
public fun enableVirtualViewDebugFeatures(): Boolean = accessor.enableVirtualViewDebugFeatures()
260260

261+
/**
262+
* Enables window focus detection for prioritizing VirtualView events.
263+
*/
264+
@JvmStatic
265+
public fun enableVirtualViewWindowFocusDetection(): Boolean = accessor.enableVirtualViewWindowFocusDetection()
266+
261267
/**
262268
* Uses the default event priority instead of the discreet event priority by default when dispatching events from Fabric to React.
263269
*/

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxAccessor.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<c46464d2d10ac0c8a6b7869ae5b3cd2b>>
7+
* @generated SignedSource<<04fa992cf8fec2d89a49cc03bc3f7757>>
88
*/
99

1010
/**
@@ -58,6 +58,7 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
5858
private var enableViewRecyclingForTextCache: Boolean? = null
5959
private var enableViewRecyclingForViewCache: Boolean? = null
6060
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
61+
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
6162
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
6263
private var fuseboxEnabledReleaseCache: Boolean? = null
6364
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
@@ -415,6 +416,15 @@ internal class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAcces
415416
return cached
416417
}
417418

419+
override fun enableVirtualViewWindowFocusDetection(): Boolean {
420+
var cached = enableVirtualViewWindowFocusDetectionCache
421+
if (cached == null) {
422+
cached = ReactNativeFeatureFlagsCxxInterop.enableVirtualViewWindowFocusDetection()
423+
enableVirtualViewWindowFocusDetectionCache = cached
424+
}
425+
return cached
426+
}
427+
418428
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
419429
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
420430
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsCxxInterop.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<62c548a9bfbf777a40b1b9e9d52b1de2>>
7+
* @generated SignedSource<<89ffcb75b9b94600174ba8a704314a69>>
88
*/
99

1010
/**
@@ -104,6 +104,8 @@ public object ReactNativeFeatureFlagsCxxInterop {
104104

105105
@DoNotStrip @JvmStatic public external fun enableVirtualViewDebugFeatures(): Boolean
106106

107+
@DoNotStrip @JvmStatic public external fun enableVirtualViewWindowFocusDetection(): Boolean
108+
107109
@DoNotStrip @JvmStatic public external fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
108110

109111
@DoNotStrip @JvmStatic public external fun fuseboxEnabledRelease(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsDefaults.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<de8775978e15479830fb215c6f15b144>>
7+
* @generated SignedSource<<a6d35f8073773430d24779cd69f194f1>>
88
*/
99

1010
/**
@@ -99,6 +99,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi
9999

100100
override fun enableVirtualViewDebugFeatures(): Boolean = false
101101

102+
override fun enableVirtualViewWindowFocusDetection(): Boolean = false
103+
102104
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean = false
103105

104106
override fun fuseboxEnabledRelease(): Boolean = false

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsLocalAccessor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<220b0cff47d2eadddf8a36646852d619>>
7+
* @generated SignedSource<<466ed58fa72b8d114887bb0a4931aa18>>
88
*/
99

1010
/**
@@ -62,6 +62,7 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
6262
private var enableViewRecyclingForTextCache: Boolean? = null
6363
private var enableViewRecyclingForViewCache: Boolean? = null
6464
private var enableVirtualViewDebugFeaturesCache: Boolean? = null
65+
private var enableVirtualViewWindowFocusDetectionCache: Boolean? = null
6566
private var fixMappingOfEventPrioritiesBetweenFabricAndReactCache: Boolean? = null
6667
private var fuseboxEnabledReleaseCache: Boolean? = null
6768
private var fuseboxNetworkInspectionEnabledCache: Boolean? = null
@@ -457,6 +458,16 @@ internal class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcc
457458
return cached
458459
}
459460

461+
override fun enableVirtualViewWindowFocusDetection(): Boolean {
462+
var cached = enableVirtualViewWindowFocusDetectionCache
463+
if (cached == null) {
464+
cached = currentProvider.enableVirtualViewWindowFocusDetection()
465+
accessedFeatureFlags.add("enableVirtualViewWindowFocusDetection")
466+
enableVirtualViewWindowFocusDetectionCache = cached
467+
}
468+
return cached
469+
}
470+
460471
override fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean {
461472
var cached = fixMappingOfEventPrioritiesBetweenFabricAndReactCache
462473
if (cached == null) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/featureflags/ReactNativeFeatureFlagsProvider.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<d2ab95a5f7bf0dfc52428a90bee2fc10>>
7+
* @generated SignedSource<<caf71a49d116ff499ef11c5657323cdd>>
88
*/
99

1010
/**
@@ -99,6 +99,8 @@ public interface ReactNativeFeatureFlagsProvider {
9999

100100
@DoNotStrip public fun enableVirtualViewDebugFeatures(): Boolean
101101

102+
@DoNotStrip public fun enableVirtualViewWindowFocusDetection(): Boolean
103+
102104
@DoNotStrip public fun fixMappingOfEventPrioritiesBetweenFabricAndReact(): Boolean
103105

104106
@DoNotStrip public fun fuseboxEnabledRelease(): Boolean

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/virtualview/ReactVirtualView.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import android.graphics.Rect
1212
import android.view.View
1313
import android.view.ViewGroup
1414
import android.view.ViewParent
15+
import android.view.ViewTreeObserver
1516
import androidx.annotation.VisibleForTesting
1617
import com.facebook.common.logging.FLog
1718
import com.facebook.react.R
@@ -35,6 +36,12 @@ internal class ReactVirtualView(context: Context) :
3536
internal var modeChangeEmitter: ModeChangeEmitter? = null
3637
internal var prerenderRatio: Double = ReactNativeFeatureFlags.virtualViewPrerenderRatio()
3738
internal val debugLogEnabled: Boolean = ReactNativeFeatureFlags.enableVirtualViewDebugFeatures()
39+
internal val detectWindowFocus = ReactNativeFeatureFlags.enableVirtualViewWindowFocusDetection()
40+
41+
private val onWindowFocusChangeListener =
42+
ViewTreeObserver.OnWindowFocusChangeListener {
43+
dispatchOnModeChangeIfNeeded(checkRectChange = false)
44+
}
3845

3946
private var parentScrollView: View? = null
4047

@@ -79,13 +86,19 @@ internal class ReactVirtualView(context: Context) :
7986
ReactScrollViewHelper.addLayoutChangeListener(this)
8087
}
8188
debugLog("onAttachedToWindow")
89+
if (detectWindowFocus) {
90+
viewTreeObserver.addOnWindowFocusChangeListener(onWindowFocusChangeListener)
91+
}
8292
dispatchOnModeChangeIfNeeded(checkRectChange = false)
8393
}
8494

8595
override fun onDetachedFromWindow() {
8696
super.onDetachedFromWindow()
8797
ReactScrollViewHelper.removeScrollListener(this)
8898
ReactScrollViewHelper.removeLayoutChangeListener(this)
99+
if (detectWindowFocus) {
100+
viewTreeObserver.addOnWindowFocusChangeListener(onWindowFocusChangeListener)
101+
}
89102
cleanupLayoutListeners()
90103
}
91104

@@ -185,7 +198,15 @@ internal class ReactVirtualView(context: Context) :
185198

186199
val newMode: VirtualViewMode
187200
if (rectsOverlap(targetRect, thresholdRect)) {
188-
newMode = VirtualViewMode.Visible
201+
if (detectWindowFocus) {
202+
if (hasWindowFocus()) {
203+
newMode = VirtualViewMode.Visible
204+
} else {
205+
newMode = VirtualViewMode.Prerender
206+
}
207+
} else {
208+
newMode = VirtualViewMode.Visible
209+
}
189210
} else {
190211
var prerender = false
191212
if (prerenderRatio > 0.0) {

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<b8d441d64e8e04ebbfe611edb4a96b97>>
7+
* @generated SignedSource<<8f4c2b4cd9f25778e0809c1261aa4728>>
88
*/
99

1010
/**
@@ -267,6 +267,12 @@ class ReactNativeFeatureFlagsJavaProvider
267267
return method(javaProvider_);
268268
}
269269

270+
bool enableVirtualViewWindowFocusDetection() override {
271+
static const auto method =
272+
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("enableVirtualViewWindowFocusDetection");
273+
return method(javaProvider_);
274+
}
275+
270276
bool fixMappingOfEventPrioritiesBetweenFabricAndReact() override {
271277
static const auto method =
272278
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("fixMappingOfEventPrioritiesBetweenFabricAndReact");
@@ -545,6 +551,11 @@ bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewDebugFeatures(
545551
return ReactNativeFeatureFlags::enableVirtualViewDebugFeatures();
546552
}
547553

554+
bool JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection(
555+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
556+
return ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection();
557+
}
558+
548559
bool JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact(
549560
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
550561
return ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact();
@@ -760,6 +771,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
760771
makeNativeMethod(
761772
"enableVirtualViewDebugFeatures",
762773
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewDebugFeatures),
774+
makeNativeMethod(
775+
"enableVirtualViewWindowFocusDetection",
776+
JReactNativeFeatureFlagsCxxInterop::enableVirtualViewWindowFocusDetection),
763777
makeNativeMethod(
764778
"fixMappingOfEventPrioritiesBetweenFabricAndReact",
765779
JReactNativeFeatureFlagsCxxInterop::fixMappingOfEventPrioritiesBetweenFabricAndReact),

packages/react-native/ReactAndroid/src/main/jni/react/featureflags/JReactNativeFeatureFlagsCxxInterop.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<30859b9c649e432263ff53fa04890837>>
7+
* @generated SignedSource<<b9c0a8157499e2007c6afafe2f59d0ce>>
88
*/
99

1010
/**
@@ -144,6 +144,9 @@ class JReactNativeFeatureFlagsCxxInterop
144144
static bool enableVirtualViewDebugFeatures(
145145
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
146146

147+
static bool enableVirtualViewWindowFocusDetection(
148+
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
149+
147150
static bool fixMappingOfEventPrioritiesBetweenFabricAndReact(
148151
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);
149152

packages/react-native/ReactCommon/react/featureflags/ReactNativeFeatureFlags.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7-
* @generated SignedSource<<6b6a9adef957abb86845ab3720fd8968>>
7+
* @generated SignedSource<<74d7512ad4e33dd4ba58cdf1da104173>>
88
*/
99

1010
/**
@@ -178,6 +178,10 @@ bool ReactNativeFeatureFlags::enableVirtualViewDebugFeatures() {
178178
return getAccessor().enableVirtualViewDebugFeatures();
179179
}
180180

181+
bool ReactNativeFeatureFlags::enableVirtualViewWindowFocusDetection() {
182+
return getAccessor().enableVirtualViewWindowFocusDetection();
183+
}
184+
181185
bool ReactNativeFeatureFlags::fixMappingOfEventPrioritiesBetweenFabricAndReact() {
182186
return getAccessor().fixMappingOfEventPrioritiesBetweenFabricAndReact();
183187
}

0 commit comments

Comments
 (0)