Skip to content

Commit 80c3151

Browse files
authored
Merge pull request #723 from dkdanish98/master
fix: ensure ringtone plays by creating notification channel and replacing MediaPlayer with Ringtone API
2 parents 1fb5372 + 2512f53 commit 80c3151

File tree

2 files changed

+85
-42
lines changed

2 files changed

+85
-42
lines changed

android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitNotificationManager.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ class CallkitNotificationManager(
180180
val notificationId =
181181
data.getString(CallkitConstants.EXTRA_CALLKIT_ID, "callkit_incoming").hashCode()
182182
createNotificationChanel(data)
183+
184+
if (incomingChannelEnabled()) {
185+
callkitSoundPlayerManager?.play(data)
186+
}
187+
183188
notificationBuilder = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_INCOMING)
184189
notificationBuilder?.setChannelId(NOTIFICATION_CHANNEL_ID_INCOMING)
185190
notificationBuilder?.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
@@ -993,9 +998,6 @@ class CallkitNotificationManager(
993998
@SuppressLint("MissingPermission")
994999
fun showIncomingNotification(data: Bundle) {
9951000

996-
if (incomingChannelEnabled()) {
997-
callkitSoundPlayerManager?.play(data)
998-
}
9991001
val callkitNotification = getIncomingNotification(data)
10001002
callkitNotification?.let {
10011003
getNotificationManager().notify(

android/src/main/kotlin/com/hiennv/flutter_callkit_incoming/CallkitSoundPlayerManager.kt

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,46 @@ import android.content.Context
44
import android.media.AudioAttributes
55
import android.media.AudioManager
66
import android.media.MediaPlayer
7+
import android.media.Ringtone
78
import android.media.RingtoneManager
89
import android.net.Uri
910
import android.os.*
1011
import android.text.TextUtils
12+
import androidx.annotation.RequiresApi
1113

1214
class CallkitSoundPlayerManager(private val context: Context) {
1315

1416
private var vibrator: Vibrator? = null
1517
private var audioManager: AudioManager? = null
1618

17-
private var mediaPlayer: MediaPlayer? = null
19+
private var ringtone: Ringtone? = null
1820

21+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
1922
fun play(data: Bundle) {
2023
this.prepare()
2124
this.playSound(data)
2225
this.playVibrator()
2326
}
2427

2528
fun stop() {
26-
mediaPlayer?.stop()
27-
mediaPlayer?.release()
29+
ringtone?.stop()
2830
vibrator?.cancel()
2931

30-
mediaPlayer = null
32+
ringtone = null
3133
vibrator = null
3234
}
3335

3436
fun destroy() {
35-
mediaPlayer?.stop()
36-
mediaPlayer?.release()
37+
ringtone?.stop()
38+
3739
vibrator?.cancel()
3840

39-
mediaPlayer = null
41+
ringtone = null
4042
vibrator = null
4143
}
4244

4345
private fun prepare() {
44-
mediaPlayer?.stop()
45-
mediaPlayer?.release()
46+
ringtone?.stop()
4647
vibrator?.cancel()
4748
}
4849

@@ -74,6 +75,7 @@ class CallkitSoundPlayerManager(private val context: Context) {
7475
}
7576
}
7677

78+
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
7779
private fun playSound(data: Bundle?) {
7880
val sound = data?.getString(
7981
CallkitConstants.EXTRA_CALLKIT_RINGTONE_PATH,
@@ -85,41 +87,51 @@ class CallkitSoundPlayerManager(private val context: Context) {
8587
return
8688
}
8789
try {
88-
mediaPlayer(uri)
90+
ringtone = RingtoneManager.getRingtone(context, uri)
91+
ringtone?.apply {
92+
audioAttributes = AudioAttributes.Builder()
93+
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
94+
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
95+
.build()
96+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
97+
isLooping = true
98+
}
99+
play()
100+
}
89101
} catch (e: Exception) {
90102
e.printStackTrace()
91103
}
92104
}
93105

94-
private fun mediaPlayer(uri: Uri) {
95-
mediaPlayer = MediaPlayer()
96-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
97-
val attribution = AudioAttributes.Builder()
98-
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
99-
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
100-
.setLegacyStreamType(AudioManager.STREAM_RING)
101-
.build()
102-
mediaPlayer?.setAudioAttributes(attribution)
103-
} else {
104-
mediaPlayer?.setAudioStreamType(AudioManager.STREAM_RING)
105-
}
106-
setDataSource(uri)
107-
mediaPlayer?.prepare()
108-
mediaPlayer?.isLooping = true
109-
mediaPlayer?.start()
110-
}
111-
112-
private fun setDataSource(uri: Uri) {
113-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
114-
val assetFileDescriptor =
115-
context.contentResolver.openAssetFileDescriptor(uri, "r")
116-
if (assetFileDescriptor != null) {
117-
mediaPlayer?.setDataSource(assetFileDescriptor)
118-
}
119-
return
120-
}
121-
mediaPlayer?.setDataSource(context, uri)
122-
}
106+
// private fun mediaPlayer(uri: Uri) {
107+
// mediaPlayer = MediaPlayer()
108+
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
109+
// val attribution = AudioAttributes.Builder()
110+
// .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
111+
// .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
112+
// .setLegacyStreamType(AudioManager.STREAM_RING)
113+
// .build()
114+
// mediaPlayer?.setAudioAttributes(attribution)
115+
// } else {
116+
// mediaPlayer?.setAudioStreamType(AudioManager.STREAM_RING)
117+
// }
118+
// setDataSource(uri)
119+
// mediaPlayer?.prepare()
120+
// mediaPlayer?.isLooping = true
121+
// mediaPlayer?.start()
122+
// }
123+
124+
// private fun setDataSource(uri: Uri) {
125+
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
126+
// val assetFileDescriptor =
127+
// context.contentResolver.openAssetFileDescriptor(uri, "r")
128+
// if (assetFileDescriptor != null) {
129+
// mediaPlayer?.setDataSource(assetFileDescriptor)
130+
// }
131+
// return
132+
// }
133+
// mediaPlayer?.setDataSource(context, uri)
134+
// }
123135

124136
private fun getRingtoneUri(fileName: String): Uri? {
125137
if (TextUtils.isEmpty(fileName)) {
@@ -166,4 +178,33 @@ class CallkitSoundPlayerManager(private val context: Context) {
166178
return null
167179
}
168180
}
181+
182+
private fun getSafeSystemRingtoneUri(): Uri? {
183+
val defaultUri = RingtoneManager.getActualDefaultRingtoneUri(
184+
context,
185+
RingtoneManager.TYPE_RINGTONE
186+
)
187+
188+
val rm = RingtoneManager(context)
189+
rm.setType(RingtoneManager.TYPE_RINGTONE)
190+
val cursor = rm.cursor
191+
if (defaultUri != null && cursor != null) {
192+
while (cursor.moveToNext()) {
193+
val uri = rm.getRingtoneUri(cursor.position)
194+
if (uri == defaultUri) {
195+
cursor.close()
196+
return defaultUri
197+
}
198+
}
199+
}
200+
201+
// Default isn't system-provided → fallback to first available
202+
if (cursor != null && cursor.moveToFirst()) {
203+
val fallback = rm.getRingtoneUri(cursor.position)
204+
cursor.close()
205+
return fallback
206+
}
207+
208+
return null
209+
}
169210
}

0 commit comments

Comments
 (0)