Skip to content

Commit 9497203

Browse files
kot331107facebook-github-bot
authored andcommitted
Android: fix ClassCastException in ReactRootView.java when software keyboard is shown (#40755)
Summary: Fixes #40754 Hi all! We noticed that our app started to crash after bumping to RN v0.71.13, anyways after a deeper investigation we also found that the crash occurs in the latest version as well. Crash log: ``` E FATAL EXCEPTION: main Process: com.nfl.fantasy.core.android.debug, PID: 6034 java.lang.ClassCastException: android.app.ContextImpl cannot be cast to android.app.Activity at com.facebook.react.ReactRootView$CustomGlobalLayoutListener.getActivity(ReactRootView.java:926) at com.facebook.react.ReactRootView$CustomGlobalLayoutListener.checkForKeyboardEvents(ReactRootView.java:946) at com.facebook.react.ReactRootView$CustomGlobalLayoutListener.onGlobalLayout(ReactRootView.java:912) at android.view.ViewTreeObserver.dispatchOnGlobalLayout(ViewTreeObserver.java:1061) ``` The code which causes ClassCastException is following [here](https://github.com/facebook/react-native/blob/ea88fbe229e1d276753ee8e118184274fc872138/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java#L864). In this code explicit type conversion to Activity is not safe because it's not guaranteed by the compiler that context will be compatible with Activity type. The appropriate issue [has been filed](#40754). ## Changelog: <!-- Help reviewers and the release process by writing your own changelog entry. Pick one each for the category and type tags: [ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message For more details, see: https://reactnative.dev/contributing/changelogs-in-pull-requests --> [ANDROID] [FIXED] - Fixed crash occurring in certain native views when keyboard events are fired. Pull Request resolved: #40755 Test Plan: Tested it manually with the [reference application](https://github.com/kot331107/rnCrashReproducer). Repro steps are as follows: - Build and run the app on Android - Tap the button "Open Modal" - You should see the red popup fragment to the bottom of the screen - Tap on the text input to open software keyboard - Expected: it should show the keyboard and no crash happens. Reviewed By: arushikesarwani94 Differential Revision: D50198424 Pulled By: NickGerleman fbshipit-source-id: a5a6d86334856f4ffbe818150da5793380da4702
1 parent b21cf6f commit 9497203

File tree

2 files changed

+23
-10
lines changed

2 files changed

+23
-10
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
1313
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;
1414

15-
import android.app.Activity;
1615
import android.content.Context;
17-
import android.content.ContextWrapper;
1816
import android.graphics.Canvas;
1917
import android.graphics.Insets;
2018
import android.graphics.Point;
@@ -856,12 +854,18 @@ public void onGlobalLayout() {
856854
checkForDeviceDimensionsChanges();
857855
}
858856

859-
private Activity getActivity() {
860-
Context context = getContext();
861-
while (!(context instanceof Activity) && context instanceof ContextWrapper) {
862-
context = ((ContextWrapper) context).getBaseContext();
857+
private @Nullable WindowManager.LayoutParams getWindowLayoutParams() {
858+
View view = ReactRootView.this;
859+
if (view.getLayoutParams() instanceof WindowManager.LayoutParams) {
860+
return (WindowManager.LayoutParams) view.getLayoutParams();
863861
}
864-
return (Activity) context;
862+
while (view.getParent() instanceof View) {
863+
view = (View) view.getParent();
864+
if (view.getLayoutParams() instanceof WindowManager.LayoutParams) {
865+
return (WindowManager.LayoutParams) view.getLayoutParams();
866+
}
867+
}
868+
return null;
865869
}
866870

867871
@RequiresApi(api = Build.VERSION_CODES.R)
@@ -881,7 +885,13 @@ private void checkForKeyboardEvents() {
881885
Insets barInsets = rootInsets.getInsets(WindowInsets.Type.systemBars());
882886
int height = imeInsets.bottom - barInsets.bottom;
883887

884-
int softInputMode = getActivity().getWindow().getAttributes().softInputMode;
888+
int softInputMode;
889+
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
890+
if (windowLayoutParams != null) {
891+
softInputMode = windowLayoutParams.softInputMode;
892+
} else {
893+
return;
894+
}
885895
int screenY =
886896
softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
887897
? mVisibleViewArea.bottom - height

packages/react-native/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import android.graphics.Insets
1313
import android.graphics.Rect
1414
import android.view.MotionEvent
1515
import android.view.WindowInsets
16+
import android.view.WindowManager
1617
import com.facebook.react.bridge.Arguments
1718
import com.facebook.react.bridge.CatalystInstance
1819
import com.facebook.react.bridge.JavaOnlyArray
@@ -211,9 +212,11 @@ class RootViewTest {
211212
.setVisible(WindowInsets.Type.ime(), true)
212213
.build()
213214
}
215+
val rootViewSpy = spy(rootView)
216+
whenever(rootViewSpy.getLayoutParams()).thenReturn(WindowManager.LayoutParams())
214217

215-
rootView.startReactApplication(instanceManager, "")
216-
rootView.simulateCheckForKeyboardForTesting()
218+
rootViewSpy.startReactApplication(instanceManager, "")
219+
rootViewSpy.simulateCheckForKeyboardForTesting()
217220

218221
val params = Arguments.createMap()
219222
val endCoordinates = Arguments.createMap()

0 commit comments

Comments
 (0)