Skip to content

Commit 9c84e2c

Browse files
authored
fix: call service crashing in background (#WPB-17663) (#4028)
1 parent 225e903 commit 9c84e2c

File tree

3 files changed

+41
-17
lines changed

3 files changed

+41
-17
lines changed

app/src/main/kotlin/com/wire/android/notification/CallNotificationManager.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
package com.wire.android.notification
2020

2121
import android.annotation.SuppressLint
22+
import android.app.ActivityManager
2223
import android.app.Notification
2324
import android.content.Context
25+
import android.os.Build
2426
import android.service.notification.StatusBarNotification
2527
import androidx.core.app.NotificationCompat
2628
import androidx.core.app.NotificationCompat.CallStyle
@@ -63,6 +65,7 @@ class CallNotificationManager @Inject constructor(
6365
) {
6466

6567
private val notificationManager = NotificationManagerCompat.from(context)
68+
private val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
6669
private val scope = CoroutineScope(SupervisorJob() + dispatcherProvider.default())
6770
private val incomingCallsForUsers = MutableStateFlow<Map<UserId, IncomingCallsForUser>>(mapOf())
6871

@@ -158,6 +161,23 @@ class CallNotificationManager @Inject constructor(
158161
notificationManager.notify(tag, id, notification)
159162
}
160163

164+
fun areServiceNotificationsEnabled(): Boolean {
165+
166+
val isBackgroundRestricted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
167+
activityManager.isBackgroundRestricted
168+
} else {
169+
false
170+
}
171+
172+
return notificationManager.areNotificationsEnabled() && !isBackgroundRestricted
173+
}
174+
175+
fun showNotification(id: NotificationIds, notification: Notification) {
176+
if (notificationManager.areNotificationsEnabled()) {
177+
notificationManager.notify(id.ordinal, notification)
178+
}
179+
}
180+
161181
companion object {
162182
private const val TAG = "CallNotificationManager"
163183

app/src/main/kotlin/com/wire/android/services/CallService.kt

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ import com.wire.android.notification.NotificationIds
3434
import com.wire.android.services.CallService.Action
3535
import com.wire.android.util.dispatchers.DispatcherProvider
3636
import com.wire.android.util.logIfEmptyUserName
37+
import com.wire.kalium.common.functional.Either
38+
import com.wire.kalium.common.functional.fold
3739
import com.wire.kalium.logic.CoreLogic
3840
import com.wire.kalium.logic.data.call.CallStatus
3941
import com.wire.kalium.logic.data.id.ConversationId
4042
import com.wire.kalium.logic.data.id.QualifiedIdMapper
4143
import com.wire.kalium.logic.data.user.UserId
4244
import com.wire.kalium.logic.feature.call.CallsScope
4345
import com.wire.kalium.logic.feature.session.CurrentSessionResult
44-
import com.wire.kalium.common.functional.Either
45-
import com.wire.kalium.common.functional.fold
4646
import dagger.hilt.android.AndroidEntryPoint
4747
import dev.ahmedmourad.bundlizer.Bundlizer
4848
import kotlinx.coroutines.CoroutineScope
@@ -145,7 +145,7 @@ class CallService : Service() {
145145
stopSelf()
146146
},
147147
{ data ->
148-
generateForegroundNotification(data)
148+
updateForegroundNotification(data)
149149
}
150150
)
151151
}
@@ -161,21 +161,19 @@ class CallService : Service() {
161161
scope.cancel()
162162
}
163163

164-
private fun generateForegroundNotification(data: CallNotificationData) {
165-
appLogger.i("$TAG: generating foregroundNotification...")
166-
val notification = if (data.callStatus == CallStatus.STARTED) {
167-
callNotificationManager.builder.getOutgoingCallNotification(data)
168-
} else {
169-
callNotificationManager.builder.getOngoingCallNotification(data)
170-
}
171-
ServiceCompat.startForeground(
172-
this,
173-
NotificationIds.CALL_OUTGOING_ONGOING_NOTIFICATION_ID.ordinal,
174-
notification,
175-
ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL or ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE
176-
)
164+
private fun updateForegroundNotification(data: CallNotificationData) {
165+
// Updating service notification when notifications are disabled (or background work restricted)
166+
// causes app crash when putting app in background
167+
if (callNotificationManager.areServiceNotificationsEnabled()) {
177168

178-
appLogger.i("$TAG: started foreground with proper notification")
169+
val notification = if (data.callStatus == CallStatus.STARTED) {
170+
callNotificationManager.builder.getOutgoingCallNotification(data)
171+
} else {
172+
callNotificationManager.builder.getOngoingCallNotification(data)
173+
}
174+
175+
callNotificationManager.showNotification(NotificationIds.CALL_OUTGOING_ONGOING_NOTIFICATION_ID, notification)
176+
}
179177
}
180178

181179
private fun generatePlaceholderForegroundNotification() {

app/src/test/kotlin/com/wire/android/notification/CallNotificationManagerTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package com.wire.android.notification
1919

20+
import android.app.ActivityManager
2021
import android.app.Notification
2122
import android.content.Context
2223
import android.service.notification.StatusBarNotification
@@ -374,6 +375,9 @@ class CallNotificationManagerTest {
374375
@MockK
375376
lateinit var notificationManager: NotificationManagerCompat
376377

378+
@MockK
379+
lateinit var activityManager: ActivityManager
380+
377381
@MockK
378382
lateinit var callNotificationBuilder: CallNotificationBuilder
379383

@@ -384,6 +388,7 @@ class CallNotificationManagerTest {
384388
MockKAnnotations.init(this, relaxUnitFun = true)
385389
mockkStatic(NotificationManagerCompat::from)
386390
every { NotificationManagerCompat.from(any()) } returns notificationManager
391+
every { context.getSystemService(Context.ACTIVITY_SERVICE) } returns activityManager
387392
withActiveNotifications(emptyList())
388393
every { callNotificationBuilder.getIncomingCallNotification(any(), any()) } returns mockk()
389394
withCurrentSession(AccountInfo.Valid(UserId("userId", "domain")))
@@ -392,6 +397,7 @@ class CallNotificationManagerTest {
392397
fun clearRecordedCallsForNotificationManager() {
393398
clearMocks(
394399
notificationManager,
400+
activityManager,
395401
answers = false,
396402
recordedCalls = true,
397403
childMocks = false,

0 commit comments

Comments
 (0)