rns-nativecall 0.7.2 → 0.7.3

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.
@@ -13,7 +13,6 @@ class AcceptCallActivity : Activity() {
13
13
  override fun onCreate(savedInstanceState: Bundle?) {
14
14
  super.onCreate(savedInstanceState)
15
15
 
16
- // Ensure we show over the lockscreen
17
16
  window.addFlags(
18
17
  WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
19
18
  WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
@@ -23,6 +22,14 @@ class AcceptCallActivity : Activity() {
23
22
  val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
24
23
  keyguardManager.requestDismissKeyguard(this, null)
25
24
 
25
+ // Check: Did the user actually press "Answer" or did the system auto-launch?
26
+ // If the action is null or doesn't match your Answer action,
27
+ // it means the system is just "preparing" the activity.
28
+ if (intent.action?.startsWith("ACTION_ANSWER") != true) {
29
+ // If it's just an auto-launch, we don't fire the JS event!
30
+ // We can either finish() or show a tiny "Swipe to Answer" UI.
31
+ return
32
+ }
26
33
  processCallIntent(intent)
27
34
  }
28
35
 
@@ -35,30 +42,36 @@ class AcceptCallActivity : Activity() {
35
42
  val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
36
43
  uuid?.let { notificationManager.cancel(it.hashCode()) }
37
44
 
38
- val dataMap = mutableMapOf<String, String>()
39
- extras?.keySet()?.forEach { key ->
40
- extras.get(key)?.let { dataMap[key] = it.toString() }
41
- }
42
-
43
- // 1. Set the data for JS (Cold start support)
44
- CallModule.setPendingCallData("onCallAccepted_pending", dataMap)
45
-
46
- // 2. Fire event immediately if JS is alive
47
- if (CallModule.isReady()) {
48
- CallModule.sendEventToJS("onCallAccepted", dataMap)
49
- }
50
-
51
- // 3. Bring the Main App to the front
45
+ // WE STOP SENDING THE JS EVENT HERE.
46
+ // Instead, we pass the intent to MainActivity with a specific ACTION.
52
47
  openMainApp(extras)
53
48
  finish()
54
49
  }
55
50
 
56
51
  private fun openMainApp(extras: Bundle?) {
57
- val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
58
- launchIntent?.apply {
59
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
60
- putExtras(extras ?: Bundle())
61
- startActivity(this)
52
+ try {
53
+ // Get the actual MainActivity class name (e.g., com.yourapp.MainActivity)
54
+ val mainActivityClassName = "${packageName}.MainActivity"
55
+
56
+ val intent = Intent().apply {
57
+ setClassName(packageName, mainActivityClassName)
58
+ action = "com.rnsnativecall.ACTION_ANSWER"
59
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
60
+
61
+ // Ensure extras are carried over
62
+ extras?.let { putExtras(it) }
63
+ }
64
+
65
+ startActivity(intent)
66
+ } catch (e: Exception) {
67
+ // Fallback: If explicit mapping fails, try the launch intent but force the action
68
+ val launchIntent = packageManager.getLaunchIntentForPackage(packageName)
69
+ launchIntent?.apply {
70
+ action = "com.rnsnativecall.ACTION_ANSWER"
71
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
72
+ extras?.let { putExtras(it) }
73
+ startActivity(this)
74
+ }
62
75
  }
63
76
  }
64
77
  }
@@ -11,92 +11,158 @@ import android.media.Ringtone
11
11
  import android.media.RingtoneManager
12
12
  import android.graphics.Color
13
13
 
14
+ import androidx.core.app.Person
15
+ import androidx.core.app.NotificationCompat
16
+
14
17
  object NativeCallManager {
15
18
 
16
19
  private var ringtone: Ringtone? = null
17
20
  const val channelId = "CALL_CHANNEL_ID"
18
21
 
19
- fun handleIncomingPush(context: Context, data: Map<String, String>) {
20
- val uuid = data["callUuid"] ?: return
21
- stopRingtone()
22
-
23
- val name = data["name"] ?: "Incoming Call"
24
- val callType = data["callType"] ?: "audio"
25
- val notificationId = uuid.hashCode()
26
-
27
- val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
28
- PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
29
- } else {
30
- PendingIntent.FLAG_UPDATE_CURRENT
31
- }
32
-
33
- val noOpIntent = PendingIntent.getActivity(
34
- context,
35
- notificationId + 1,
36
- Intent(),
37
- pendingFlags
38
- )
39
-
40
- val intentToActivity = Intent(context, AcceptCallActivity::class.java).apply {
41
- this.action = "ACTION_SHOW_UI_$uuid"
42
- data.forEach { (key, value) -> this.putExtra(key, value) }
43
- this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
44
- }
22
+ // fun handleIncomingPush(context: Context, data: Map<String, String>) {
23
+ // val uuid = data["callUuid"] ?: return
24
+ // stopRingtone()
25
+
26
+ // val name = data["name"] ?: "Incoming Call"
27
+ // val callType = data["callType"] ?: "audio"
28
+ // val notificationId = uuid.hashCode()
29
+
30
+ // val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
31
+ // PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
32
+ // } else {
33
+ // PendingIntent.FLAG_UPDATE_CURRENT
34
+ // }
35
+
36
+ // val noOpIntent = PendingIntent.getActivity(
37
+ // context,
38
+ // notificationId + 1,
39
+ // Intent(),
40
+ // pendingFlags
41
+ // )
42
+
43
+ // val intentToActivity = Intent(context, AcceptCallActivity::class.java).apply {
44
+ // this.action = "ACTION_SHOW_UI_$uuid"
45
+ // data.forEach { (key, value) -> this.putExtra(key, value) }
46
+ // this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
47
+ // }
48
+
49
+ // val fullScreenPendingIntent = PendingIntent.getActivity(
50
+ // context,
51
+ // notificationId,
52
+ // intentToActivity,
53
+ // pendingFlags
54
+ // )
55
+
56
+ // val rejectIntent = Intent(context, CallActionReceiver::class.java).apply {
57
+ // this.action = "ACTION_REJECT_$uuid"
58
+ // this.putExtra("EXTRA_CALL_UUID", uuid)
59
+ // data.forEach { (key, value) -> this.putExtra(key, value) }
60
+ // }
61
+
62
+ // val rejectPendingIntent = PendingIntent.getBroadcast(
63
+ // context,
64
+ // notificationId,
65
+ // rejectIntent,
66
+ // pendingFlags
67
+ // )
68
+
69
+ // val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
70
+
71
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
72
+ // val channel = NotificationChannel(
73
+ // channelId,
74
+ // "Incoming Calls",
75
+ // NotificationManager.IMPORTANCE_HIGH // NotificationManager.IMPORTANCE_HIGH
76
+ // ).apply {
77
+ // enableVibration(true)
78
+ // vibrationPattern = longArrayOf(0, 500, 500, 500)
79
+ // lightColor = Color.GREEN
80
+ // setBypassDnd(true)
81
+ // lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
82
+ // setSound(null, null)
83
+ // }
84
+ // notificationManager.createNotificationChannel(channel)
85
+ // }
86
+
87
+ // val builder = NotificationCompat.Builder(context, channelId)
88
+ // .setSmallIcon(context.applicationInfo.icon)
89
+ // .setContentTitle("Incoming $callType call")
90
+ // .setContentText(name)
91
+ // .setPriority(NotificationCompat.PRIORITY_MAX) // PRIORITY_HIGH
92
+ // .setCategory(NotificationCompat.CATEGORY_CALL) // CATEGORY_CALL
93
+ // .setOngoing(true)
94
+ // .setAutoCancel(false)
95
+ // .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
96
+ // .setFullScreenIntent(fullScreenPendingIntent, true)
97
+ // .setContentIntent(noOpIntent)
98
+ // .addAction(0, "Answer", fullScreenPendingIntent)
99
+ // .addAction(0, "Decline", rejectPendingIntent)
100
+
101
+ // notificationManager.notify(notificationId, builder.build())
102
+
103
+ // try {
104
+ // val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
105
+ // ringtone = RingtoneManager.getRingtone(context, ringtoneUri)
106
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
107
+ // ringtone?.isLooping = true
108
+ // }
109
+ // ringtone?.play()
110
+ // } catch (e: Exception) {
111
+ // e.printStackTrace()
112
+ // }
113
+ // }
114
+
115
+
116
+ fun handleIncomingPush(context: Context, data: Map<String, String>) {
117
+ val uuid = data["callUuid"] ?: return
118
+ stopRingtone()
119
+
120
+ val name = data["name"] ?: "Incoming Call"
121
+ val callType = data["callType"] ?: "audio"
122
+ val notificationId = uuid.hashCode()
45
123
 
46
- val fullScreenPendingIntent = PendingIntent.getActivity(
47
- context,
48
- notificationId,
49
- intentToActivity,
50
- pendingFlags
51
- )
124
+ // 1. Create the Person object (Required for CallStyle)
125
+ val caller = Person.Builder()
126
+ .setName(name)
127
+ .setImportant(true)
128
+ .build()
129
+
130
+ // 2. Intents (Keep your existing intent logic)
131
+ val intentToActivity = Intent(context, AcceptCallActivity::class.java).apply {
132
+ this.action = "ACTION_ANSWER_$uuid"
133
+ data.forEach { (key, value) -> this.putExtra(key, value) }
134
+ this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
135
+ }
52
136
 
53
- val rejectIntent = Intent(context, CallActionReceiver::class.java).apply {
54
- this.action = "ACTION_REJECT_$uuid"
55
- this.putExtra("EXTRA_CALL_UUID", uuid)
56
- data.forEach { (key, value) -> this.putExtra(key, value) }
57
- }
137
+ val fullScreenPendingIntent = PendingIntent.getActivity(
138
+ context, notificationId, intentToActivity,
139
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
140
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
141
+ else PendingIntent.FLAG_UPDATE_CURRENT
142
+ )
58
143
 
59
- val rejectPendingIntent = PendingIntent.getBroadcast(
60
- context,
61
- notificationId,
62
- rejectIntent,
63
- pendingFlags
144
+ // 3. Build the Notification with CallStyle
145
+ val builder = NotificationCompat.Builder(context, channelId)
146
+ .setSmallIcon(context.applicationInfo.icon)
147
+ .setPriority(NotificationCompat.PRIORITY_MAX)
148
+ .setCategory(NotificationCompat.CATEGORY_CALL)
149
+ .setOngoing(true)
150
+ .setAutoCancel(false)
151
+ .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
152
+ // This makes it show on the lock screen WITHOUT auto-launching the activity
153
+ .setFullScreenIntent(fullScreenPendingIntent, true)
154
+ .setStyle(
155
+ NotificationCompat.CallStyle.forIncomingCall(
156
+ caller,
157
+ rejectPendingIntent, // Use your existing rejectIntent
158
+ fullScreenPendingIntent
159
+ )
64
160
  )
65
161
 
66
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
67
-
68
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
69
- val channel = NotificationChannel(
70
- channelId,
71
- "Incoming Calls",
72
- NotificationManager.IMPORTANCE_HIGH // NotificationManager.IMPORTANCE_HIGH
73
- ).apply {
74
- enableVibration(true)
75
- vibrationPattern = longArrayOf(0, 500, 500, 500)
76
- lightColor = Color.GREEN
77
- setBypassDnd(true)
78
- lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
79
- setSound(null, null)
80
- }
81
- notificationManager.createNotificationChannel(channel)
82
- }
83
-
84
- val builder = NotificationCompat.Builder(context, channelId)
85
- .setSmallIcon(context.applicationInfo.icon)
86
- .setContentTitle("Incoming $callType call")
87
- .setContentText(name)
88
- .setPriority(NotificationCompat.PRIORITY_MAX) // PRIORITY_HIGH
89
- .setCategory(NotificationCompat.CATEGORY_CALL) // CATEGORY_CALL
90
- .setOngoing(true)
91
- .setAutoCancel(false)
92
- .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
93
- .setFullScreenIntent(fullScreenPendingIntent, true)
94
- .setContentIntent(noOpIntent)
95
- .addAction(0, "Answer", fullScreenPendingIntent)
96
- .addAction(0, "Decline", rejectPendingIntent)
97
-
98
- notificationManager.notify(notificationId, builder.build())
99
-
162
+ val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
163
+ // ... ensure channel is created ...
164
+ notificationManager.notify(notificationId, builder.build())
165
+
100
166
  try {
101
167
  val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
102
168
  ringtone = RingtoneManager.getRingtone(context, ringtoneUri)
@@ -107,7 +173,7 @@ object NativeCallManager {
107
173
  } catch (e: Exception) {
108
174
  e.printStackTrace()
109
175
  }
110
- }
176
+ }
111
177
 
112
178
  fun stopRingtone() {
113
179
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "High-performance React Native module for handling native VoIP call UI on Android and iOS.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",