Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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.VideoConfPackage;

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(VideoConfPackage())
}

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
Loading