Fix coroutine scope (#4820)
* Inject the session scope instead of the application scope where it's possible. * Create AppCoroutineScope annotation to let developers explicitly choose the appropriate CoroutineScope when injecting one.
This commit is contained in:
parent
36c7c7ab9b
commit
5f191d9f9c
58 changed files with 172 additions and 72 deletions
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.di.annotations
|
||||
|
||||
import javax.inject.Qualifier
|
||||
|
||||
/**
|
||||
* Qualifies a [CoroutineScope] object which represents the base coroutine scope to use for the application.
|
||||
*/
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MustBeDocumented
|
||||
@Qualifier
|
||||
annotation class AppCoroutineScope
|
||||
|
|
@ -9,6 +9,7 @@ package io.element.android.libraries.matrix.impl
|
|||
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.di.CacheDirectory
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.impl.analytics.UtdTracker
|
||||
|
|
@ -40,6 +41,7 @@ import javax.inject.Inject
|
|||
class RustMatrixClientFactory @Inject constructor(
|
||||
private val baseDirectory: File,
|
||||
@CacheDirectory private val cacheDirectory: File,
|
||||
@AppCoroutineScope
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
private val coroutineDispatchers: CoroutineDispatchers,
|
||||
private val sessionStore: SessionStore,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.audio.api.AudioFocus
|
|||
import io.element.android.libraries.audio.api.AudioFocusRequester
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.mediaplayer.api.MediaPlayer
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
|
|
@ -37,7 +38,8 @@ import kotlin.time.Duration.Companion.seconds
|
|||
@SingleIn(RoomScope::class)
|
||||
class DefaultMediaPlayer @Inject constructor(
|
||||
private val player: SimplePlayer,
|
||||
private val coroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val audioFocus: AudioFocus,
|
||||
) : MediaPlayer {
|
||||
private val listener = object : SimplePlayer.Listener {
|
||||
|
|
@ -50,7 +52,7 @@ class DefaultMediaPlayer @Inject constructor(
|
|||
)
|
||||
}
|
||||
if (isPlaying) {
|
||||
job = coroutineScope.launch { updateCurrentPosition() }
|
||||
job = sessionCoroutineScope.launch { updateCurrentPosition() }
|
||||
} else {
|
||||
audioFocus.releaseAudioFocus()
|
||||
job?.cancel()
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ class DefaultMediaPlayerTest {
|
|||
audioFocus: AudioFocus = FakeAudioFocus(),
|
||||
): DefaultMediaPlayer = DefaultMediaPlayer(
|
||||
player = simplePlayer,
|
||||
coroutineScope = backgroundScope,
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
audioFocus = audioFocus,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import io.element.android.libraries.core.data.tryOrNull
|
|||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
|
|
@ -48,6 +49,7 @@ class DefaultNotificationDrawerManager @Inject constructor(
|
|||
private val notificationManager: NotificationManagerCompat,
|
||||
private val notificationRenderer: NotificationRenderer,
|
||||
private val appNavigationStateService: AppNavigationStateService,
|
||||
@AppCoroutineScope
|
||||
coroutineScope: CoroutineScope,
|
||||
private val matrixClientProvider: MatrixClientProvider,
|
||||
private val imageLoaderHolder: ImageLoaderHolder,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ package io.element.android.libraries.push.impl.notifications
|
|||
|
||||
import android.content.Intent
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClientProvider
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
@ -36,6 +37,7 @@ import javax.inject.Inject
|
|||
private val loggerTag = LoggerTag("NotificationBroadcastReceiverHandler", LoggerTag.NotificationLoggerTag)
|
||||
|
||||
class NotificationBroadcastReceiverHandler @Inject constructor(
|
||||
@AppCoroutineScope
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
private val matrixClientProvider: MatrixClientProvider,
|
||||
private val sessionPreferencesStore: SessionPreferencesStoreFactory,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ package io.element.android.libraries.push.impl.notifications
|
|||
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
|
|
@ -34,6 +35,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
|||
@SingleIn(AppScope::class)
|
||||
class NotificationResolverQueue @Inject constructor(
|
||||
private val notifiableEventResolver: NotifiableEventResolver,
|
||||
@AppCoroutineScope
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
) {
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import io.element.android.libraries.core.log.logger.LoggerTag
|
|||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.push.impl.history.PushHistoryService
|
||||
import io.element.android.libraries.push.impl.history.onDiagnosticPush
|
||||
|
|
@ -58,6 +59,7 @@ class DefaultPushHandler @Inject constructor(
|
|||
private val notificationChannels: NotificationChannels,
|
||||
private val pushHistoryService: PushHistoryService,
|
||||
private val resolverQueue: NotificationResolverQueue,
|
||||
@AppCoroutineScope
|
||||
private val appCoroutineScope: CoroutineScope,
|
||||
) : PushHandler {
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ package io.element.android.libraries.push.impl.push
|
|||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.push.impl.notifications.DefaultNotificationDrawerManager
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableRingingCallEvent
|
||||
|
|
@ -23,6 +24,7 @@ interface OnNotifiableEventReceived {
|
|||
@ContributesBinding(AppScope::class)
|
||||
class DefaultOnNotifiableEventReceived @Inject constructor(
|
||||
private val defaultNotificationDrawerManager: DefaultNotificationDrawerManager,
|
||||
@AppCoroutineScope
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val syncOnNotifiableEvent: SyncOnNotifiableEvent,
|
||||
) : OnNotifiableEventReceived {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import androidx.core.text.inSpans
|
|||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.push.impl.notifications.ActiveNotificationsProvider
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationDisplayer
|
||||
import io.element.android.libraries.push.impl.notifications.factories.DefaultNotificationCreator
|
||||
|
|
@ -36,6 +37,7 @@ interface OnRedactedEventReceived {
|
|||
class DefaultOnRedactedEventReceived @Inject constructor(
|
||||
private val activeNotificationsProvider: ActiveNotificationsProvider,
|
||||
private val notificationDisplayer: NotificationDisplayer,
|
||||
@AppCoroutineScope
|
||||
private val coroutineScope: CoroutineScope,
|
||||
@ApplicationContext private val context: Context,
|
||||
private val stringProvider: StringProvider,
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.google.firebase.messaging.FirebaseMessagingService
|
|||
import com.google.firebase.messaging.RemoteMessage
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.pushproviders.api.PushHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -23,6 +24,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
|||
@Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler
|
||||
@Inject lateinit var pushParser: FirebasePushParser
|
||||
@Inject lateinit var pushHandler: PushHandler
|
||||
@AppCoroutineScope
|
||||
@Inject lateinit var coroutineScope: CoroutineScope
|
||||
|
||||
override fun onCreate() {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.pushproviders.api.PushHandler
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult
|
||||
|
|
@ -34,6 +35,7 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
|||
@Inject lateinit var unifiedPushGatewayUrlResolver: UnifiedPushGatewayUrlResolver
|
||||
@Inject lateinit var newGatewayHandler: UnifiedPushNewGatewayHandler
|
||||
@Inject lateinit var endpointRegistrationHandler: EndpointRegistrationHandler
|
||||
@AppCoroutineScope
|
||||
@Inject lateinit var coroutineScope: CoroutineScope
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import com.squareup.anvil.annotations.ContributesBinding
|
|||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
|
||||
|
|
@ -28,6 +29,7 @@ import javax.inject.Inject
|
|||
@ContributesBinding(AppScope::class)
|
||||
class DefaultSessionObserver @Inject constructor(
|
||||
private val sessionStore: SessionStore,
|
||||
@AppCoroutineScope
|
||||
private val coroutineScope: CoroutineScope,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : SessionObserver {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.libraries.voiceplayer.impl
|
|||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.voiceplayer.api.VoiceMessagePresenterFactory
|
||||
|
|
@ -22,7 +23,8 @@ import kotlin.time.Duration
|
|||
@ContributesBinding(RoomScope::class)
|
||||
class DefaultVoiceMessagePresenterFactory @Inject constructor(
|
||||
private val analyticsService: AnalyticsService,
|
||||
private val scope: CoroutineScope,
|
||||
@SessionCoroutineScope
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val voiceMessagePlayerFactory: VoiceMessagePlayer.Factory,
|
||||
) : VoiceMessagePresenterFactory {
|
||||
override fun createVoiceMessagePresenter(
|
||||
|
|
@ -41,7 +43,7 @@ class DefaultVoiceMessagePresenterFactory @Inject constructor(
|
|||
|
||||
return VoiceMessagePresenter(
|
||||
analyticsService = analyticsService,
|
||||
scope = scope,
|
||||
sessionCoroutineScope = sessionCoroutineScope,
|
||||
player = player,
|
||||
eventId = eventId,
|
||||
duration = duration,
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ import kotlin.time.Duration.Companion.milliseconds
|
|||
|
||||
class VoiceMessagePresenter(
|
||||
private val analyticsService: AnalyticsService,
|
||||
private val scope: CoroutineScope,
|
||||
private val sessionCoroutineScope: CoroutineScope,
|
||||
private val player: VoiceMessagePlayer,
|
||||
private val eventId: EventId?,
|
||||
private val duration: Duration,
|
||||
|
|
@ -92,7 +92,7 @@ class VoiceMessagePresenter(
|
|||
} else if (playerState.isReady) {
|
||||
player.play()
|
||||
} else {
|
||||
scope.launch {
|
||||
sessionCoroutineScope.launch {
|
||||
play.runUpdatingState(
|
||||
errorTransform = {
|
||||
analyticsService.trackError(
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ fun TestScope.createVoiceMessagePresenter(
|
|||
mediaSource: MediaSource = MediaSource(contentUri),
|
||||
) = VoiceMessagePresenter(
|
||||
analyticsService = analyticsService,
|
||||
scope = this,
|
||||
sessionCoroutineScope = this,
|
||||
player = DefaultVoiceMessagePlayer(
|
||||
mediaPlayer = mediaPlayer,
|
||||
voiceMessageMediaRepoFactory = { _, _, _ -> voiceMessageMediaRepo },
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
|||
import io.element.android.libraries.core.coroutine.childScope
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.di.annotations.SessionCoroutineScope
|
||||
import io.element.android.libraries.voicerecorder.api.VoiceRecorder
|
||||
import io.element.android.libraries.voicerecorder.api.VoiceRecorderState
|
||||
import io.element.android.libraries.voicerecorder.impl.audio.Audio
|
||||
|
|
@ -51,10 +52,11 @@ class DefaultVoiceRecorder @Inject constructor(
|
|||
private val config: AudioConfig,
|
||||
private val fileConfig: VoiceFileConfig,
|
||||
private val audioLevelCalculator: AudioLevelCalculator,
|
||||
appCoroutineScope: CoroutineScope,
|
||||
@SessionCoroutineScope
|
||||
sessionCoroutineScope: CoroutineScope,
|
||||
) : VoiceRecorder {
|
||||
private val voiceCoroutineScope by lazy {
|
||||
appCoroutineScope.childScope(dispatchers.io, "VoiceRecorder-${UUID.randomUUID()}")
|
||||
sessionCoroutineScope.childScope(dispatchers.io, "VoiceRecorder-${UUID.randomUUID()}")
|
||||
}
|
||||
|
||||
private var outputFile: File? = null
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ class DefaultVoiceRecorderTest {
|
|||
fileConfig = fileConfig,
|
||||
fileManager = FakeVoiceFileManager(fakeFileSystem, fileConfig, FILE_ID),
|
||||
audioLevelCalculator = FakeAudioLevelCalculator(),
|
||||
appCoroutineScope = backgroundScope,
|
||||
sessionCoroutineScope = backgroundScope,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue