diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index 8672bd2d639..ec8a13a8d75 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -2992,9 +2992,11 @@ public abstract interface class com/facebook/react/modules/appregistry/AppRegist public abstract fun unmountApplicationComponentAtRootTag (I)V } -public class com/facebook/react/modules/appstate/AppStateModule : com/facebook/fbreact/specs/NativeAppStateSpec, com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/bridge/WindowFocusChangeListener { +public final class com/facebook/react/modules/appstate/AppStateModule : com/facebook/fbreact/specs/NativeAppStateSpec, com/facebook/react/bridge/LifecycleEventListener, com/facebook/react/bridge/WindowFocusChangeListener { public static final field APP_STATE_ACTIVE Ljava/lang/String; public static final field APP_STATE_BACKGROUND Ljava/lang/String; + public static final field Companion Lcom/facebook/react/modules/appstate/AppStateModule$Companion; + public static final field NAME Ljava/lang/String; public fun (Lcom/facebook/react/bridge/ReactApplicationContext;)V public fun addListener (Ljava/lang/String;)V public fun getCurrentAppState (Lcom/facebook/react/bridge/Callback;Lcom/facebook/react/bridge/Callback;)V @@ -3007,6 +3009,9 @@ public class com/facebook/react/modules/appstate/AppStateModule : com/facebook/f public fun removeListeners (D)V } +public final class com/facebook/react/modules/appstate/AppStateModule$Companion { +} + public class com/facebook/react/modules/blob/BlobModule : com/facebook/fbreact/specs/NativeBlobModuleSpec { public fun (Lcom/facebook/react/bridge/ReactApplicationContext;)V public fun addNetworkingHandler ()V diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java deleted file mode 100644 index 393a21890ea..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.modules.appstate; - -import com.facebook.fbreact.specs.NativeAppStateSpec; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Callback; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.WindowFocusChangeListener; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.common.LifecycleState; -import com.facebook.react.module.annotations.ReactModule; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nullable; - -@ReactModule(name = NativeAppStateSpec.NAME) -public class AppStateModule extends NativeAppStateSpec - implements LifecycleEventListener, WindowFocusChangeListener { - - public static final String APP_STATE_ACTIVE = "active"; - public static final String APP_STATE_BACKGROUND = "background"; - - private static final String INITIAL_STATE = "initialAppState"; - - private String mAppState; - - public AppStateModule(ReactApplicationContext reactContext) { - super(reactContext); - reactContext.addLifecycleEventListener(this); - reactContext.addWindowFocusChangeListener(this); - mAppState = - (reactContext.getLifecycleState() == LifecycleState.RESUMED - ? APP_STATE_ACTIVE - : APP_STATE_BACKGROUND); - } - - @Override - public Map getTypedExportedConstants() { - HashMap constants = new HashMap<>(); - constants.put(INITIAL_STATE, mAppState); - return constants; - } - - @Override - public void getCurrentAppState(Callback success, Callback error) { - success.invoke(createAppStateEventMap()); - } - - @Override - public void onHostResume() { - mAppState = APP_STATE_ACTIVE; - sendAppStateChangeEvent(); - } - - @Override - public void onHostPause() { - mAppState = APP_STATE_BACKGROUND; - sendAppStateChangeEvent(); - } - - @Override - public void onHostDestroy() { - // do not set state to destroyed, do not send an event. By the current implementation, the - // catalyst instance is going to be immediately dropped, and all JS calls with it. - } - - @Override - public void onWindowFocusChange(boolean hasFocus) { - sendEvent("appStateFocusChange", hasFocus); - } - - private WritableMap createAppStateEventMap() { - WritableMap appState = Arguments.createMap(); - appState.putString("app_state", mAppState); - return appState; - } - - private void sendEvent(String eventName, @Nullable Object data) { - ReactApplicationContext reactApplicationContext = getReactApplicationContext(); - - if (reactApplicationContext == null) { - return; - } - // We don't gain anything interesting from logging here, and it's an extremely common - // race condition for an AppState event to be triggered as the Catalyst instance is being - // set up or torn down. So, just fail silently here. - if (!reactApplicationContext.hasActiveReactInstance()) { - return; - } - reactApplicationContext.emitDeviceEvent(eventName, data); - } - - private void sendAppStateChangeEvent() { - sendEvent("appStateDidChange", createAppStateEventMap()); - } - - @Override - public void addListener(String eventName) { - // iOS only - } - - @Override - public void removeListeners(double count) { - // iOS only - } - - @Override - public void invalidate() { - super.invalidate(); - - getReactApplicationContext().removeLifecycleEventListener(this); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.kt new file mode 100644 index 00000000000..86177fae852 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appstate/AppStateModule.kt @@ -0,0 +1,97 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.modules.appstate + +import com.facebook.fbreact.specs.NativeAppStateSpec +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.Callback +import com.facebook.react.bridge.LifecycleEventListener +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.WindowFocusChangeListener +import com.facebook.react.bridge.WritableMap +import com.facebook.react.common.LifecycleState +import com.facebook.react.module.annotations.ReactModule + +@ReactModule(name = NativeAppStateSpec.NAME) +public class AppStateModule(reactContext: ReactApplicationContext) : + NativeAppStateSpec(reactContext), LifecycleEventListener, WindowFocusChangeListener { + + private var appState: String + + init { + reactContext.addLifecycleEventListener(this) + reactContext.addWindowFocusChangeListener(this) + appState = + if (reactContext.lifecycleState === LifecycleState.RESUMED) APP_STATE_ACTIVE + else APP_STATE_BACKGROUND + } + + public override fun getTypedExportedConstants(): Map = + mapOf(INITIAL_STATE to appState) + + public override fun getCurrentAppState(success: Callback, error: Callback?) { + success.invoke(createAppStateEventMap()) + } + + public override fun onHostResume() { + appState = APP_STATE_ACTIVE + sendAppStateChangeEvent() + } + + public override fun onHostPause() { + appState = APP_STATE_BACKGROUND + sendAppStateChangeEvent() + } + + public override fun onHostDestroy() { + // do not set state to destroyed, do not send an event. By the current implementation, the + // catalyst instance is going to be immediately dropped, and all JS calls with it. + } + + public override fun onWindowFocusChange(hasFocus: Boolean) { + sendEvent("appStateFocusChange", hasFocus) + } + + private fun createAppStateEventMap(): WritableMap = + Arguments.createMap().apply { putString("app_state", appState) } + + private fun sendEvent(eventName: String, data: Any?) { + val reactApplicationContext = getReactApplicationContext() ?: return + // We don't gain anything interesting from logging here, and it's an extremely common + // race condition for an AppState event to be triggered as the Catalyst instance is being + // set up or torn down. So, just fail silently here. + if (!reactApplicationContext.hasActiveReactInstance()) { + return + } + reactApplicationContext.emitDeviceEvent(eventName, data) + } + + private fun sendAppStateChangeEvent() { + sendEvent("appStateDidChange", createAppStateEventMap()) + } + + public override fun addListener(eventName: String?) { + // iOS only + } + + public override fun removeListeners(count: Double) { + // iOS only + } + + public override fun invalidate() { + super.invalidate() + getReactApplicationContext().removeLifecycleEventListener(this) + } + + public companion object { + public const val NAME: String = NativeAppStateSpec.NAME + public const val APP_STATE_ACTIVE: String = "active" + public const val APP_STATE_BACKGROUND: String = "background" + private const val INITIAL_STATE: String = "initialAppState" + } +}