Skip to content

Commit

Permalink
Android: fix ClassCastException in ReactRootView.java when software k…
Browse files Browse the repository at this point in the history
…eyboard is shown (facebook#40755)

Summary:
Fixes facebook#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](facebook#40754).

<!-- 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: facebook#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
  • Loading branch information
kot331107 authored and hurali97 committed Dec 19, 2023
1 parent 39d8caf commit 8a99845
Showing 1 changed file with 18 additions and 8 deletions.
26 changes: 18 additions & 8 deletions ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
import static com.facebook.react.uimanager.common.UIManagerType.FABRIC;
import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE;

import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Point;
Expand Down Expand Up @@ -917,12 +915,18 @@ public void onGlobalLayout() {
checkForDeviceDimensionsChanges();
}

private Activity getActivity() {
Context context = getContext();
while (!(context instanceof Activity) && context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
private @Nullable WindowManager.LayoutParams getWindowLayoutParams() {
View view = ReactRootView.this;
if (view.getLayoutParams() instanceof WindowManager.LayoutParams) {
return (WindowManager.LayoutParams) view.getLayoutParams();
}
return (Activity) context;
while (view.getParent() instanceof View) {
view = (View) view.getParent();
if (view.getLayoutParams() instanceof WindowManager.LayoutParams) {
return (WindowManager.LayoutParams) view.getLayoutParams();
}
}
return null;
}

@RequiresApi(api = Build.VERSION_CODES.R)
Expand All @@ -942,7 +946,13 @@ private void checkForKeyboardEvents() {
Insets barInsets = rootInsets.getInsets(WindowInsets.Type.systemBars());
int height = imeInsets.bottom - barInsets.bottom;

int softInputMode = getActivity().getWindow().getAttributes().softInputMode;
int softInputMode;
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
if (windowLayoutParams != null) {
softInputMode = windowLayoutParams.softInputMode;
} else {
return;
}
int screenY =
softInputMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
? mVisibleViewArea.bottom - height
Expand Down

0 comments on commit 8a99845

Please sign in to comment.