Repository: expo/expo
File: packages/expo-updates/android/src/main/java/expo/modules/updates/errorrecovery/ErrorRecovery.kt (Kotlin)

Code before:
    unregisterContentAppearedListener()

    // wait 10s before unsetting error handlers; even though we won't try to relaunch if our
    // handlers are triggered after now, we still want to give the app a reasonable window of time
    // to start the WAIT_FOR_REMOTE_UPDATE task and check for a new update is there is one
    //
    // it's safe to use the handler thread for this since nothing else
    // touches this class's fields
    handler.postDelayed({ unregisterErrorHandler() }, 10000)
  }

  private val contentAppearedListener = MarkerListener { name, _, _ ->
    if (name == ReactMarkerConstants.CONTENT_APPEARED) {
      handleContentAppeared()
    }
  }

  private fun registerContentAppearedListener() {
    ReactMarker.addListener(contentAppearedListener)
  }

  private fun unregisterContentAppearedListener() {
    ReactMarker.removeListener(contentAppearedListener)
  }

  private fun registerErrorHandler(devSupportManager: DevSupportManager) {
    if (enableBridgelessArchitecture) {
      registerErrorHandlerImplBridgeless()
    } else {
      registerErrorHandlerImplBridge(devSupportManager)
    }
  }

  private fun registerErrorHandlerImplBridgeless() {
    shouldHandleReactInstanceException = true
  }

  private fun registerErrorHandlerImplBridge(devSupportManager: DevSupportManager) {
    if (devSupportManager !is ReleaseDevSupportManager) {
      logger.debug("Unexpected type of ReactInstanceManager.DevSupportManager. expo-updates error recovery will not behave properly.")
      return
    }

    val defaultJSExceptionHandler = JSExceptionHandler { e -> this@ErrorRecovery.handleException(e) }

    val devSupportManagerClass = devSupportManager.javaClass
    previousExceptionHandler = devSupportManagerClass.getDeclaredField("defaultJSExceptionHandler").let { field ->
      field.isAccessible = true
      val previousValue = field[devSupportManager]
      field[devSupportManager] = defaultJSExceptionHandler
      return@let previousValue as DefaultJSExceptionHandler

Review comment (suggestion):
[🏗️ **design**] After this change, `registerErrorHandlerImplBridge()` and `unregisterErrorHandlerImplBridge()` are no longer called from anywhere — they're dead code. They should be removed along with the fields they use (`weakDevSupportManager`, `previousExceptionHandler`) and the now-unused imports (`DefaultJSExceptionHandler`, `JSExceptionHandler`, `ReleaseDevSupportManager`, `WeakReference`).

Code after:

    // wait 10s before unsetting error handlers; even though we won't try to relaunch if our
    // handlers are triggered after now, we still want to give the app a reasonable window of time
    // to start the WAIT_FOR_REMOTE_UPDATE task and check for a new update is there is one
    //
    // it's safe to use the handler thread for this since nothing else
    // touches this class's fields
    handler.postDelayed({ unregisterErrorHandler() }, 10000)
  }

  private val contentAppearedListener = MarkerListener { name, _, _ ->
    if (name == ReactMarkerConstants.CONTENT_APPEARED) {
      handleContentAppeared()
    }
  }

  private fun registerContentAppearedListener() {
    ReactMarker.addListener(contentAppearedListener)
  }

  private fun unregisterContentAppearedListener() {
    ReactMarker.removeListener(contentAppearedListener)
  }

  private fun registerErrorHandler(devSupportManager: DevSupportManager) {
    registerErrorHandlerImplBridgeless()
  }

  private fun registerErrorHandlerImplBridgeless() {
    shouldHandleReactInstanceException = true
  }

  private fun registerErrorHandlerImplBridge(devSupportManager: DevSupportManager) {
    if (devSupportManager !is ReleaseDevSupportManager) {
      logger.debug("Unexpected type of ReactInstanceManager.DevSupportManager. expo-updates error recovery will not behave properly.")
      return
    }

    val defaultJSExceptionHandler = JSExceptionHandler { e -> this@ErrorRecovery.handleException(e) }

    val devSupportManagerClass = devSupportManager.javaClass
    previousExceptionHandler = devSupportManagerClass.getDeclaredField("defaultJSExceptionHandler").let { field ->
      field.isAccessible = true
      val previousValue = field[devSupportManager]
      field[devSupportManager] = defaultJSExceptionHandler
      return@let previousValue as DefaultJSExceptionHandler
    }
    weakDevSupportManager = WeakReference(devSupportManager)
  }

  private fun unregisterErrorHandler() {