rns-nativecall 1.0.6 → 1.0.7

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.
@@ -1,6 +1,7 @@
1
1
  package com.rnsnativecall
2
2
 
3
3
  import android.app.*
4
+ import android.app.Service
4
5
  import android.content.BroadcastReceiver
5
6
  import android.content.Context
6
7
  import android.content.Intent
@@ -12,13 +13,14 @@ import android.os.Handler
12
13
  import android.os.IBinder
13
14
  import android.os.Looper
14
15
  import androidx.core.app.NotificationCompat
16
+ import androidx.core.content.ContextCompat
15
17
  import com.facebook.react.HeadlessJsTaskService
16
18
 
17
19
  class CallForegroundService : Service() {
18
20
  private var unlockReceiver: UnlockReceiver? = null // Store reference for unregistering
19
21
 
20
22
  companion object {
21
- private const val CHANNEL_ID = "CALL_CHANNEL_V14_URGENT"
23
+ private const val CHANNEL_ID = "CALL_WAKE_SILENT"
22
24
 
23
25
  fun stop(context: Context) {
24
26
  val intent = Intent(context, CallForegroundService::class.java)
@@ -63,7 +65,7 @@ class CallForegroundService : Service() {
63
65
  .setContentTitle(name)
64
66
  .setContentText("Connecting...")
65
67
  .setSmallIcon(applicationInfo.icon)
66
- .setPriority(NotificationCompat.PRIORITY_DEFAULT)
68
+ .setPriority(NotificationCompat.PRIORITY_LOW)
67
69
  .setCategory(NotificationCompat.CATEGORY_SERVICE)
68
70
  .setOngoing(true)
69
71
  .build()
@@ -72,7 +74,7 @@ class CallForegroundService : Service() {
72
74
  startForeground(
73
75
  notificationId,
74
76
  notification,
75
- ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL,
77
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC,
76
78
  )
77
79
  } else {
78
80
  startForeground(notificationId, notification)
@@ -97,13 +99,13 @@ class CallForegroundService : Service() {
97
99
  e.printStackTrace()
98
100
  }
99
101
 
100
- // Auto-stop after 30s
101
- // Handler(Looper.getMainLooper()).postDelayed({
102
- // try {
103
- // stopSelf()
104
- // } catch (e: Exception) {
105
- // }
106
- // }, 30000)
102
+ // / Auto - stop after 30 s
103
+ Handler(Looper.getMainLooper()).postDelayed({
104
+ try {
105
+ stopSelf()
106
+ } catch (e: Exception) {
107
+ }
108
+ }, 30000)
107
109
 
108
110
  return START_NOT_STICKY
109
111
  }
@@ -130,12 +132,12 @@ class CallForegroundService : Service() {
130
132
  NotificationChannel(
131
133
  CHANNEL_ID,
132
134
  "Call Service",
133
- NotificationManager.IMPORTANCE_DEFAULT,
135
+ NotificationManager.IMPORTANCE_LOW,
134
136
  ).apply {
135
137
  description = "Incoming call connection state"
136
138
  setSound(null, null)
137
139
  enableVibration(false)
138
- setBypassDnd(true)
140
+ setBypassDnd(false)
139
141
  lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
140
142
  }
141
143
  val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@@ -145,3 +147,45 @@ class CallForegroundService : Service() {
145
147
 
146
148
  override fun onBind(intent: Intent?): IBinder? = null
147
149
  }
150
+
151
+ class CallUiForegroundService : Service() {
152
+ override fun onStartCommand(
153
+ intent: Intent?,
154
+ flags: Int,
155
+ startId: Int,
156
+ ): Int {
157
+ val notification =
158
+ NativeCallManager.pendingCallNotification
159
+ ?: run {
160
+ stopSelf()
161
+ return START_NOT_STICKY
162
+ }
163
+
164
+ val notificationId =
165
+ NativeCallManager.pendingNotificationId
166
+ ?: run {
167
+ stopSelf()
168
+ return START_NOT_STICKY
169
+ }
170
+
171
+ // Inside CallUiForegroundService.onStartCommand
172
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
173
+ startForeground(
174
+ notificationId,
175
+ notification,
176
+ ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL,
177
+ )
178
+ } else {
179
+ startForeground(notificationId, notification)
180
+ }
181
+
182
+ return START_NOT_STICKY
183
+ }
184
+
185
+ override fun onDestroy() {
186
+ stopForeground(true)
187
+ super.onDestroy()
188
+ }
189
+
190
+ override fun onBind(intent: Intent?): IBinder? = null
191
+ }
@@ -1,23 +1,32 @@
1
1
  package com.rnsnativecall
2
2
 
3
+ import android.app.Notification
3
4
  import android.app.NotificationChannel
4
5
  import android.app.NotificationManager
5
6
  import android.app.PendingIntent
6
7
  import android.content.Context
7
8
  import android.content.Intent
9
+ import android.content.pm.ServiceInfo
8
10
  import android.graphics.Color
9
11
  import android.media.AudioAttributes
10
12
  import android.media.RingtoneManager
11
13
  import android.os.Build
14
+ import android.os.Bundle
12
15
  import android.os.Handler
13
16
  import android.os.Looper
14
17
  import androidx.core.app.NotificationCompat
15
18
  import androidx.core.app.Person
19
+ import androidx.core.content.ContextCompat
16
20
 
17
21
  object NativeCallManager {
18
- const val channelId = "CALL_CHANNEL_V14_URGENT"
22
+ const val channelId = "CALL_CHANNEL_V15_URGENT"
19
23
  private var currentCallData: Map<String, String>? = null
20
24
 
25
+ // Change these to internal so the Service can access them
26
+ @JvmStatic internal var pendingCallNotification: android.app.Notification? = null
27
+
28
+ @JvmStatic internal var pendingNotificationId: Int? = null
29
+
21
30
  fun getCurrentCallData(): Map<String, String>? = currentCallData
22
31
 
23
32
  fun handleIncomingPush(
@@ -76,24 +85,22 @@ object NativeCallManager {
76
85
 
77
86
  // Setup Channel with System-Managed Sound
78
87
  val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
79
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
80
- val channel =
81
- NotificationChannel(channelId, "Incoming Calls", NotificationManager.IMPORTANCE_HIGH).apply {
82
- lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
83
- enableVibration(true)
84
- setBypassDnd(true)
85
- // System-managed sound ensures the "pill" pops up correctly
86
- setSound(
87
- ringtoneUri,
88
- AudioAttributes
89
- .Builder()
90
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
91
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
92
- .build(),
93
- )
94
- }
95
- notificationManager.createNotificationChannel(channel)
96
- }
88
+
89
+ val channel =
90
+ NotificationChannel(channelId, "Incoming Calls", NotificationManager.IMPORTANCE_HIGH).apply {
91
+ lockscreenVisibility = NotificationCompat.VISIBILITY_PUBLIC
92
+ enableVibration(true)
93
+ setBypassDnd(true)
94
+ setSound(
95
+ ringtoneUri,
96
+ AudioAttributes
97
+ .Builder()
98
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
99
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
100
+ .build(),
101
+ )
102
+ }
103
+ notificationManager.createNotificationChannel(channel)
97
104
 
98
105
  val caller =
99
106
  Person
@@ -111,6 +118,8 @@ object NativeCallManager {
111
118
  .setOngoing(true)
112
119
  .setAutoCancel(false)
113
120
  .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
121
+ .setWhen(0)
122
+ .setUsesChronometer(false)
114
123
  .setContentIntent(contentIntent)
115
124
  .setFullScreenIntent(fullScreenPendingIntent, true)
116
125
  .setStyle(
@@ -120,8 +129,19 @@ object NativeCallManager {
120
129
  .setDeclineButtonColorHint(Color.RED),
121
130
  ).setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
122
131
 
123
- // Sending this notification will now trigger the system ringtone automatically
124
- notificationManager.notify(notificationId, builder.build())
132
+ val notification = builder.build()
133
+ pendingCallNotification = notification
134
+ pendingNotificationId = notificationId
135
+
136
+ // Relay to UI Service
137
+ val uiIntent = Intent(context, CallUiForegroundService::class.java)
138
+ ContextCompat.startForegroundService(context, uiIntent)
139
+
140
+ // Manual notify ensures the banner pops immediately
141
+ val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
142
+ manager.notify(notificationId, notification)
143
+
144
+ CallForegroundService.stop(context)
125
145
  }
126
146
  }
127
147
 
@@ -129,18 +149,15 @@ object NativeCallManager {
129
149
  context: Context,
130
150
  uuid: String?,
131
151
  ) {
132
- this.currentCallData = null
133
- val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
152
+ pendingCallNotification = null
153
+ pendingNotificationId = null
134
154
 
135
- if (uuid != null) {
136
- // 1. Kill the notification UI
137
- notificationManager.cancel(uuid.hashCode())
155
+ val notificationManager =
156
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
138
157
 
139
- // 2. IMPORTANT: Stop the Foreground Service process
140
- // This ensures the "Pill" in the status bar goes away
141
- val serviceIntent = Intent(context, CallForegroundService::class.java)
142
- context.stopService(serviceIntent)
143
- }
158
+ uuid?.let { notificationManager.cancel(it.hashCode()) }
159
+
160
+ context.stopService(Intent(context, CallUiForegroundService::class.java))
144
161
  }
145
162
 
146
163
  fun connecting(
@@ -1,6 +1,8 @@
1
1
  package com.rnsnativecall
2
2
 
3
3
  import android.app.Activity
4
+ import android.app.KeyguardManager
5
+ import android.content.Context
4
6
  import android.os.Build
5
7
  import android.os.Bundle
6
8
  import android.view.WindowManager
@@ -10,17 +12,21 @@ class NotificationOverlayActivity : Activity() {
10
12
  super.onCreate(savedInstanceState)
11
13
 
12
14
  // These flags allow the notification pill to show over the lockscreen
15
+
13
16
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
14
17
  setShowWhenLocked(true)
15
18
  setTurnScreenOn(true)
19
+ val km = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
20
+ km.requestDismissKeyguard(this, null)
16
21
  } else {
17
22
  @Suppress("DEPRECATION")
18
23
  window.addFlags(
19
24
  WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
20
- WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
21
- WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
25
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
26
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON or
27
+ WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
22
28
  )
23
29
  }
24
30
  finish()
25
31
  }
26
- }
32
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rns-nativecall",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
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",
@@ -87,6 +87,7 @@ function withAndroidConfig(config) {
87
87
  'android.permission.VIBRATE',
88
88
  'android.permission.FOREGROUND_SERVICE',
89
89
  'android.permission.FOREGROUND_SERVICE_PHONE_CALL', // ADDED THIS
90
+ 'android.permission.FOREGROUND_SERVICE_DATA_SYNC', // ADDED THIS
90
91
  'android.permission.USE_FULL_SCREEN_INTENT', // ADDED THIS
91
92
  'android.permission.MANAGE_ONGOING_CALLS', // ADDED THIS
92
93
  'android.permission.POST_NOTIFICATIONS',
@@ -107,7 +108,8 @@ function withAndroidConfig(config) {
107
108
 
108
109
  const services = [
109
110
  { name: 'com.rnsnativecall.CallMessagingService', exported: 'false', filter: 'com.google.firebase.MESSAGING_EVENT' },
110
- { name: 'com.rnsnativecall.CallForegroundService', type: 'phoneCall' },
111
+ { name: 'com.rnsnativecall.CallForegroundService', type: 'dataSync' },
112
+ { name: 'com.rnsnativecall.CallUiForegroundService', type: 'phoneCall' },
111
113
  { name: 'com.rnsnativecall.CallHeadlessTask' }
112
114
  ];
113
115