Skip to content

Commit 14cea6e

Browse files
alanleedevfacebook-github-bot
authored andcommitted
migrate deprecated KEYCODE_BACK in Modal (#51097)
Summary: Pull Request resolved: #51097 **Problem:** `Event.KEYCODE_BACK`has been deprecated with targetSdk 36, predictive back will be enforced and KEYCODE_BACK no longer triggered. We need to migrate to backward compatible `OnBackPressedCallback`. - https://developer.android.com/about/versions/16/behavior-changes-16#predictive-back. **Solution:** Use `OnBackPressedCallback` to handle BACK. Logic for ESC key handling still remains. To support the callback mechanism, we are using AndroidX ComponentDialog ([src](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:activity/activity/src/main/java/androidx/activity/ComponentDialog.kt)) which is a thin wrapper on the existing Dialog. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D74162844 fbshipit-source-id: ebd0e89c29999d3dd99431a4359c442e42d23911
1 parent bc876fb commit 14cea6e

File tree

1 file changed

+31
-17
lines changed

1 file changed

+31
-17
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/ReactModalHostView.kt

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import android.view.MotionEvent
2020
import android.view.View
2121
import android.view.ViewGroup
2222
import android.view.ViewStructure
23-
import android.view.Window
2423
import android.view.WindowManager
2524
import android.view.accessibility.AccessibilityEvent
2625
import android.view.accessibility.AccessibilityNodeInfo
2726
import android.widget.FrameLayout
27+
import androidx.activity.ComponentDialog
28+
import androidx.activity.OnBackPressedCallback
2829
import androidx.annotation.UiThread
2930
import androidx.core.view.WindowInsetsCompat
3031
import androidx.core.view.WindowInsetsControllerCompat
@@ -49,10 +50,10 @@ import com.facebook.react.uimanager.ThemedReactContext
4950
import com.facebook.react.uimanager.UIManagerModule
5051
import com.facebook.react.uimanager.events.EventDispatcher
5152
import com.facebook.react.views.common.ContextUtils
53+
import com.facebook.react.views.modal.ReactModalHostView.DialogRootViewGroup
5254
import com.facebook.react.views.view.ReactViewGroup
5355
import com.facebook.react.views.view.setStatusBarTranslucency
5456
import com.facebook.react.views.view.setSystemBarsTranslucency
55-
import java.util.Objects
5657

5758
/**
5859
* ReactModalHostView is a view that sits in the view hierarchy representing a Modal view.
@@ -71,7 +72,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
7172
ViewGroup(context), LifecycleEventListener {
7273

7374
@get:VisibleForTesting
74-
public var dialog: Dialog? = null
75+
public var dialog: ComponentDialog? = null
7576
private set
7677

7778
public var transparent: Boolean = false
@@ -260,17 +261,34 @@ public class ReactModalHostView(context: ThemedReactContext) :
260261
}
261262

262263
val currentActivity = getCurrentActivity()
263-
val newDialog = Dialog(currentActivity ?: context, theme)
264+
val newDialog = ComponentDialog(currentActivity ?: context, theme)
264265
dialog = newDialog
265-
Objects.requireNonNull<Window>(newDialog.window)
266-
.setFlags(
267-
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
268-
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
266+
val window = requireNotNull(newDialog.window)
267+
window.setFlags(
268+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
269+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
269270

270271
newDialog.setContentView(contentView)
271272
updateProperties()
272273

273274
newDialog.setOnShowListener(onShowListener)
275+
276+
val handleCloseAction: () -> Unit = {
277+
val listener =
278+
checkNotNull(onRequestCloseListener) {
279+
"onRequestClose callback must be set if back key is expected to close the modal"
280+
}
281+
listener.onRequestClose(newDialog)
282+
}
283+
284+
val backPressedCallback: OnBackPressedCallback =
285+
object : OnBackPressedCallback(true) {
286+
override fun handleOnBackPressed() {
287+
handleCloseAction()
288+
}
289+
}
290+
291+
newDialog.onBackPressedDispatcher.addCallback(newDialog, backPressedCallback)
274292
newDialog.setOnKeyListener(
275293
object : DialogInterface.OnKeyListener {
276294
override fun onKey(dialog: DialogInterface, keyCode: Int, event: KeyEvent): Boolean {
@@ -280,11 +298,7 @@ public class ReactModalHostView(context: ThemedReactContext) :
280298
// to whether or not to allow the back/escape key to close the dialog. If it chooses
281299
// to, it can just set visible to false on the Modal and the Modal will go away
282300
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
283-
val listener =
284-
checkNotNull(onRequestCloseListener) {
285-
"onRequestClose callback must be set if back key is expected to close the modal"
286-
}
287-
listener.onRequestClose(dialog)
301+
handleCloseAction()
288302
return true
289303
} else {
290304
// We redirect the rest of the key events to the current activity, since the
@@ -301,19 +315,19 @@ public class ReactModalHostView(context: ThemedReactContext) :
301315
}
302316
})
303317

304-
newDialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
318+
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
305319
if (hardwareAccelerated) {
306-
newDialog.window?.addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
320+
window.addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
307321
}
308322
val flagSecureSet = isFlagSecureSet(currentActivity)
309323
if (flagSecureSet) {
310-
newDialog.window?.setFlags(
324+
window.setFlags(
311325
WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
312326
}
313327
if (currentActivity?.isFinishing == false) {
314328
newDialog.show()
315329
updateSystemAppearance()
316-
newDialog.window?.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
330+
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
317331
}
318332
}
319333

0 commit comments

Comments
 (0)