rns-nativecall 0.3.4 → 0.3.6
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.
|
@@ -6,14 +6,15 @@ import com.facebook.react.bridge.Arguments
|
|
|
6
6
|
import com.facebook.react.jstasks.HeadlessJsTaskConfig
|
|
7
7
|
|
|
8
8
|
class CallHeadlessTask : HeadlessJsTaskService() {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Note: The '?' after Intent and the return type are specific in Kotlin
|
|
10
|
+
override fun getTaskConfig(intent: Intent?): HeadlessJsTaskConfig? {
|
|
11
|
+
val extras = intent?.extras
|
|
11
12
|
return if (extras != null) {
|
|
12
13
|
HeadlessJsTaskConfig(
|
|
13
|
-
"ColdStartCallTask",
|
|
14
|
+
"ColdStartCallTask",
|
|
14
15
|
Arguments.fromBundle(extras),
|
|
15
|
-
|
|
16
|
-
true
|
|
16
|
+
30000,
|
|
17
|
+
true
|
|
17
18
|
)
|
|
18
19
|
} else {
|
|
19
20
|
null
|
|
@@ -6,47 +6,87 @@ import android.content.Intent
|
|
|
6
6
|
import android.os.Bundle
|
|
7
7
|
import android.os.Handler
|
|
8
8
|
import android.os.Looper
|
|
9
|
+
import android.app.NotificationManager
|
|
10
|
+
import androidx.core.app.NotificationCompat
|
|
9
11
|
import com.google.firebase.messaging.FirebaseMessagingService
|
|
10
12
|
import com.google.firebase.messaging.RemoteMessage
|
|
11
13
|
import com.facebook.react.HeadlessJsTaskService
|
|
12
14
|
|
|
13
15
|
class CallMessagingService : FirebaseMessagingService() {
|
|
14
16
|
|
|
17
|
+
companion object {
|
|
18
|
+
private val handler = Handler(Looper.getMainLooper())
|
|
19
|
+
private val pendingNotifications = mutableMapOf<String, Runnable>()
|
|
20
|
+
// This is the standard ID used for the incoming call notification pill
|
|
21
|
+
private const val CALL_NOTIFICATION_ID = 123
|
|
22
|
+
}
|
|
23
|
+
|
|
15
24
|
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
|
16
25
|
val data = remoteMessage.data
|
|
17
26
|
val context = applicationContext
|
|
18
27
|
|
|
28
|
+
val uuid = data["callUuid"] ?: return
|
|
29
|
+
val type = data["type"] ?: ""
|
|
30
|
+
|
|
31
|
+
if (type == "CANCEL") {
|
|
32
|
+
pendingNotifications[uuid]?.let {
|
|
33
|
+
handler.removeCallbacks(it)
|
|
34
|
+
pendingNotifications.remove(uuid)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 1. Stop the ringtone
|
|
38
|
+
NativeCallManager.stopRingtone()
|
|
39
|
+
|
|
40
|
+
// 2. DISMISS THE PILL (Direct Native Way)
|
|
41
|
+
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
42
|
+
notificationManager.cancel(CALL_NOTIFICATION_ID)
|
|
43
|
+
|
|
44
|
+
// 3. Show Missed Call
|
|
45
|
+
showMissedCallNotification(context, data, uuid)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
19
49
|
if (isAppInForeground(context)) {
|
|
20
|
-
// App is visible: Send event to active JS bridge
|
|
21
50
|
CallModule.sendEventToJS("onCallReceived", data)
|
|
22
51
|
} else {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
// show the native full-screen notification (The Pill)
|
|
52
|
+
val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
|
|
53
|
+
launchIntent?.apply {
|
|
54
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
55
|
+
putExtra("background_wake", true)
|
|
56
|
+
}
|
|
57
|
+
context.startActivity(launchIntent)
|
|
58
|
+
|
|
59
|
+
val showNotificationRunnable = Runnable {
|
|
32
60
|
if (!isAppInForeground(context)) {
|
|
33
61
|
NativeCallManager.handleIncomingPush(context, data)
|
|
34
62
|
}
|
|
35
|
-
|
|
63
|
+
pendingNotifications.remove(uuid)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pendingNotifications[uuid] = showNotificationRunnable
|
|
67
|
+
handler.postDelayed(showNotificationRunnable, 18000)
|
|
36
68
|
}
|
|
37
69
|
}
|
|
38
70
|
|
|
39
|
-
private fun
|
|
40
|
-
val
|
|
41
|
-
val
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
71
|
+
private fun showMissedCallNotification(context: Context, data: Map<String, String>, uuid: String) {
|
|
72
|
+
val name = data["name"] ?: "Unknown"
|
|
73
|
+
val callType = data["callType"] ?: "video"
|
|
74
|
+
val channelId = "missed_calls"
|
|
75
|
+
|
|
76
|
+
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
|
77
|
+
|
|
78
|
+
var iconResId = context.resources.getIdentifier("ic_missed_call", "drawable", context.packageName)
|
|
79
|
+
if (iconResId == 0) iconResId = android.R.drawable.sym_call_missed
|
|
80
|
+
|
|
81
|
+
val builder = NotificationCompat.Builder(context, channelId)
|
|
82
|
+
.setSmallIcon(iconResId)
|
|
83
|
+
.setContentTitle("Missed $callType call")
|
|
84
|
+
.setContentText("You missed a call from $name")
|
|
85
|
+
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
86
|
+
.setAutoCancel(true)
|
|
87
|
+
.setCategory(NotificationCompat.CATEGORY_MISSED_CALL)
|
|
88
|
+
|
|
89
|
+
notificationManager.notify(uuid.hashCode(), builder.build())
|
|
50
90
|
}
|
|
51
91
|
|
|
52
92
|
private fun isAppInForeground(context: Context): Boolean {
|
|
@@ -55,9 +95,6 @@ class CallMessagingService : FirebaseMessagingService() {
|
|
|
55
95
|
val packageName = context.packageName
|
|
56
96
|
|
|
57
97
|
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.
|
|
61
98
|
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
|
|
62
99
|
appProcess.processName == packageName) {
|
|
63
100
|
return true
|
|
@@ -28,7 +28,6 @@ object NativeCallManager {
|
|
|
28
28
|
} else {
|
|
29
29
|
PendingIntent.FLAG_UPDATE_CURRENT
|
|
30
30
|
}
|
|
31
|
-
|
|
32
31
|
// 1. IMPROVED INTENT: Direct to AcceptCallActivity
|
|
33
32
|
// This is better than a dummy intent because it allows the OS to
|
|
34
33
|
// launch your "Accept" logic immediately if the phone is locked.
|
package/package.json
CHANGED
package/withNativeCallVoip.js
CHANGED
|
@@ -5,10 +5,15 @@ function withMainActivityDataFix(config) {
|
|
|
5
5
|
return withMainActivity(config, (config) => {
|
|
6
6
|
let contents = config.modResults.contents;
|
|
7
7
|
|
|
8
|
+
// 1. Ensure necessary Imports are present
|
|
8
9
|
if (!contents.includes('import android.content.Intent')) {
|
|
9
10
|
contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.content.Intent`);
|
|
10
11
|
}
|
|
12
|
+
if (!contents.includes('import android.os.Bundle')) {
|
|
13
|
+
contents = contents.replace(/package .*/, (match) => `${match}\n\nimport android.os.Bundle`);
|
|
14
|
+
}
|
|
11
15
|
|
|
16
|
+
// 2. Define the code blocks
|
|
12
17
|
const onNewIntentCode = `
|
|
13
18
|
override fun onNewIntent(intent: Intent) {
|
|
14
19
|
super.onNewIntent(intent)
|
|
@@ -16,11 +21,28 @@ function withMainActivityDataFix(config) {
|
|
|
16
21
|
}
|
|
17
22
|
`;
|
|
18
23
|
|
|
24
|
+
const onCreateCode = `
|
|
25
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
26
|
+
super.onCreate(savedInstanceState)
|
|
27
|
+
// If woken up silently, move to back to prevent UI flicker
|
|
28
|
+
if (intent.getBooleanExtra("background_wake", false)) {
|
|
29
|
+
moveTaskToBack(true)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
// 3. Insert the codes before the last closing brace of the class
|
|
19
35
|
if (!contents.includes('override fun onNewIntent')) {
|
|
20
36
|
const lastBraceIndex = contents.lastIndexOf('}');
|
|
21
37
|
contents = contents.slice(0, lastBraceIndex) + onNewIntentCode + contents.slice(lastBraceIndex);
|
|
22
38
|
}
|
|
23
39
|
|
|
40
|
+
if (!contents.includes('override fun onCreate')) {
|
|
41
|
+
// Re-calculate lastBraceIndex because contents string has changed
|
|
42
|
+
const lastBraceIndex = contents.lastIndexOf('}');
|
|
43
|
+
contents = contents.slice(0, lastBraceIndex) + onCreateCode + contents.slice(lastBraceIndex);
|
|
44
|
+
}
|
|
45
|
+
|
|
24
46
|
config.modResults.contents = contents;
|
|
25
47
|
return config;
|
|
26
48
|
});
|
|
@@ -104,6 +126,8 @@ function withAndroidConfig(config) {
|
|
|
104
126
|
});
|
|
105
127
|
}
|
|
106
128
|
|
|
129
|
+
|
|
130
|
+
|
|
107
131
|
return config;
|
|
108
132
|
});
|
|
109
133
|
}
|