diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt index 06ee1e4f503..f76c676af87 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManagerBinding.kt @@ -57,6 +57,8 @@ internal class FabricUIManagerBinding : HybridClassBase() { external fun findNextFocusableElement(parentTag: Int, focusedTag: Int, direction: Int): Int + external fun findRelativeTopMostParent(rootTag: Int, childTag: Int): Int + external fun stopSurface(surfaceId: Int) external fun stopSurfaceWithSurfaceHandler(surfaceHandler: SurfaceHandlerBinding) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp index a128dac13bd..50f20e19aa3 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp @@ -253,6 +253,40 @@ jint FabricUIManagerBinding::findNextFocusableElement( return nextNode->getTag(); } +jint FabricUIManagerBinding::findRelativeTopMostParent( + jint rootTag, + jint childTag) { + std::shared_ptr uimanager = getScheduler()->getUIManager(); + + ShadowNode::Shared childShadowNode = + uimanager->findShadowNodeByTag_DEPRECATED(childTag); + ShadowNode::Shared rootShadowNode = + uimanager->findShadowNodeByTag_DEPRECATED(rootTag); + + if (childShadowNode == nullptr || rootShadowNode == nullptr) { + return -1; + } + + ShadowNode::AncestorList ancestorList = + childShadowNode->getFamily().getAncestors(*rootShadowNode); + + if (ancestorList.empty() || ancestorList.size() < 2) { + return -1; + } + + // ignore the first ancestor as it is the rootShadowNode itself + for (auto it = std::next(ancestorList.begin()); it != ancestorList.end(); + ++it) { + auto& ancestor = *it; + if (ancestor.first.get().getTraits().check( + ShadowNodeTraits::Trait::FormsStackingContext)) { + return ancestor.first.get().getTag(); + } + } + + return -1; +} + // Used by non-bridgeless+Fabric void FabricUIManagerBinding::startSurfaceWithConstraints( jint surfaceId, @@ -728,6 +762,9 @@ void FabricUIManagerBinding::registerNatives() { makeNativeMethod( "findNextFocusableElement", FabricUIManagerBinding::findNextFocusableElement), + makeNativeMethod( + "findRelativeTopMostParent", + FabricUIManagerBinding::findRelativeTopMostParent), }); } diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h index fd298701562..e045425269d 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h +++ b/packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h @@ -135,6 +135,8 @@ class FabricUIManagerBinding : public jni::HybridClass, jint findNextFocusableElement(jint parentTag, jint focusedTag, jint direction); + jint findRelativeTopMostParent(jint rootTag, jint childTag); + void uninstallFabricUIManager(); // Private member variables