Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ android {
versionName "4.68.0"
vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60" // See note below!
resValue "string", "rn_config_reader_custom_package", "chat.rocket.reactnative"
}

Expand Down Expand Up @@ -144,7 +143,6 @@ dependencies {
implementation jscFlavor
}

implementation project(':react-native-notifications')
implementation "com.google.firebase:firebase-messaging:23.3.1"
implementation project(':watermelondb-jsi')

Expand Down
17 changes: 17 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@
<data android:mimeType="*/*" />
</intent-filter>
</activity>
<!-- Custom Firebase Messaging Service for Rocket.Chat notifications -->
<service
android:name="chat.rocket.reactnative.notification.RCFirebaseMessagingService"
android:exported="false">
<intent-filter android:priority="100">
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver
android:name="chat.rocket.reactnative.notification.ReplyBroadcast"
android:enabled="true"
Expand All @@ -84,6 +92,15 @@
android:enabled="true"
android:exported="true" >
</receiver>
<receiver
android:name="chat.rocket.reactnative.notification.VideoConfBroadcast"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="chat.rocket.reactnative.ACTION_VIDEO_CONF_ACCEPT" />
<action android:name="chat.rocket.reactnative.ACTION_VIDEO_CONF_DECLINE" />
</intent-filter>
</receiver>
<meta-data
android:name="com.bugsnag.android.API_KEY"
android:value="${BugsnagAPIKey}" />
Expand Down
60 changes: 57 additions & 3 deletions android/app/src/main/java/chat/rocket/reactnative/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ import com.facebook.react.defaults.DefaultReactActivityDelegate

import android.os.Bundle
import com.zoontek.rnbootsplash.RNBootSplash
import android.content.Intent;
import android.content.res.Configuration;
import android.content.Intent
import android.content.res.Configuration
import chat.rocket.reactnative.notification.VideoConfModule
import chat.rocket.reactnative.notification.VideoConfNotification
import com.google.gson.GsonBuilder

class MainActivity : ReactActivity() {

Expand All @@ -25,9 +28,60 @@ class MainActivity : ReactActivity() {
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)

override fun onCreate(savedInstanceState: Bundle?) {
override fun onCreate(savedInstanceState: Bundle?) {
RNBootSplash.init(this, R.style.BootTheme)
super.onCreate(null)

// Handle video conf action from notification
intent?.let { handleVideoConfIntent(it) }
}

public override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// Handle video conf action when activity is already running
handleVideoConfIntent(intent)
}

private fun handleVideoConfIntent(intent: Intent) {
if (intent.getBooleanExtra("videoConfAction", false)) {
val notificationId = intent.getIntExtra("notificationId", 0)
val event = intent.getStringExtra("event") ?: return
val rid = intent.getStringExtra("rid") ?: ""
val callerId = intent.getStringExtra("callerId") ?: ""
val callerName = intent.getStringExtra("callerName") ?: ""
val host = intent.getStringExtra("host") ?: ""
val callId = intent.getStringExtra("callId") ?: ""

android.util.Log.d("RocketChat.MainActivity", "Handling video conf intent - event: $event, rid: $rid, host: $host, callId: $callId")

// Cancel the notification
if (notificationId != 0) {
VideoConfNotification.cancelById(this, notificationId)
}

// Store action for JS to pick up - include all required fields
val data = mapOf(
"notificationType" to "videoconf",
"rid" to rid,
"event" to event,
"host" to host,
"callId" to callId,
"caller" to mapOf(
"_id" to callerId,
"name" to callerName
)
)

val gson = GsonBuilder().create()
val jsonData = gson.toJson(data)

android.util.Log.d("RocketChat.MainActivity", "Storing video conf action: $jsonData")

VideoConfModule.storePendingAction(this, jsonData)

// Clear the video conf flag to prevent re-processing
intent.removeExtra("videoConfAction")
}
}

override fun invokeDefaultOnBackPressed() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package chat.rocket.reactnative

import android.app.Application
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
Expand All @@ -18,24 +16,33 @@ import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage;
import com.wix.reactnativenotifications.core.AppLaunchHelper
import com.wix.reactnativenotifications.core.AppLifecycleFacade
import com.wix.reactnativenotifications.core.JsIOHelper
import com.wix.reactnativenotifications.core.notification.INotificationsApplication
import com.wix.reactnativenotifications.core.notification.IPushNotification
import com.bugsnag.android.Bugsnag
import expo.modules.ApplicationLifecycleDispatcher
import chat.rocket.reactnative.networking.SSLPinningTurboPackage;
import chat.rocket.reactnative.notification.CustomPushNotification;
import chat.rocket.reactnative.notification.VideoConfTurboPackage

open class MainApplication : Application(), ReactApplication, INotificationsApplication {
/**
* Main Application class.
*
* NOTIFICATION ARCHITECTURE:
* - JS layer uses expo-notifications for token registration and event handling
* - Native layer uses RCFirebaseMessagingService + CustomPushNotification for:
* - FCM message handling
* - Notification display with MessagingStyle
* - E2E encrypted message decryption
* - Direct reply functionality
* - Message-id-only notification loading
*/
open class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(SSLPinningTurboPackage())
add(WatermelonDBJSIPackage())
add(VideoConfTurboPackage())
}

override fun getJSMainModuleName(): String = "index"
Expand Down Expand Up @@ -71,19 +78,4 @@ open class MainApplication : Application(), ReactApplication, INotificationsAppl
super.onConfigurationChanged(newConfig)
ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig)
}

override fun getPushNotification(
context: Context,
bundle: Bundle,
defaultFacade: AppLifecycleFacade,
defaultAppLaunchHelper: AppLaunchHelper
): IPushNotification {
return CustomPushNotification(
context,
bundle,
defaultFacade,
defaultAppLaunchHelper,
JsIOHelper()
)
}
}
Loading