Skip to content

Commit 90ca301

Browse files
committed
Push Notifications Fix
1 parent c55897b commit 90ca301

File tree

21 files changed

+549
-191
lines changed

21 files changed

+549
-191
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ We can then use this method to create a listener that listens for an invitation
174174
SocketMethod.BYE.methodName -> {
175175
// Handle a call rejection or ending - Update UI or Navigate to new screen, etc.
176176
}
177+
SocketMethod.RINGING.methodName -> {
178+
// Client Can simulate ringing state
179+
}
180+
181+
SocketMethod.RINGING.methodName -> {
182+
// Ringback tone is streamed to the caller
183+
// early Media - Client Can simulate ringing state
184+
}
177185
}
178186
}
179187

app/src/main/AndroidManifest.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.telnyx.webrtc.sdk">
4+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
5+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"/>
46

57
<uses-permission android:name="android.permission.INTERNET" />
68
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -13,6 +15,9 @@
1315
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
1416
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
1517
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
18+
<uses-permission android:name="android.permission.WAKE_LOCK" />
19+
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
20+
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
1621

1722
<application
1823
android:allowBackup="true"
@@ -60,5 +65,12 @@
6065
android:name="com.google.firebase.messaging.default_notification_channel_id"
6166
android:value="telnyx_channel" />
6267

68+
<service
69+
android:enabled="true"
70+
android:exported="true"
71+
android:foregroundServiceType="phoneCall"
72+
android:name=".NotificationsService"
73+
/>
74+
6375
</application>
6476
</manifest>

app/src/main/java/com/telnyx/webrtc/sdk/App.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,23 @@
55
package com.telnyx.webrtc.sdk
66

77
import android.app.Application
8+
import android.content.Context
89
import dagger.hilt.android.HiltAndroidApp
910
import timber.log.Timber
1011

