Звонки: надёжность отмены (INVITE-кодограмма + watchdog) и вибрация входящего по ringer-режиму
This commit is contained in:
1 parent
b90dc752d2
commit
cc269e810c
5 files changed
+144
-71
No files matched your search
@@ -16,12 +16,18 @@ import com.utun.chat.ChatApplication
|
||||
import com.utun.chat.R
|
||||
|
||||
/**
|
||||
* Мелодия входящего звонка через профиль звонка (STREAM_RING):
|
||||
* - громкость — настройка «громкость вызова»;
|
||||
* - вибрация — по системной настройке «вибрировать при вызове» (VIBRATE_WHEN_RINGING).
|
||||
* Мелодия входящего звонка через профиль звонка (STREAM_RING) + ручная вибрация.
|
||||
*
|
||||
* API 28+ : Ringtone (RingtoneManager) — громкость и вибрация автоматически.
|
||||
* API 26–27: MediaPlayer(STREAM_RING, loop) + ручная вибрация по системной настройке.
|
||||
* Поведение по системному режиму звонка (AudioManager.getRingerMode):
|
||||
* - NORMAL : звук + вибрация, если включена настройка «вибрировать при вызове»
|
||||
* (Settings.System.VIBRATE_WHEN_RINGING);
|
||||
* - VIBRATE: без звука, только вибрация;
|
||||
* - SILENT : без звука и вибрации.
|
||||
*
|
||||
* Вибрация всегда запускается вручную через Vibrator (класс Ringtone сам не вибрирует).
|
||||
*
|
||||
* API 28+ : звук через Ringtone (RingtoneManager), громкость — «громкость вызова».
|
||||
* API 26–27: звук через MediaPlayer(STREAM_RING, loop) + audio focus.
|
||||
*/
|
||||
class RingtonePlayer {
|
||||
|
||||
@@ -33,50 +39,69 @@ class RingtonePlayer {
|
||||
fun play() {
|
||||
stop()
|
||||
val ctx = ChatApplication.instance
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val uri = Uri.parse("android.resource://${ctx.packageName}/${R.raw.ringtone}")
|
||||
val r = try {
|
||||
RingtoneManager.getRingtone(ctx, uri)
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "getRingtone failed: ${e.message}")
|
||||
null
|
||||
} ?: return
|
||||
try {
|
||||
r.isLooping = true
|
||||
r.play()
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "play failed: ${e.message}")
|
||||
return
|
||||
val am = try {
|
||||
ctx.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("WARN", "Ringtone", "audio service unavailable: ${e.message}")
|
||||
null
|
||||
} ?: return
|
||||
|
||||
val ringerMode = am.ringerMode
|
||||
val playSound = ringerMode == AudioManager.RINGER_MODE_NORMAL
|
||||
val playVibrate = ringerMode == AudioManager.RINGER_MODE_VIBRATE
|
||||
|| (playSound && systemVibrateWhenRinging())
|
||||
|
||||
LogManager.addLog("INFO", "Ringtone",
|
||||
"ringerMode=%d sound=%b vibrate=%b".format(ringerMode, playSound, playVibrate))
|
||||
|
||||
if (playSound) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val uri = Uri.parse("android.resource://${ctx.packageName}/${R.raw.ringtone}")
|
||||
val r = try {
|
||||
RingtoneManager.getRingtone(ctx, uri)
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "getRingtone failed: ${e.message}")
|
||||
null
|
||||
} ?: return
|
||||
try {
|
||||
r.isLooping = true
|
||||
r.play()
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "play failed: ${e.message}")
|
||||
return
|
||||
}
|
||||
ringtone = r
|
||||
LogManager.addLog("INFO", "Ringtone", "sound started (Ringtone, STREAM_RING)")
|
||||
} else {
|
||||
val mp = try {
|
||||
MediaPlayer.create(ctx, R.raw.ringtone)
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "MediaPlayer.create failed: ${e.message}")
|
||||
null
|
||||
} ?: return
|
||||
try {
|
||||
mp.setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_RING)
|
||||
.build()
|
||||
)
|
||||
mp.isLooping = true
|
||||
requestAudioFocus()
|
||||
mp.start()
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "MediaPlayer start failed: ${e.message}")
|
||||
try { mp.release() } catch (_: Exception) {}
|
||||
abandonAudioFocus()
|
||||
return
|
||||
}
|
||||
mediaPlayer = mp
|
||||
LogManager.addLog("INFO", "Ringtone", "sound started (MediaPlayer fallback, STREAM_RING)")
|
||||
}
|
||||
ringtone = r
|
||||
LogManager.addLog("INFO", "Ringtone", "started (Ringtone, STREAM_RING + system vibrate)")
|
||||
} else {
|
||||
val mp = try {
|
||||
MediaPlayer.create(ctx, R.raw.ringtone)
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "MediaPlayer.create failed: ${e.message}")
|
||||
null
|
||||
} ?: return
|
||||
try {
|
||||
mp.setAudioAttributes(
|
||||
AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
||||
.setLegacyStreamType(AudioManager.STREAM_RING)
|
||||
.build()
|
||||
)
|
||||
mp.isLooping = true
|
||||
requestAudioFocus()
|
||||
mp.start()
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("ERROR", "Ringtone", "MediaPlayer start failed: ${e.message}")
|
||||
try { mp.release() } catch (_: Exception) {}
|
||||
abandonAudioFocus()
|
||||
return
|
||||
}
|
||||
mediaPlayer = mp
|
||||
}
|
||||
if (playVibrate) {
|
||||
startVibrate()
|
||||
LogManager.addLog("INFO", "Ringtone", "started (MediaPlayer fallback, STREAM_RING)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +120,7 @@ class RingtonePlayer {
|
||||
LogManager.addLog("INFO", "Ringtone", "stopped")
|
||||
}
|
||||
|
||||
/* ── вибрация (fallback API 26–27) по системной настройке ── */
|
||||
/* ── вибрация (решение принято в play(): VIBRATE-режим или VIBRATE_WHEN_RINGING) ── */
|
||||
|
||||
private fun systemVibrateWhenRinging(): Boolean = try {
|
||||
Settings.System.getInt(
|
||||
@@ -105,7 +130,6 @@ class RingtonePlayer {
|
||||
}
|
||||
|
||||
private fun startVibrate() {
|
||||
if (!systemVibrateWhenRinging()) return
|
||||
val v = try {
|
||||
ChatApplication.instance.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
||||
} catch (e: Exception) {
|
||||
@@ -116,6 +140,7 @@ class RingtonePlayer {
|
||||
try {
|
||||
v.vibrate(VibrationEffect.createWaveform(longArrayOf(1000, 1000), 0))
|
||||
vibrator = v
|
||||
LogManager.addLog("INFO", "Ringtone", "vibration started")
|
||||
} catch (e: Exception) {
|
||||
LogManager.addLog("WARN", "Ringtone", "vibrate failed: ${e.message}")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user