Skip to content

Commit 55b3839

Browse files
cortinicofacebook-github-bot
authored andcommitted
Convert com.facebook.react.devsupport.RedBoxDialogSurfaceDelegate to Kotlin (#49091)
Summary: Pull Request resolved: #49091 Just another Kotlin migration for the devsupport package. Changelog: [Internal] [Changed] - Reviewed By: Abbondanzo Differential Revision: D68954219 fbshipit-source-id: 4d82a8965207916acec4fa3779627b9e93bb8b10
1 parent 95f9ca5 commit 55b3839

File tree

2 files changed

+159
-188
lines changed

2 files changed

+159
-188
lines changed

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

Lines changed: 0 additions & 188 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.devsupport
9+
10+
import android.app.Activity
11+
import android.app.Dialog
12+
import android.graphics.Color
13+
import android.graphics.drawable.ColorDrawable
14+
import android.os.Bundle
15+
import android.view.KeyEvent
16+
import android.view.View
17+
import android.view.Window
18+
import android.widget.FrameLayout
19+
import androidx.core.graphics.Insets
20+
import androidx.core.view.ViewCompat
21+
import androidx.core.view.WindowInsetsCompat
22+
import com.facebook.common.logging.FLog
23+
import com.facebook.react.R
24+
import com.facebook.react.bridge.LifecycleEventListener
25+
import com.facebook.react.bridge.ReactContext
26+
import com.facebook.react.common.ReactConstants
27+
import com.facebook.react.common.SurfaceDelegate
28+
import com.facebook.react.devsupport.interfaces.DevSupportManager
29+
30+
/**
31+
* The implementation of SurfaceDelegate with [Activity]. This is the default [SurfaceDelegate] for
32+
* Mobile.
33+
*/
34+
internal class RedBoxDialogSurfaceDelegate(private val devSupportManager: DevSupportManager) :
35+
SurfaceDelegate {
36+
private val doubleTapReloadRecognizer = DoubleTapReloadRecognizer()
37+
38+
private var dialog: Dialog? = null
39+
private var redBoxContentView: RedBoxContentView? = null
40+
41+
override fun createContentView(appKey: String) {
42+
// The content view is created in android instead of using react app. Hence the appKey is not
43+
// used here.
44+
val redBoxHandler = devSupportManager.redBoxHandler
45+
val context = devSupportManager.currentActivity
46+
if (context == null || context.isFinishing) {
47+
val message = devSupportManager.lastErrorTitle
48+
FLog.e(
49+
ReactConstants.TAG,
50+
"Unable to launch redbox because react activity is not available, here is the error that redbox would've displayed: ${(message ?: "N/A")}")
51+
return
52+
}
53+
54+
// Create a new RedBox when currentActivity get updated
55+
redBoxContentView =
56+
RedBoxContentView(context, devSupportManager, redBoxHandler).also { it.init() }
57+
}
58+
59+
override fun isContentViewReady(): Boolean = redBoxContentView != null
60+
61+
override fun destroyContentView() {
62+
redBoxContentView = null
63+
}
64+
65+
override fun show() {
66+
val message: String? = devSupportManager.lastErrorTitle
67+
val context: Activity? = devSupportManager.currentActivity
68+
if (context == null || context.isFinishing) {
69+
devSupportManager.currentReactContext?.let { reactContext ->
70+
/**
71+
* If the activity isn't available, try again after the next onHostResume(). onHostResume()
72+
* is when the activity gets attached to the react native.
73+
*/
74+
runAfterHostResume(reactContext) { this.show() }
75+
return
76+
}
77+
FLog.e(
78+
ReactConstants.TAG,
79+
"Unable to launch redbox because react activity and react context is not available, here is the error that redbox would've displayed: ${message ?: "N/A"}")
80+
return
81+
}
82+
83+
if (redBoxContentView?.context !== context) {
84+
// Create a new RedBox when currentActivity get updated
85+
createContentView("RedBox")
86+
}
87+
88+
redBoxContentView?.refreshContentView()
89+
if (dialog == null) {
90+
dialog =
91+
object : Dialog(context, R.style.Theme_Catalyst_RedBox) {
92+
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
93+
if (keyCode == KeyEvent.KEYCODE_MENU) {
94+
devSupportManager.showDevOptionsDialog()
95+
return true
96+
}
97+
if (doubleTapReloadRecognizer.didDoubleTapR(keyCode, currentFocus)) {
98+
devSupportManager.handleReloadJS()
99+
}
100+
return super.onKeyUp(keyCode, event)
101+
}
102+
103+
override fun onCreate(savedInstanceState: Bundle?) {
104+
// set background color so it will show below transparent system bars on forced
105+
// edge-to-edge
106+
checkNotNull(window).setBackgroundDrawable(ColorDrawable(Color.BLACK))
107+
// register insets listener to update margins on the ReactRootView to avoid
108+
// overlap w/ system bars
109+
val insetsType: Int =
110+
WindowInsetsCompat.Type.systemBars() or
111+
WindowInsetsCompat.Type.displayCutout()
112+
113+
ViewCompat.setOnApplyWindowInsetsListener(checkNotNull(redBoxContentView)) {
114+
view: View,
115+
windowInsetsCompat: WindowInsetsCompat ->
116+
val insets: Insets = windowInsetsCompat.getInsets(insetsType)
117+
val lp: FrameLayout.LayoutParams = view.layoutParams as FrameLayout.LayoutParams
118+
lp.setMargins(insets.left, insets.top, insets.right, insets.bottom)
119+
WindowInsetsCompat.CONSUMED
120+
}
121+
}
122+
}
123+
.apply {
124+
requestWindowFeature(Window.FEATURE_NO_TITLE)
125+
setContentView(checkNotNull(redBoxContentView))
126+
}
127+
}
128+
dialog?.show()
129+
}
130+
131+
override fun hide() {
132+
try {
133+
// dismiss redbox if exists
134+
dialog?.dismiss()
135+
} catch (e: IllegalArgumentException) {
136+
FLog.e(ReactConstants.TAG, "RedBoxDialogSurfaceDelegate: error while dismissing dialog: ", e)
137+
}
138+
destroyContentView()
139+
dialog = null
140+
}
141+
142+
override fun isShowing(): Boolean = dialog?.isShowing == true
143+
144+
companion object {
145+
private fun runAfterHostResume(reactContext: ReactContext, runnable: Runnable) {
146+
reactContext.addLifecycleEventListener(
147+
object : LifecycleEventListener {
148+
override fun onHostResume() {
149+
runnable.run()
150+
reactContext.removeLifecycleEventListener(this)
151+
}
152+
153+
override fun onHostPause() = Unit
154+
155+
override fun onHostDestroy() = Unit
156+
})
157+
}
158+
}
159+
}

0 commit comments

Comments
 (0)