Allow Modal to handle hardware escape key in the same way the back button is handled (#31564)

Summary:
On Android, when a hardware keyboard is connected pressing the escape key will partially dismiss an active `<Modal>` without calling the `onRequestClose` callback. The modal will disappear, but I beleive the underlying activity may still be present, blocking interaction with the main app below and leaving things in a partially broken state.

This code change allows the escape key to be handled in the same way as the hardware back button, calling the `onRequestClose` and allowing the developer to decide the behaviour.

This issue isn't present on iOS, so no change is required there.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Fixed] - Fix Modal being dismissed incorrectly when pressing escape on a hardware keyboard

Pull Request resolved: https://github.com/facebook/react-native/pull/31564

Test Plan: I've tested this manually locally, but unsure if it's possible to test in an automated way as the emulator didn't respond to a hardware escape key in the same way as a physical device.

Reviewed By: ShikaSD

Differential Revision: D28953718

Pulled By: lunaleaps

fbshipit-source-id: 5547bc5d894da0d3d9daf4515b1af9c2407815db
This commit is contained in:
Levi Buzolic
2021-08-13 19:26:20 -07:00
committed by Facebook GitHub Bot
parent ecd6927b9a
commit f51773ecde
@@ -293,14 +293,11 @@ public class ReactModalHostView extends ViewGroup
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
// We need to stop the BACK button from closing the dialog by default so we capture
// that
// event and instead inform JS so that it can make the decision as to whether or not
// to
// allow the back button to close the dialog. If it chooses to, it can just set
// visible
// to false on the Modal and the Modal will go away
if (keyCode == KeyEvent.KEYCODE_BACK) {
// We need to stop the BACK button and ESCAPE key from closing the dialog by default
// so we capture that event and instead inform JS so that it can make the decision as
// to whether or not to allow the back/escape key to close the dialog. If it chooses
// to, it can just set visible to false on the Modal and the Modal will go away
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
Assertions.assertNotNull(
mOnRequestCloseListener,
"setOnRequestCloseListener must be called by the manager");
@@ -308,9 +305,8 @@ public class ReactModalHostView extends ViewGroup
return true;
} else {
// We redirect the rest of the key events to the current activity, since the
// activity
// expects to receive those events and react to them, ie. in the case of the dev
// menu
// activity expects to receive those events and react to them, ie. in the case of
// the dev menu
Activity currentActivity = ((ReactContext) getContext()).getCurrentActivity();
if (currentActivity != null) {
return currentActivity.onKeyUp(keyCode, event);