rns-nativecall 0.7.2 → 0.7.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.
@@ -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
  }
@@ -6,17 +6,112 @@ import android.app.PendingIntent
6
6
  import android.content.Context
7
7
  import android.content.Intent
8
8
  import android.os.Build
9
- import androidx.core.app.NotificationCompat
10
9
  import android.media.Ringtone
11
10
  import android.media.RingtoneManager
12
11
  import android.graphics.Color
13
12
 
13
+ import androidx.core.app.Person
14
+ import androidx.core.app.NotificationCompat
15
+
14
16
  object NativeCallManager {
15
17
 
16
18
  private var ringtone: Ringtone? = null
17
19
  const val channelId = "CALL_CHANNEL_ID"
18
20
 
19
- fun handleIncomingPush(context: Context, data: Map<String, String>) {
21
+ // fun handleIncomingPush(context: Context, data: Map<String, String>) {
22
+ // val uuid = data["callUuid"] ?: return
23
+ // stopRingtone()
24
+
25
+ // val name = data["name"] ?: "Incoming Call"
26
+ // val callType = data["callType"] ?: "audio"
27
+ // val notificationId = uuid.hashCode()
28
+
29
+ // val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
30
+ // PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
31
+ // } else {
32
+ // PendingIntent.FLAG_UPDATE_CURRENT
33
+ // }
34
+
35
+ // val noOpIntent = PendingIntent.getActivity(
36
+ // context,
37
+ // notificationId + 1,
38
+ // Intent(),
39
+ // pendingFlags
40
+ // )
41
+
42
+ // val intentToActivity = Intent(context, AcceptCallActivity::class.java).apply {
43
+ // this.action = "ACTION_SHOW_UI_$uuid"
44
+ // data.forEach { (key, value) -> this.putExtra(key, value) }
45
+ // this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
46
+ // }
47
+
48
+ // val fullScreenPendingIntent = PendingIntent.getActivity(
49
+ // context,
50
+ // notificationId,
51
+ // intentToActivity,
52
+ // pendingFlags
53
+ // )
54
+
55
+ // val rejectIntent = Intent(context, CallActionReceiver::class.java).apply {
56
+ // this.action = "ACTION_REJECT_$uuid"
57
+ // this.putExtra("EXTRA_CALL_UUID", uuid)
58
+ // data.forEach { (key, value) -> this.putExtra(key, value) }
59
+ // }
60
+
61
+ // val rejectPendingIntent = PendingIntent.getBroadcast(
62
+ // context,
63
+ // notificationId,
64
+ // rejectIntent,
65
+ // pendingFlags
66
+ // )
67
+
68
+ // val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
69
+
70
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
71
+ // val channel = NotificationChannel(
72
+ // channelId,
73
+ // "Incoming Calls",
74
+ // NotificationManager.IMPORTANCE_HIGH // NotificationManager.IMPORTANCE_HIGH
75
+ // ).apply {
76
+ // enableVibration(true)
77
+ // vibrationPattern = longArrayOf(0, 500, 500, 500)
78
+ // lightColor = Color.GREEN
79
+ // setBypassDnd(true)
80
+ // lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
81
+ // setSound(null, null)
82
+ // }
83
+ // notificationManager.createNotificationChannel(channel)
84
+ // }
85
+
86
+ // val builder = NotificationCompat.Builder(context, channelId)
87
+ // .setSmallIcon(context.applicationInfo.icon)
88
+ // .setContentTitle("Incoming $callType call")
89
+ // .setContentText(name)
90
+ // .setPriority(NotificationCompat.PRIORITY_MAX) // PRIORITY_HIGH
91
+ // .setCategory(NotificationCompat.CATEGORY_CALL) // CATEGORY_CALL
92
+ // .setOngoing(true)
93
+ // .setAutoCancel(false)
94
+ // .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
95
+ // .setFullScreenIntent(fullScreenPendingIntent, true)
96
+ // .setContentIntent(noOpIntent)
97
+ // .addAction(0, "Answer", fullScreenPendingIntent)
98
+ // .addAction(0, "Decline", rejectPendingIntent)
99
+
100
+ // notificationManager.notify(notificationId, builder.build())
101
+
102
+ // try {
103
+ // val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
104
+ // ringtone = RingtoneManager.getRingtone(context, ringtoneUri)
105
+ // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
106
+ // ringtone?.isLooping = true
107
+ // }
108
+ // ringtone?.play()
109
+ // } catch (e: Exception) {
110
+ // e.printStackTrace()
111
+ // }
112
+ // }
113
+
114
+ fun handleIncomingPush(context: Context, data: Map<String, String>) {
20
115
  val uuid = data["callUuid"] ?: return
21
116
  stopRingtone()
22
117
 
@@ -30,24 +125,15 @@ object NativeCallManager {
30
125
  PendingIntent.FLAG_UPDATE_CURRENT
31
126
  }
32
127
 
33
- val noOpIntent = PendingIntent.getActivity(
34
- context,
35
- notificationId + 1,
36
- Intent(),
37
- pendingFlags
38
- )
39
-
128
+ // 1. Setup the Intents
40
129
  val intentToActivity = Intent(context, AcceptCallActivity::class.java).apply {
41
- this.action = "ACTION_SHOW_UI_$uuid"
130
+ this.action = "ACTION_ANSWER_$uuid"
42
131
  data.forEach { (key, value) -> this.putExtra(key, value) }
43
132
  this.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
44
133
  }
45
134
 
46
135
  val fullScreenPendingIntent = PendingIntent.getActivity(
47
- context,
48
- notificationId,
49
- intentToActivity,
50
- pendingFlags
136
+ context, notificationId, intentToActivity, pendingFlags
51
137
  )
52
138
 
53
139
  val rejectIntent = Intent(context, CallActionReceiver::class.java).apply {
@@ -56,47 +142,55 @@ object NativeCallManager {
56
142
  data.forEach { (key, value) -> this.putExtra(key, value) }
57
143
  }
58
144
 
145
+ // Fix: Define the missing rejectPendingIntent
59
146
  val rejectPendingIntent = PendingIntent.getBroadcast(
60
- context,
61
- notificationId,
62
- rejectIntent,
63
- pendingFlags
147
+ context, notificationId, rejectIntent, pendingFlags
64
148
  )
65
149
 
150
+ // 2. Create the Person object for CallStyle
151
+ val caller = Person.Builder()
152
+ .setName(name)
153
+ .setImportant(true)
154
+ .build()
155
+
66
156
  val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
67
157
 
158
+ // 3. Setup Channel
68
159
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
69
160
  val channel = NotificationChannel(
70
161
  channelId,
71
162
  "Incoming Calls",
72
- NotificationManager.IMPORTANCE_HIGH // NotificationManager.IMPORTANCE_HIGH
163
+ NotificationManager.IMPORTANCE_HIGH
73
164
  ).apply {
74
165
  enableVibration(true)
75
166
  vibrationPattern = longArrayOf(0, 500, 500, 500)
76
167
  lightColor = Color.GREEN
77
168
  setBypassDnd(true)
78
- lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
79
169
  setSound(null, null)
80
170
  }
81
171
  notificationManager.createNotificationChannel(channel)
82
172
  }
83
173
 
174
+ // 4. Build with CallStyle
84
175
  val builder = NotificationCompat.Builder(context, channelId)
85
176
  .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
177
+ .setPriority(NotificationCompat.PRIORITY_MAX)
178
+ .setCategory(NotificationCompat.CATEGORY_CALL)
90
179
  .setOngoing(true)
91
180
  .setAutoCancel(false)
92
181
  .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
93
182
  .setFullScreenIntent(fullScreenPendingIntent, true)
94
- .setContentIntent(noOpIntent)
95
- .addAction(0, "Answer", fullScreenPendingIntent)
96
- .addAction(0, "Decline", rejectPendingIntent)
183
+ .setStyle(
184
+ NotificationCompat.CallStyle.forIncomingCall(
185
+ caller,
186
+ rejectPendingIntent,
187
+ fullScreenPendingIntent
188
+ )
189
+ )
97
190
 
98
191
  notificationManager.notify(notificationId, builder.build())
99
192
 
193
+ // 5. Start Ringtone
100
194
  try {
101
195
  val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
102
196
  ringtone = RingtoneManager.getRingtone(context, ringtoneUri)
@@ -109,6 +203,7 @@ object NativeCallManager {
109
203
  }
110
204
  }
111
205
 
206
+
112
207
  fun stopRingtone() {
113
208
  try {
114
209
  ringtone?.let { if (it.isPlaying) it.stop() }
@@ -156,7 +251,6 @@ fun aborting(context: Context, uuid: String, name: String, callType: String) {
156
251
  notificationManager.notify(notificationId, builder.build())
157
252
  }
158
253
 
159
-
160
254
  fun dismissIncomingCall(context: Context, uuid: String?) {
161
255
  stopRingtone()
162
256
  val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
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",