Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ import chat.rocket.reactnative.storage.MMKVKeyManager;
import chat.rocket.reactnative.storage.SecureStoragePackage;
import chat.rocket.reactnative.notification.VideoConfTurboPackage
import chat.rocket.reactnative.notification.PushNotificationTurboPackage
import chat.rocket.reactnative.notification.CustomPushNotification
import chat.rocket.reactnative.scroll.InvertedScrollPackage
import android.app.Activity
import android.os.Bundle

/**
* Main Application class.
Expand All @@ -36,6 +39,34 @@ import chat.rocket.reactnative.scroll.InvertedScrollPackage
*/
open class MainApplication : Application(), ReactApplication {

// Track active activity count for immediate foreground/background detection
private var activeActivityCount = 0

// ActivityLifecycleCallbacks for immediate app state tracking
private val activityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
activeActivityCount++
if (activeActivityCount == 1) {
// App moved from background to foreground
CustomPushNotification.setAppInForeground(true)
}
}

override fun onActivityStopped(activity: Activity) {
activeActivityCount--
if (activeActivityCount == 0) {
// App moved from foreground to background
CustomPushNotification.setAppInForeground(false)
}
}

override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityResumed(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityDestroyed(activity: Activity) {}
}

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
Expand Down Expand Up @@ -68,6 +99,9 @@ open class MainApplication : Application(), ReactApplication {
// Must run before React Native starts to avoid race conditions
MMKVKeyManager.initialize(this)

// Register ActivityLifecycleCallbacks for immediate foreground/background detection
registerActivityLifecycleCallbacks(activityLifecycleCallbacks)

// Load the native entry point for the New Architecture
load()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class CustomPushNotification {
// Shared state
private static final Gson gson = new Gson();
private static final Map<String, List<Bundle>> notificationMessages = new ConcurrentHashMap<>();

// Track app foreground state
private static volatile boolean isAppInForeground = false;

// Constants
public static final String KEY_REPLY = "KEY_REPLY";
Expand All @@ -68,6 +71,23 @@ public CustomPushNotification(Context context, Bundle bundle) {
public static void clearMessages(int notId) {
notificationMessages.remove(Integer.toString(notId));
}

/**
* Sets the app foreground state. Should be called from MainActivity's lifecycle callbacks.
*/
public static void setAppInForeground(boolean inForeground) {
isAppInForeground = inForeground;
if (ENABLE_VERBOSE_LOGS) {
Log.d(TAG, "App foreground state changed to: " + (inForeground ? "FOREGROUND" : "BACKGROUND"));
}
}

/**
* Checks if the app is currently in the foreground.
*/
public static boolean isAppInForeground() {
return isAppInForeground;
}

public void onReceived() {
String notId = mBundle.getString("notId");
Expand Down Expand Up @@ -228,6 +248,14 @@ private void showNotification(Bundle bundle, Ejson ejson, String notId) {
if (ENABLE_VERBOSE_LOGS) {
Log.d(TAG, "[Before add to notificationMessages] notId=" + notId + ", bundle.message length=" + (bundle.getString("message") != null ? bundle.getString("message").length() : 0) + ", bundle.notificationLoaded=" + bundle.getBoolean("notificationLoaded", false));
}

// Don't show notification if app is in foreground
// In-app notifications are handled by the JavaScript layer
if (isAppInForeground()) {
Log.d(TAG, "App is in foreground, skipping native notification");
return;
}

notificationMessages.get(notId).add(bundle);
if (ENABLE_VERBOSE_LOGS) {
Log.d(TAG, "[After add] notificationMessages[" + notId + "].size=" + notificationMessages.get(notId).size());
Expand Down
Loading