Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: crash when starting foreground service for calling from background (WPB-11112) 🍒 #3459

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@
android:theme="@style/AppTheme" />

<activity
android:name=".ui.WireActivity"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.SplashScreen"
android:windowSoftInputMode="adjustResize|stateHidden">
android:name=".ui.WireActivity"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.SplashScreen"
android:windowSoftInputMode="adjustResize|stateHidden">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down Expand Up @@ -149,12 +149,12 @@
android:scheme="wire" />

<data
android:host="conversation"
android:scheme="wire" />
android:host="conversation"
android:scheme="wire" />

<data
android:host="user"
android:scheme="wire" />
android:host="user"
android:scheme="wire" />

<data
android:host="other-user-profile"
Expand Down Expand Up @@ -351,7 +351,7 @@
android:foregroundServiceType="specialUse" />

<service
android:name=".services.OngoingCallService"
android:name=".services.CallService"
android:exported="false"
android:foregroundServiceType="phoneCall|microphone" />
</application>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.wire.android.R
import com.wire.android.appLogger
import com.wire.android.util.dispatchers.DispatcherProvider
import com.wire.kalium.logic.data.call.Call
import com.wire.kalium.logic.data.call.CallStatus
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.QualifiedID
Expand Down Expand Up @@ -62,7 +63,6 @@ class CallNotificationManager @Inject constructor(
private val notificationManager = NotificationManagerCompat.from(context)
private val scope = CoroutineScope(SupervisorJob() + dispatcherProvider.default())
private val incomingCallsForUsers = MutableStateFlow<Map<UserId, Call>>(mapOf())
private val outgoingCallForUsers = MutableStateFlow<Map<UserId, Call>>(mapOf())
private val reloadCallNotification = MutableSharedFlow<CallNotificationIds>()

init {
Expand All @@ -81,25 +81,6 @@ class CallNotificationManager @Inject constructor(
}
}
}
scope.launch {
outgoingCallForUsers
.map { it.entries.firstOrNull()?.toCallNotificationData() }
.distinctUntilChanged()
.reloadIfNeeded()
.collectLatest { outgoingCallData ->
if (outgoingCallData == null) {
hideOutgoingCallNotification()
} else {
appLogger.i("$TAG: showing outgoing call")
showOutgoingCallNotification(
outgoingCallData.copy(
conversationName = outgoingCallData.conversationName
?: context.getString(R.string.username_unavailable_label)
)
)
}
}
}
}

fun reloadIfNeeded(data: CallNotificationData): Flow<CallNotificationData> = reloadCallNotification
Expand All @@ -126,14 +107,6 @@ class CallNotificationManager @Inject constructor(
}
}

fun handleOutgoingCallNotifications(calls: List<Call>, userId: UserId) {
if (calls.isEmpty()) {
outgoingCallForUsers.update { it.filter { it.key != userId } }
} else {
outgoingCallForUsers.update { it.filter { it.key != userId } + (userId to calls.first()) }
}
}

fun hideAllNotifications() {
hideIncomingCallNotification()
}
Expand All @@ -149,11 +122,6 @@ class CallNotificationManager @Inject constructor(
notificationManager.cancel(NotificationIds.CALL_INCOMING_NOTIFICATION_ID.ordinal)
}

private fun hideOutgoingCallNotification() {
appLogger.i("$TAG: hiding outgoing call")
notificationManager.cancel(NotificationIds.CALL_OUTGOING_NOTIFICATION_ID.ordinal)
}

@SuppressLint("MissingPermission")
@VisibleForTesting
internal fun showIncomingCallNotification(data: CallNotificationData) {
Expand All @@ -165,17 +133,6 @@ class CallNotificationManager @Inject constructor(
)
}

@SuppressLint("MissingPermission")
@VisibleForTesting
internal fun showOutgoingCallNotification(data: CallNotificationData) {
appLogger.i("$TAG: showing outgoing call notification for user ${data.userId.toLogString()}")
val notification = builder.getOutgoingCallNotification(data)
notificationManager.notify(
NotificationIds.CALL_OUTGOING_NOTIFICATION_ID.ordinal,
notification
)
}

// Notifications

companion object {
Expand All @@ -199,7 +156,7 @@ class CallNotificationBuilder @Inject constructor(
fun getOutgoingCallNotification(data: CallNotificationData): Notification {
val userIdString = data.userId.toString()
val conversationIdString = data.conversationId.toString()
val channelId = NotificationConstants.getIncomingChannelId(data.userId)
val channelId = NotificationConstants.getOutgoingChannelId(data.userId)

return NotificationCompat.Builder(context, channelId)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
Expand Down Expand Up @@ -263,6 +220,7 @@ class CallNotificationBuilder @Inject constructor(
.setSmallIcon(R.drawable.notification_icon_small)
.setAutoCancel(true)
.setOngoing(true)
.setUsesChronometer(true)
.addAction(getHangUpCallAction(context, conversationIdString, userIdString))
.addAction(getOpenOngoingCallAction(context, conversationIdString))
.setFullScreenIntent(openOngoingCallPendingIntent(context, conversationIdString), true)
Expand All @@ -272,15 +230,15 @@ class CallNotificationBuilder @Inject constructor(
}

/**
* @return placeholder Notification for OngoingCall, that can be shown immediately after starting the Service
* @return placeholder Notification for CallService, that can be shown immediately after starting the Service
* (e.g. in [android.app.Service.onCreate]). It has no any [NotificationCompat.Action], on click - just opens the app.
* This notification should be replace by the user-specific notification (with corresponding [NotificationCompat.Action],
* [android.content.Intent] and title) once it's possible (e.g. in [android.app.Service.onStartCommand])
*/
fun getOngoingCallPlaceholderNotification(): Notification {
fun getCallServicePlaceholderNotification(): Notification {
val channelId = NotificationConstants.ONGOING_CALL_CHANNEL_ID
return NotificationCompat.Builder(context, channelId)
.setContentText(context.getString(R.string.notification_ongoing_call_content))
.setContentText(context.getString(R.string.notification_outgoing_call_tap_to_return))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
Expand Down Expand Up @@ -326,6 +284,7 @@ data class CallNotificationData(
val conversationType: Conversation.Type,
val callerName: String?,
val callerTeamName: String?,
val callStatus: CallStatus
) {
constructor(userId: UserId, call: Call) : this(
userId,
Expand All @@ -334,6 +293,7 @@ data class CallNotificationData(
call.conversationType,
call.callerName,
call.callerTeamName,
call.status
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ object NotificationConstants {
// Notification IDs (has to be unique!)
enum class NotificationIds {
CALL_INCOMING_NOTIFICATION_ID,
CALL_OUTGOING_NOTIFICATION_ID,
CALL_ONGOING_NOTIFICATION_ID,
CALL_OUTGOING_ONGOING_NOTIFICATION_ID,
PERSISTENT_NOTIFICATION_ID,
MESSAGE_SYNC_NOTIFICATION_ID,
MIGRATION_NOTIFICATION_ID,
Expand Down
Loading
Loading