rns-nativecall 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ package com.rnsnativecall
2
+
3
+ import android.content.Intent
4
+ import com.facebook.react.HeadlessJsTaskService
5
+ import com.facebook.react.bridge.Arguments
6
+ import com.facebook.react.jstasks.HeadlessJsTaskConfig
7
+
8
+ class CallHeadlessTask : HeadlessJsTaskService() {
9
+ override fun getTaskConfig(intent: Intent): HeadlessJsTaskConfig? {
10
+ val extras = intent.extras
11
+ return if (extras != null) {
12
+ HeadlessJsTaskConfig(
13
+ "ColdStartCallTask", // This name must match JS registration
14
+ Arguments.fromBundle(extras),
15
+ 5000, // Timeout for the task
16
+ true // Allowed in foreground
17
+ )
18
+ } else {
19
+ null
20
+ }
21
+ }
22
+ }
@@ -2,38 +2,62 @@ package com.rnsnativecall
2
2
 
3
3
  import android.app.ActivityManager
4
4
  import android.content.Context
5
+ import android.content.Intent
6
+ import android.os.Bundle
5
7
  import android.os.Handler
6
8
  import android.os.Looper
7
9
  import com.google.firebase.messaging.FirebaseMessagingService
8
10
  import com.google.firebase.messaging.RemoteMessage
11
+ import com.facebook.react.HeadlessJsTaskService
9
12
 
10
13
  class CallMessagingService : FirebaseMessagingService() {
11
14
 
12
15
  override fun onMessageReceived(remoteMessage: RemoteMessage) {
13
16
  val data = remoteMessage.data
17
+ val context = applicationContext
14
18
 
15
- if (isAppInForeground(applicationContext)) {
16
- // 1. App is OPEN: Send to JS immediately (No delay)
19
+ if (isAppInForeground(context)) {
20
+ // App is visible: Send event to active JS bridge
17
21
  CallModule.sendEventToJS("onCallReceived", data)
18
22
  } else {
19
- // 2. App is CLOSED/BACKGROUND: Delay the system pill by 18 seconds
23
+ // App is killed/background: Start the Headless JS Task
24
+ // This wakes up the JS engine and connects your WebSocket
25
+ startHeadlessTask(context, data)
26
+
27
+ // Start the 18-second "System Pill" backup timer
20
28
  val handler = Handler(Looper.getMainLooper())
21
29
  handler.postDelayed({
22
- // Re-check: If the user opened the app during these 18 seconds,
23
- // we might want to cancel the pill.
24
- if (!isAppInForeground(applicationContext)) {
25
- NativeCallManager.handleIncomingPush(applicationContext, data)
30
+ // Final safety check: if the user hasn't brought the app to foreground,
31
+ // show the native full-screen notification (The Pill)
32
+ if (!isAppInForeground(context)) {
33
+ NativeCallManager.handleIncomingPush(context, data)
26
34
  }
27
35
  }, 18000)
28
36
  }
29
37
  }
30
38
 
39
+ private fun startHeadlessTask(context: Context, data: Map<String, String>) {
40
+ val serviceIntent = Intent(context, CallHeadlessTask::class.java)
41
+ val bundle = Bundle()
42
+
43
+ // Pass all FCM data to the JS task
44
+ data.forEach { (key, value) -> bundle.putString(key, value) }
45
+ serviceIntent.putExtras(bundle)
46
+
47
+ // Start the service. This triggers the 'ColdStartCallTask' in index.js
48
+ context.startService(serviceIntent)
49
+ HeadlessJsTaskService.acquireWakeLockNow(context)
50
+ }
51
+
31
52
  private fun isAppInForeground(context: Context): Boolean {
32
53
  val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
33
54
  val appProcesses = activityManager.runningAppProcesses ?: return false
34
55
  val packageName = context.packageName
35
56
 
36
57
  for (appProcess in appProcesses) {
58
+ // IMPORTANCE_FOREGROUND only triggers if a real Activity is on screen.
59
+ // Running a Headless Task counts as IMPORTANCE_VISIBLE or lower,
60
+ // so this check remains accurate.
37
61
  if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
38
62
  appProcess.processName == packageName) {
39
63
  return true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "RNS nativecall component with native Android/iOS for handling native call ui, when app is not open or open.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -50,37 +50,29 @@ function withAndroidConfig(config) {
50
50
  }
51
51
  });
52
52
 
53
- // 2. Activity Cleanup & Setup
53
+ // 2. Activity Setup
54
54
  application.activity = application.activity || [];
55
55
 
56
- // Remove old/redundant activities
57
- application.activity = application.activity.filter(a =>
58
- a.$['android:name'] !== 'com.rnsnativecall.IncomingCallActivity' &&
59
- a.$['android:name'] !== 'com.rnsnativecall.AcceptCallActivity'
60
- );
61
-
62
- // Add the specific AcceptCallActivity (Trampoline)
63
- application.activity.push({
64
- $: {
65
- 'android:name': 'com.rnsnativecall.AcceptCallActivity',
66
- 'android:theme': '@android:style/Theme.Translucent.NoTitleBar',
67
- 'android:excludeFromRecents': 'true',
68
- 'android:noHistory': 'true',
69
- 'android:exported': 'false',
70
- 'android:launchMode': 'singleInstance',
71
- 'android:showWhenLocked': 'true',
72
- 'android:turnScreenOn': 'true'
73
- }
74
- });
56
+ // Add AcceptCallActivity (The Trampoline)
57
+ if (!application.activity.some(a => a.$['android:name'] === 'com.rnsnativecall.AcceptCallActivity')) {
58
+ application.activity.push({
59
+ $: {
60
+ 'android:name': 'com.rnsnativecall.AcceptCallActivity',
61
+ 'android:theme': '@android:style/Theme.Translucent.NoTitleBar',
62
+ 'android:excludeFromRecents': 'true',
63
+ 'android:noHistory': 'true',
64
+ 'android:exported': 'false',
65
+ 'android:launchMode': 'singleInstance',
66
+ 'android:showWhenLocked': 'true',
67
+ 'android:turnScreenOn': 'true'
68
+ }
69
+ });
70
+ }
75
71
 
76
- // 3. Service Cleanup & Setup (Firebase only)
72
+ // 3. Service Setup (Firebase + Headless Task)
77
73
  application.service = application.service || [];
78
74
 
79
- // Explicitly remove Telecom Service
80
- application.service = application.service.filter(
81
- s => s.$['android:name'] !== 'com.rnsnativecall.MyConnectionService'
82
- );
83
-
75
+ // Add Firebase Messaging Service
84
76
  const firebaseServiceName = 'com.rnsnativecall.CallMessagingService';
85
77
  if (!application.service.some(s => s.$['android:name'] === firebaseServiceName)) {
86
78
  application.service.push({
@@ -92,6 +84,17 @@ function withAndroidConfig(config) {
92
84
  });
93
85
  }
94
86
 
87
+ // Add Headless JS Task Service
88
+ const headlessServiceName = 'com.rnsnativecall.CallHeadlessTask';
89
+ if (!application.service.some(s => s.$['android:name'] === headlessServiceName)) {
90
+ application.service.push({
91
+ $: {
92
+ 'android:name': headlessServiceName,
93
+ 'android:exported': 'false'
94
+ }
95
+ });
96
+ }
97
+
95
98
  // 4. Receiver Setup
96
99
  application.receiver = application.receiver || [];
97
100
  const receiverName = 'com.rnsnativecall.CallActionReceiver';