Author SHA1 Message Date
MrBlakeandClaude Opus 5.5 612c017c2b fix(telefon): ongoing-call notification crashed the InCallService; 0.1.2
CallStyle.forOngoingCall is only allowed with a foreground service or a full-screen intent and
throws otherwise. The crash on every outgoing call made Telecom fall back to the system phone app.
The call path now logs failures instead of crashing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-17 16:46:40 +02:00
3 changed files with 13 additions and 7 deletions
+2 -2
View File
@@ -16,8 +16,8 @@ android {
applicationId = "app.telefon" applicationId = "app.telefon"
minSdk = 29 minSdk = 29
targetSdk = 36 targetSdk = 36
versionCode = 2 versionCode = 3
versionName = "0.1.1" versionName = "0.1.2"
} }
// Release key lives outside the repo; without it, release builds fall back to the debug key (local only). // Release key lives outside the repo; without it, release builds fall back to the debug key (local only).
@@ -25,7 +25,9 @@ class CallService : InCallService() {
override fun onCallAdded(call: Call) { override fun onCallAdded(call: Call) {
CallManager.added(call) CallManager.added(call)
if (call.details.state == Call.STATE_RINGING) showIncoming(call) else startActivity(CallActivity.intent(this)) // a crash here would make Telecom switch to the system phone app, so failures are logged, not thrown
runCatching { if (call.details.state == Call.STATE_RINGING) showIncoming(call) else startActivity(CallActivity.intent(this)) }
.onFailure { android.util.Log.e("Telefon", "onCallAdded", it); runCatching { startActivity(CallActivity.intent(this)) } }
} }
override fun onCallRemoved(call: Call) = CallManager.removed(call) override fun onCallRemoved(call: Call) = CallManager.removed(call)
@@ -36,7 +38,9 @@ class CallService : InCallService() {
updateProximity(audioState.route) updateProximity(audioState.route)
} }
internal fun onCallsChanged(calls: List<CallUi>) { internal fun onCallsChanged(calls: List<CallUi>) = runCatching { updateNotification(calls) }.onFailure { android.util.Log.e("Telefon", "notification", it) }
private fun updateNotification(calls: List<CallUi>) {
val nm = getSystemService(NotificationManager::class.java) val nm = getSystemService(NotificationManager::class.java)
val ringing = calls.firstOrNull { it.phase == Phase.RINGING } val ringing = calls.firstOrNull { it.phase == Phase.RINGING }
val current = calls.firstOrNull { it.phase != Phase.RINGING && it.phase != Phase.DISCONNECTED } val current = calls.firstOrNull { it.phase != Phase.RINGING && it.phase != Phase.DISCONNECTED }
@@ -64,10 +68,11 @@ class CallService : InCallService() {
private fun ongoing(c: CallUi): Notification { private fun ongoing(c: CallUi): Notification {
val name = Contacts.lookupName(this, c.number) ?: c.number val name = Contacts.lookupName(this, c.number) ?: c.number
val person = Person.Builder().setName(name).build() // not CallStyle: that style is only allowed with a foreground service or a full-screen intent
// and throws otherwise, which made Telecom fall back to the system phone app
return NotificationCompat.Builder(this, CH_ONGOING).setSmallIcon(R.drawable.ic_stat_call) return NotificationCompat.Builder(this, CH_ONGOING).setSmallIcon(R.drawable.ic_stat_call)
.setContentTitle(name).setContentIntent(CallActivity.pending(this)).setOngoing(true).setSilent(true) .setContentTitle(name).setContentText(getString(R.string.ongoing_call)).setContentIntent(CallActivity.pending(this)).setOngoing(true).setSilent(true)
.setStyle(NotificationCompat.CallStyle.forOngoingCall(person, action(ACTION_HANGUP))) .addAction(0, getString(R.string.hang_up), action(ACTION_HANGUP))
.apply { c.connectedAt?.let { setUsesChronometer(true).setWhen(it).setShowWhen(true) } } .apply { c.connectedAt?.let { setUsesChronometer(true).setWhen(it).setShowWhen(true) } }
.setCategory(NotificationCompat.CATEGORY_CALL).build() .setCategory(NotificationCompat.CATEGORY_CALL).build()
} }
@@ -57,6 +57,7 @@
<string name="resume">Fortsetzen</string> <string name="resume">Fortsetzen</string>
<string name="bluetooth">Bluetooth</string> <string name="bluetooth">Bluetooth</string>
<string name="hang_up">Auflegen</string> <string name="hang_up">Auflegen</string>
<string name="ongoing_call">Laufender Anruf</string>
<string name="ch_incoming">Eingehende Anrufe</string> <string name="ch_incoming">Eingehende Anrufe</string>
<string name="ch_ongoing">Laufende Anrufe</string> <string name="ch_ongoing">Laufende Anrufe</string>
</resources> </resources>