1112
@HiltAndroidApp
1213
class App : Application() {
1314

15+
init {
16+
appContext = this
17+
}
18+
19+
companion object {
20+
lateinit var appContext: Context
21+
22+
val telnyxClient by lazy { TelnyxClient(appContext) }
23+
}
24+
1425
override fun onCreate() {
1526
super.onCreate()
1627

app/src/main/java/com/telnyx/webrtc/sdk/AppConstants.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
package com.telnyx.webrtc.sdk
66

7-
const val MOCK_USERNAME = "<SIP_USER>"
8-
const val MOCK_PASSWORD = "<SIP_PASSWORD>"
7+
const val MOCK_USERNAME = "isaac71432"
8+
const val MOCK_PASSWORD = "2EFCb9MW"
99
const val MOCK_CALLER_NAME = "NAME"
1010
const val MOCK_CALLER_NUMBER = "000000000"
1111
const val MOCK_DESTINATION_NUMBER = "+35315227159"
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package com.telnyx.webrtc.sdk
2+
3+
import android.app.NotificationChannel
4+
import android.app.NotificationManager
5+
import android.app.PendingIntent
6+
import android.app.Service
7+
import android.content.Context
8+
import android.content.Intent
9+
import android.content.pm.ServiceInfo
10+
import android.graphics.Color
11+
import android.media.RingtoneManager
12+
import android.net.Uri
13+
import android.os.Build
14+
import android.os.IBinder
15+
import androidx.core.app.NotificationCompat
16+
import androidx.core.app.NotificationManagerCompat
17+
import androidx.core.app.ServiceCompat
18+
import com.google.gson.Gson
19+
import com.telnyx.webrtc.sdk.di.AppModule
20+
import com.telnyx.webrtc.sdk.manager.UserManager
21+
import com.telnyx.webrtc.sdk.model.LogLevel
22+
import com.telnyx.webrtc.sdk.model.PushMetaData
23+
import com.telnyx.webrtc.sdk.model.SocketStatus
24+
import com.telnyx.webrtc.sdk.ui.MainActivity
25+
import com.telnyx.webrtc.sdk.utility.MyFirebaseMessagingService
26+
import com.telnyx.webrtc.sdk.verto.receive.ReceivedMessageBody
27+
import com.telnyx.webrtc.sdk.verto.receive.SocketObserver
28+
import com.telnyx.webrtc.sdk.verto.receive.SocketResponse
29+
import org.checkerframework.checker.units.qual.C
30+
import timber.log.Timber
31+
32+
class NotificationsService : Service() {
33+
34+
companion object {
35+
private const val CHANNEL_ID = "PHONE_CALL_NOTIFICATION_CHANNEL"
36+
private const val NOTIFICATION_ID = 1
37+
}
38+
39+
override fun onCreate() {
40+
super.onCreate()
41+
createNotificationChannel()
42+
}
43+
44+
/* override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
45+
val metadata = intent?.getStringExtra("metadata")
46+
val telnyxPushMetadata = Gson().fromJson(metadata, PushMetaData::class.java)
47+
48+
telnyxPushMetadata?.let {
49+
showNotification(telnyxPushMetadata,metadata!!)
50+
}
51+
return START_STICKY
52+
}*/
53+
54+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
55+
val metadata = intent?.getStringExtra("metadata")
56+
val telnyxPushMetadata = Gson().fromJson(metadata, PushMetaData::class.java)
57+
val sharedPref = this.getSharedPreferences(
58+
AppModule.SHARED_PREFERENCES_KEY,
59+
Context.MODE_PRIVATE
60+
)
61+
val userManager = UserManager(sharedPref)
62+
telnyxPushMetadata?.let {
63+
showNotification(it)
64+
val loginConfig = CredentialConfig(
65+
userManager.sipUsername,
66+
userManager.sipPass,
67+
userManager.callerIdNumber,
68+
userManager.callerIdNumber,
69+
userManager.fcmToken,
70+
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE),// or ringtone,
71+
R.raw.ringback_tone,
72+
LogLevel.ALL
73+
)
74+
App.telnyxClient.connect(txPushMetaData = metadata, credentialConfig = loginConfig, autoLogin = true)
75+
}
76+
return START_STICKY
77+
}
78+
79+
override fun onBind(intent: Intent?): IBinder? {
80+
return null
81+
}
82+
83+
private fun createNotificationChannel() {
84+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
85+
val name = "Phone Call Notifications"
86+
val description = "Notifications for incoming phone calls"
87+
val importance = NotificationManager.IMPORTANCE_HIGH
88+
val channel = NotificationChannel(CHANNEL_ID, name, importance)
89+
channel.description = description
90+
91+
val notificationManager = getSystemService(NotificationManager::class.java)
92+
channel.apply {
93+
vibrationPattern =
94+
longArrayOf(0, 1000, 500, 1000, 500)
95+
lightColor = Color.RED
96+
enableLights(true)
97+
enableVibration(true)
98+
setSound(null, null)
99+
}
100+
notificationManager.createNotificationChannel(channel)
101+
}
102+
}
103+
104+
private fun showNotification(txPushMetaData: PushMetaData) {
105+
val intent = Intent(this, MainActivity::class.java).apply {
106+
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
107+
}
108+
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
109+
110+
val customSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
111+
112+
val rejectResultIntent = Intent(this, MainActivity::class.java)
113+
rejectResultIntent.addCategory(Intent.CATEGORY_LAUNCHER)
114+
rejectResultIntent.action = Intent.ACTION_VIEW
115+
rejectResultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
116+
rejectResultIntent.putExtra(
117+
MyFirebaseMessagingService.EXT_KEY_DO_ACTION,
118+
MyFirebaseMessagingService.ACT_REJECT_CALL
119+
)
120+
val rejectPendingIntent = PendingIntent.getActivity(
121+
this,
122+
MyFirebaseMessagingService.REJECT_REQUEST_CODE,
123+
rejectResultIntent,
124+
PendingIntent.FLAG_IMMUTABLE
125+
)
126+
127+
val answerResultIntent = Intent(this, MainActivity::class.java)
128+
answerResultIntent.addCategory(Intent.CATEGORY_LAUNCHER)
129+
answerResultIntent.action = Intent.ACTION_VIEW
130+
answerResultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
131+
132+
answerResultIntent.putExtra(
133+
MyFirebaseMessagingService.EXT_KEY_DO_ACTION,
134+
MyFirebaseMessagingService.ACT_ANSWER_CALL
135+
)
136+
137+
answerResultIntent.putExtra(MyFirebaseMessagingService.TX_PUSH_METADATA, txPushMetaData.toJson())
138+
139+
val answerPendingIntent = PendingIntent.getActivity(
140+
this,
141+
MyFirebaseMessagingService.ANSWER_REQUEST_CODE,
142+
answerResultIntent,
143+
PendingIntent.FLAG_IMMUTABLE
144+
)
145+
146+
Timber.d("showNotification: ${txPushMetaData.toJson()}")
147+
148+
149+
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
150+
.setSmallIcon(R.drawable.ic_stat_contact_phone)
151+
.setContentTitle("Incoming Call")
152+
.setContentText("Incoming call from: ")
153+
.setPriority(NotificationCompat.PRIORITY_MAX)
154+
.setContentIntent(pendingIntent)
155+
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
156+
.setSound(customSoundUri)
157+
.addAction(R.drawable.ic_call_white,
158+
MyFirebaseMessagingService.ACT_ANSWER_CALL, answerPendingIntent)
159+
.addAction(R.drawable.ic_call_end_white,
160+
MyFirebaseMessagingService.ACT_REJECT_CALL, rejectPendingIntent)
161+
.setOngoing(true)
162+
.setAutoCancel(false)
163+
.setCategory(NotificationCompat.CATEGORY_CALL)
164+
.setFullScreenIntent(pendingIntent, true)
165+
166+
startForeground(NOTIFICATION_ID, builder.build(),ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL)
167+
}
168+
169+
170+
/*
171+
private fun showNotification(telnyxPushMetadata: PushMetaData,metaData: String) {
172+
173+
val rejectResultIntent = Intent(this, MainActivity::class.java)
174+
rejectResultIntent.addCategory(Intent.CATEGORY_LAUNCHER)
175+
rejectResultIntent.action = Intent.ACTION_VIEW
176+
rejectResultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
177+
rejectResultIntent.putExtra(
178+
MyFirebaseMessagingService.EXT_KEY_DO_ACTION,
179+
MyFirebaseMessagingService.ACT_REJECT_CALL
180+
)
181+
val rejectPendingIntent = PendingIntent.getActivity(
182+
this,
183+
MyFirebaseMessagingService.REJECT_REQUEST_CODE,
184+
rejectResultIntent,
185+
PendingIntent.FLAG_IMMUTABLE
186+
)
187+
188+
val answerResultIntent = Intent(this, MainActivity::class.java)
189+
answerResultIntent.addCategory(Intent.CATEGORY_LAUNCHER)
190+
answerResultIntent.action = Intent.ACTION_VIEW
191+
answerResultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
192+
193+
answerResultIntent.putExtra(
194+
MyFirebaseMessagingService.EXT_KEY_DO_ACTION,
195+
MyFirebaseMessagingService.ACT_ANSWER_CALL
196+
)
197+
198+
answerResultIntent.putExtra(MyFirebaseMessagingService.TX_PUSH_METADATA, metaData)
199+
200+
val answerPendingIntent = PendingIntent.getActivity(
201+
this,
202+
MyFirebaseMessagingService.ANSWER_REQUEST_CODE,
203+
answerResultIntent,
204+
PendingIntent.FLAG_IMMUTABLE
205+
)
206+
207+
val notificationSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
208+
val notificationBuilder = NotificationCompat.Builder(this,
209+
MyFirebaseMessagingService.TELNYX_CHANNEL_ID
210+
)
211+
.setSmallIcon(R.drawable.ic_stat_contact_phone)
212+
.setPriority(NotificationCompat.PRIORITY_MAX)
213+
.setContentTitle("Incoming Call")
214+
.setContentText(telnyxPushMetadata.callerName + " - " + telnyxPushMetadata.callerNumber)
215+
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
216+
.addAction(R.drawable.ic_call_white,
217+
MyFirebaseMessagingService.ACT_ANSWER_CALL, answerPendingIntent)
218+
.addAction(R.drawable.ic_call_end_white,
219+
MyFirebaseMessagingService.ACT_REJECT_CALL, rejectPendingIntent)
220+
.setAutoCancel(false)
221+
.setOngoing(true)
222+
.setSound(notificationSoundUri)
223+
224+
225+
226+
startForeground(NOTIFICATION_ID, notificationBuilder.build())
227+
}
228+
229+
*/
230+
231+
}

app/src/main/java/com/telnyx/webrtc/sdk/di/AppModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import javax.inject.Singleton
1717
@InstallIn(SingletonComponent::class)
1818
object AppModule {
1919

20-
private const val SHARED_PREFERENCES_KEY = "TelnyxSharedPreferences"
20+
const val SHARED_PREFERENCES_KEY = "TelnyxSharedPreferences"
2121

2222
@Singleton
2323
@Provides

app/src/main/java/com/telnyx/webrtc/sdk/ui/CallInstanceFragment.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ class CallInstanceFragment : Fragment(), NumberKeyboardListener {
145145
when (data?.method) {
146146
SocketMethod.INVITE.methodName -> {
147147
//NOOP
148+
}
149+
SocketMethod.RINGING.methodName -> {
150+
151+
}
152+
SocketMethod.MEDIA.methodName -> {
153+
148154
}
149155
SocketMethod.BYE.methodName -> {
150156

0 commit comments

Comments
 (0)