1 package expo.modules.devmenu.websockets
2 
3 import android.util.Log
4 import com.facebook.react.ReactInstanceManager
5 import com.facebook.react.bridge.UiThreadUtil
6 import com.facebook.react.modules.core.RCTNativeAppEventEmitter
7 import com.facebook.react.packagerconnection.NotificationOnlyHandler
8 import expo.interfaces.devmenu.DevMenuManagerInterface
9 import expo.modules.devmenu.devtools.DevMenuDevToolsDelegate
10 import org.json.JSONObject
11 import java.lang.ref.WeakReference
12 
13 class DevMenuCommandHandlersProvider(
14   private val manager: DevMenuManagerInterface,
15   reactInstanceManager: ReactInstanceManager
16 ) {
17   private val _instanceManager = WeakReference(reactInstanceManager)
18   private val instanceManager
19     get() = _instanceManager.get()
20 
21   private val onReload = object : NotificationOnlyHandler() {
onNotificationnull22     override fun onNotification(params: Any?) {
23       manager.closeMenu()
24       UiThreadUtil.runOnUiThread {
25         instanceManager?.devSupportManager?.handleReloadJS()
26       }
27     }
28   }
29 
30   private val onDevMenu = object : NotificationOnlyHandler() {
onNotificationnull31     override fun onNotification(params: Any?) {
32       val activity = instanceManager?.currentReactContext?.currentActivity ?: return
33       manager.toggleMenu(activity)
34     }
35   }
36 
37   private val onDevCommand = object : NotificationOnlyHandler() {
onNotificationnull38     override fun onNotification(params: Any?) {
39       val instanceManager = instanceManager ?: return
40       val devDelegate = DevMenuDevToolsDelegate(manager, instanceManager)
41 
42       if (params is JSONObject) {
43         val command = params.optString("name") ?: return
44 
45         when (command) {
46           "reload" -> devDelegate.reload()
47           "toggleDevMenu" -> {
48             val activity = instanceManager.currentReactContext?.currentActivity ?: return
49             manager.toggleMenu(activity)
50           }
51           "toggleRemoteDebugging" -> devDelegate.toggleRemoteDebugging()
52           "toggleElementInspector" -> devDelegate.toggleElementInspector()
53           "togglePerformanceMonitor" -> {
54             val activity = instanceManager.currentReactContext?.currentActivity ?: return
55             devDelegate.togglePerformanceMonitor(activity)
56           }
57           "openJSInspector" -> devDelegate.openJSInspector()
58           "reconnectReactDevTools" -> {
59             // Emit the `RCTDevMenuShown` for the app to reconnect react-devtools
60             // https://github.com/facebook/react-native/blob/22ba1e45c52edcc345552339c238c1f5ef6dfc65/Libraries/Core/setUpReactDevTools.js#L80
61             instanceManager.currentReactContext?.getJSModule(RCTNativeAppEventEmitter::class.java)?.emit("RCTDevMenuShown", null)
62           }
63           else -> Log.w("DevMenu", "Unknown command: $command")
64         }
65       }
66     }
67   }
68 
createCommandHandlersnull69   fun createCommandHandlers(): Map<String, NotificationOnlyHandler> {
70     return mapOf(
71       "reload" to onReload,
72       "devMenu" to onDevMenu,
73       "sendDevCommand" to onDevCommand
74     )
75   }
76 }
77