Inject WorkManagerProvider, to avoid injecting the Android context

Also ensure WorkManager uses a distinct tags for each session (for future multi-sessions support)
This commit is contained in:
Benoit Marty 2020-01-14 15:06:19 +01:00 committed by Valere
parent 4543658ae0
commit 494ad83704
12 changed files with 182 additions and 169 deletions

View File

@ -15,7 +15,6 @@
*/
package im.vector.matrix.android.internal.crypto.verification
import android.content.Context
import androidx.lifecycle.Observer
import androidx.work.*
import com.zhuinden.monarchy.Monarchy
@ -29,8 +28,9 @@ import im.vector.matrix.android.internal.crypto.model.rest.KeyVerificationStart
import im.vector.matrix.android.internal.di.DeviceId
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.util.StringProvider
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@ -41,7 +41,8 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class SasTransportRoomMessage(
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
private val stringProvider: StringProvider,
private val sessionId: String,
private val userId: String,
private val userDeviceId: String?,
@ -88,7 +89,8 @@ internal class SasTransportRoomMessage(
// }
// }, listenerExecutor)
val workLiveData = WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
val workLiveData = workManagerProvider.workManager
.getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
val observer = object : Observer<List<WorkInfo>> {
override fun onChanged(workInfoList: List<WorkInfo>?) {
@ -122,7 +124,7 @@ internal class SasTransportRoomMessage(
roomId: String,
callback: (String?, MessageVerificationRequestContent?) -> Unit) {
val info = MessageVerificationRequestContent(
body = context.getString(R.string.key_verification_request_fallback_message, userId),
body = stringProvider.getString(R.string.key_verification_request_fallback_message, userId),
fromDevice = userDeviceId ?: "",
toUserId = otherUserId,
methods = listOf(KeyVerificationStart.VERIF_METHOD_SAS)
@ -141,20 +143,21 @@ internal class SasTransportRoomMessage(
event = event
))
val workRequest = WorkManagerUtil.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(workerParams)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance(context)
workManagerProvider.workManager
.beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND, workRequest)
.enqueue()
// I cannot just listen to the given work request, because when used in a uniqueWork,
// The callback is called while it is still Running ...
val workLiveData = WorkManager.getInstance(context).getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
val workLiveData = workManagerProvider.workManager
.getWorkInfosForUniqueWorkLiveData("${roomId}_VerificationWork")
val observer = object : Observer<List<WorkInfo>> {
override fun onChanged(workInfoList: List<WorkInfo>?) {
@ -213,12 +216,12 @@ internal class SasTransportRoomMessage(
}
private fun enqueueSendWork(workerParams: Data): Pair<Operation, UUID> {
val workRequest = WorkManagerUtil.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SendVerificationMessageWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(workerParams)
.setBackoffCriteria(BackoffPolicy.LINEAR, 2_000L, TimeUnit.MILLISECONDS)
.build()
return WorkManager.getInstance(context)
return workManagerProvider.workManager
.beginUniqueWork("${roomId}_VerificationWork", ExistingWorkPolicy.APPEND, workRequest)
.enqueue() to workRequest.id
}
@ -290,7 +293,8 @@ internal class SasTransportRoomMessage(
}
internal class SasTransportRoomMessageFactory @Inject constructor(
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
private val stringProvider: StringProvider,
private val monarchy: Monarchy,
@SessionId
private val sessionId: String,
@ -301,6 +305,6 @@ internal class SasTransportRoomMessageFactory @Inject constructor(
private val localEchoEventFactory: LocalEchoEventFactory) {
fun createTransport(roomId: String, tx: SASVerificationTransaction?): SasTransportRoomMessage {
return SasTransportRoomMessage(context, sessionId, userId, deviceId, roomId, monarchy, localEchoEventFactory, tx)
return SasTransportRoomMessage(workManagerProvider, stringProvider, sessionId, userId, deviceId, roomId, monarchy, localEchoEventFactory, tx)
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.di
import android.content.Context
import androidx.work.*
import javax.inject.Inject
internal class WorkManagerProvider @Inject constructor(
context: Context,
@SessionId private val sessionId: String
) {
private val tag = MATRIX_SDK_TAG_PREFIX + sessionId
val workManager = WorkManager.getInstance(context)
/**
* Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
*/
inline fun <reified W : ListenableWorker> matrixOneTimeWorkRequestBuilder() =
OneTimeWorkRequestBuilder<W>()
.addTag(tag)
/**
* Cancel all works instantiated by the Matrix SDK for the current session, and not those from the SDK client, or for other sessions
*/
fun cancelAllWorks() {
workManager.let {
it.cancelAllWorkByTag(tag)
it.pruneWork()
}
}
companion object {
private const val MATRIX_SDK_TAG_PREFIX = "MatrixSDK-"
/**
* Default constraints: connected network
*/
val workConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
}
}

View File

@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.session
import android.content.Context
import androidx.annotation.MainThread
import androidx.lifecycle.LiveData
import dagger.Lazy
@ -46,6 +45,7 @@ import im.vector.matrix.android.internal.auth.SessionParamsStore
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
import im.vector.matrix.android.internal.database.LiveEntityObserver
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.sync.SyncTaskSequencer
import im.vector.matrix.android.internal.session.sync.SyncTokenStore
import im.vector.matrix.android.internal.session.sync.job.SyncThread
@ -63,7 +63,7 @@ import javax.inject.Provider
@SessionScope
internal class DefaultSession @Inject constructor(
override val sessionParams: SessionParams,
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
private val eventBus: EventBus,
@SessionId
override val sessionId: String,
@ -122,15 +122,15 @@ internal class DefaultSession @Inject constructor(
}
override fun requireBackgroundSync() {
SyncWorker.requireBackgroundSync(context, sessionId)
SyncWorker.requireBackgroundSync(workManagerProvider, sessionId)
}
override fun startAutomaticBackgroundSync(repeatDelay: Long) {
SyncWorker.automaticallyBackgroundSync(context, sessionId, 0, repeatDelay)
SyncWorker.automaticallyBackgroundSync(workManagerProvider, sessionId, 0, repeatDelay)
}
override fun stopAnyBackgroundSync() {
SyncWorker.stopAnyBackgroundSync(context)
SyncWorker.stopAnyBackgroundSync(workManagerProvider)
}
override fun startSync(fromForeground: Boolean) {

View File

@ -16,9 +16,7 @@
package im.vector.matrix.android.internal.session.group
import android.content.Context
import androidx.work.ExistingWorkPolicy
import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.internal.database.RealmLiveEntityObserver
@ -27,8 +25,7 @@ import im.vector.matrix.android.internal.database.model.GroupEntity
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import io.realm.OrderedCollectionChangeSet
import io.realm.RealmResults
@ -38,7 +35,7 @@ import javax.inject.Inject
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
internal class GroupSummaryUpdater @Inject constructor(
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
@SessionId private val sessionId: String,
private val monarchy: Monarchy)
: RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) {
@ -72,12 +69,12 @@ internal class GroupSummaryUpdater @Inject constructor(
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
val sendWork = matrixOneTimeWorkRequestBuilder<GetGroupDataWorker>()
val sendWork = workManagerProvider.matrixOneTimeWorkRequestBuilder<GetGroupDataWorker>()
.setInputData(workData)
.setConstraints(WorkManagerUtil.workConstraints)
.setConstraints(WorkManagerProvider.workConstraints)
.build()
WorkManager.getInstance(context)
workManagerProvider.workManager
.beginUniqueWork(GET_GROUP_DATA_WORKER, ExistingWorkPolicy.APPEND, sendWork)
.enqueue()
}

View File

@ -15,10 +15,8 @@
*/
package im.vector.matrix.android.internal.session.pushers
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.work.BackoffPolicy
import androidx.work.WorkManager
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.pushers.Pusher
@ -27,17 +25,16 @@ import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
internal class DefaultPusherService @Inject constructor(
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
private val monarchy: Monarchy,
@SessionId private val sessionId: String,
private val getPusherTask: GetPushersTask,
@ -68,12 +65,12 @@ internal class DefaultPusherService @Inject constructor(
val params = AddHttpPusherWorker.Params(sessionId, pusher)
val request = matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
val request = workManagerProvider.matrixOneTimeWorkRequestBuilder<AddHttpPusherWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(WorkerParamsFactory.toData(params))
.setBackoffCriteria(BackoffPolicy.LINEAR, 10_000L, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance(context).enqueue(request)
workManagerProvider.workManager.enqueue(request)
return request.id
}

View File

@ -15,7 +15,6 @@
*/
package im.vector.matrix.android.internal.session.room.relation
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import androidx.work.OneTimeWorkRequest
@ -39,6 +38,7 @@ import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryE
import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.room.send.EncryptEventWorker
import im.vector.matrix.android.internal.session.room.send.LocalEchoEventFactory
import im.vector.matrix.android.internal.session.room.send.RedactEventWorker
@ -53,8 +53,9 @@ import timber.log.Timber
internal class DefaultRelationService @AssistedInject constructor(
@Assisted private val roomId: String,
private val context: Context,
@SessionId private val sessionId: String,
private val workManagerProvider: WorkManagerProvider,
private val timeLineEveSendEventWorkCommon: TimelineSendEventWorkCommon,
private val eventFactory: LocalEchoEventFactory,
private val cryptoService: CryptoService,
private val findReactionEventForUndoTask: FindReactionEventForUndoTask,
@ -85,8 +86,8 @@ internal class DefaultRelationService @AssistedInject constructor(
val event = eventFactory.createReactionEvent(roomId, targetEventId, reaction)
.also { saveLocalEcho(it) }
val sendRelationWork = createSendEventWork(event, true)
TimelineSendEventWorkCommon.postWork(context, roomId, sendRelationWork)
CancelableWork(context, sendRelationWork.id)
timeLineEveSendEventWorkCommon.postWork(roomId, sendRelationWork)
CancelableWork(workManagerProvider.workManager, sendRelationWork.id)
} else {
Timber.w("Reaction already added")
NoOpCancellable
@ -111,7 +112,7 @@ internal class DefaultRelationService @AssistedInject constructor(
.also { saveLocalEcho(it) }
val redactWork = createRedactEventWork(redactEvent, toRedact, null)
TimelineSendEventWorkCommon.postWork(context, roomId, redactWork)
timeLineEveSendEventWorkCommon.postWork(roomId, redactWork)
}
}
}
@ -132,7 +133,7 @@ internal class DefaultRelationService @AssistedInject constructor(
eventId,
reason)
val redactWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
return TimelineSendEventWorkCommon.createWork<RedactEventWorker>(redactWorkData, true)
return timeLineEveSendEventWorkCommon.createWork<RedactEventWorker>(redactWorkData, true)
}
override fun editTextMessage(targetEventId: String,
@ -146,12 +147,12 @@ internal class DefaultRelationService @AssistedInject constructor(
return if (cryptoService.isRoomEncrypted(roomId)) {
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
val workRequest = createSendEventWork(event, false)
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
CancelableWork(context, encryptWork.id)
timeLineEveSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, workRequest)
CancelableWork(workManagerProvider.workManager, encryptWork.id)
} else {
val workRequest = createSendEventWork(event, true)
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
CancelableWork(context, workRequest.id)
timeLineEveSendEventWorkCommon.postWork(roomId, workRequest)
CancelableWork(workManagerProvider.workManager, workRequest.id)
}
}
@ -168,12 +169,12 @@ internal class DefaultRelationService @AssistedInject constructor(
return if (cryptoService.isRoomEncrypted(roomId)) {
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
val workRequest = createSendEventWork(event, false)
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
CancelableWork(context, encryptWork.id)
timeLineEveSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, workRequest)
CancelableWork(workManagerProvider.workManager, encryptWork.id)
} else {
val workRequest = createSendEventWork(event, true)
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
CancelableWork(context, workRequest.id)
timeLineEveSendEventWorkCommon.postWork(roomId, workRequest)
CancelableWork(workManagerProvider.workManager, workRequest.id)
}
}
@ -194,12 +195,12 @@ internal class DefaultRelationService @AssistedInject constructor(
return if (cryptoService.isRoomEncrypted(roomId)) {
val encryptWork = createEncryptEventWork(event, listOf("m.relates_to"))
val workRequest = createSendEventWork(event, false)
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, workRequest)
CancelableWork(context, encryptWork.id)
timeLineEveSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, workRequest)
CancelableWork(workManagerProvider.workManager, encryptWork.id)
} else {
val workRequest = createSendEventWork(event, true)
TimelineSendEventWorkCommon.postWork(context, roomId, workRequest)
CancelableWork(context, workRequest.id)
timeLineEveSendEventWorkCommon.postWork(roomId, workRequest)
CancelableWork(workManagerProvider.workManager, workRequest.id)
}
}
@ -207,13 +208,13 @@ internal class DefaultRelationService @AssistedInject constructor(
// Same parameter
val params = EncryptEventWorker.Params(sessionId, roomId, event, keepKeys)
val sendWorkData = WorkerParamsFactory.toData(params)
return TimelineSendEventWorkCommon.createWork<EncryptEventWorker>(sendWorkData, true)
return timeLineEveSendEventWorkCommon.createWork<EncryptEventWorker>(sendWorkData, true)
}
private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest {
val sendContentWorkerParams = SendEventWorker.Params(sessionId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
return timeLineEveSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
}
override fun getEventAnnotationsSummary(eventId: String): EventAnnotationsSummary? {

View File

@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.session.room.send
import android.content.Context
import androidx.work.*
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
@ -38,12 +37,11 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity
import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.di.SessionId
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.session.content.UploadContentWorker
import im.vector.matrix.android.internal.session.room.timeline.TimelineSendEventWorkCommon
import im.vector.matrix.android.internal.util.CancelableWork
import im.vector.matrix.android.internal.worker.AlwaysSuccessfulWorker
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.startChain
import timber.log.Timber
@ -55,7 +53,8 @@ private const val BACKOFF_DELAY = 10_000L
internal class DefaultSendService @AssistedInject constructor(
@Assisted private val roomId: String,
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
private val timelineSendEventWorkCommon: TimelineSendEventWorkCommon,
@SessionId private val sessionId: String,
private val localEchoEventFactory: LocalEchoEventFactory,
private val cryptoService: CryptoService,
@ -91,12 +90,12 @@ internal class DefaultSendService @AssistedInject constructor(
Timber.v("Send event in encrypted room")
val encryptWork = createEncryptEventWork(event, true)
val sendWork = createSendEventWork(event, false)
TimelineSendEventWorkCommon.postSequentialWorks(context, roomId, encryptWork, sendWork)
CancelableWork(context, encryptWork.id)
timelineSendEventWorkCommon.postSequentialWorks(roomId, encryptWork, sendWork)
CancelableWork(workManagerProvider.workManager, encryptWork.id)
} else {
val sendWork = createSendEventWork(event, true)
TimelineSendEventWorkCommon.postWork(context, roomId, sendWork)
CancelableWork(context, sendWork.id)
timelineSendEventWorkCommon.postWork(roomId, sendWork)
CancelableWork(workManagerProvider.workManager, sendWork.id)
}
}
@ -109,8 +108,8 @@ internal class DefaultSendService @AssistedInject constructor(
override fun redactEvent(event: Event, reason: String?): Cancelable {
// TODO manage media/attachements?
val redactWork = createRedactEventWork(event, reason)
TimelineSendEventWorkCommon.postWork(context, roomId, redactWork)
return CancelableWork(context, redactWork.id)
timelineSendEventWorkCommon.postWork(roomId, redactWork)
return CancelableWork(workManagerProvider.workManager, redactWork.id)
}
override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? {
@ -168,16 +167,16 @@ internal class DefaultSendService @AssistedInject constructor(
}
override fun clearSendingQueue() {
TimelineSendEventWorkCommon.cancelAllWorks(context, roomId)
WorkManager.getInstance(context).cancelUniqueWork(buildWorkName(UPLOAD_WORK))
timelineSendEventWorkCommon.cancelAllWorks(roomId)
workManagerProvider.workManager.cancelUniqueWork(buildWorkName(UPLOAD_WORK))
// Replace the worker chains with a AlwaysSuccessfulWorker, to ensure the queues are well emptied
matrixOneTimeWorkRequestBuilder<AlwaysSuccessfulWorker>()
workManagerProvider.matrixOneTimeWorkRequestBuilder<AlwaysSuccessfulWorker>()
.build().let {
TimelineSendEventWorkCommon.postWork(context, roomId, it, ExistingWorkPolicy.REPLACE)
timelineSendEventWorkCommon.postWork(roomId, it, ExistingWorkPolicy.REPLACE)
// need to clear also image sending queue
WorkManager.getInstance(context)
workManagerProvider.workManager
.beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.REPLACE, it)
.enqueue()
}
@ -254,7 +253,7 @@ internal class DefaultSendService @AssistedInject constructor(
if (isRoomEncrypted) {
val encryptWork = createEncryptEventWork(localEcho, false /*not start of chain, take input error*/)
val op: Operation = WorkManager.getInstance(context)
val op: Operation = workManagerProvider.workManager
.beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.APPEND, uploadWork)
.then(encryptWork)
.then(sendWork)
@ -267,13 +266,13 @@ internal class DefaultSendService @AssistedInject constructor(
}
}, workerFutureListenerExecutor)
} else {
WorkManager.getInstance(context)
workManagerProvider.workManager
.beginUniqueWork(buildWorkName(UPLOAD_WORK), ExistingWorkPolicy.APPEND, uploadWork)
.then(sendWork)
.enqueue()
}
return CancelableWork(context, sendWork.id)
return CancelableWork(workManagerProvider.workManager, sendWork.id)
}
private fun saveLocalEcho(event: Event) {
@ -289,8 +288,8 @@ internal class DefaultSendService @AssistedInject constructor(
val params = EncryptEventWorker.Params(sessionId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(params)
return matrixOneTimeWorkRequestBuilder<EncryptEventWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
return workManagerProvider.matrixOneTimeWorkRequestBuilder<EncryptEventWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(sendWorkData)
.startChain(startChain)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
@ -301,7 +300,7 @@ internal class DefaultSendService @AssistedInject constructor(
val sendContentWorkerParams = SendEventWorker.Params(sessionId, roomId, event)
val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
return TimelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
return timelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain)
}
private fun createRedactEventWork(event: Event, reason: String?): OneTimeWorkRequest {
@ -310,7 +309,7 @@ internal class DefaultSendService @AssistedInject constructor(
}
val sendContentWorkerParams = RedactEventWorker.Params(sessionId, redactEvent.eventId!!, roomId, event.eventId, reason)
val redactWorkData = WorkerParamsFactory.toData(sendContentWorkerParams)
return TimelineSendEventWorkCommon.createWork<RedactEventWorker>(redactWorkData, true)
return timelineSendEventWorkCommon.createWork<RedactEventWorker>(redactWorkData, true)
}
private fun createUploadMediaWork(event: Event,
@ -320,8 +319,8 @@ internal class DefaultSendService @AssistedInject constructor(
val uploadMediaWorkerParams = UploadContentWorker.Params(sessionId, roomId, event, attachment, isRoomEncrypted)
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)
return matrixOneTimeWorkRequestBuilder<UploadContentWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
return workManagerProvider.matrixOneTimeWorkRequestBuilder<UploadContentWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.startChain(startChain)
.setInputData(uploadWorkData)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)

View File

@ -15,32 +15,30 @@
*/
package im.vector.matrix.android.internal.session.room.timeline
import android.content.Context
import androidx.work.*
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.worker.startChain
import java.util.concurrent.TimeUnit
private const val SEND_WORK = "SEND_WORK"
private const val BACKOFF_DELAY = 10_000L
import javax.inject.Inject
/**
* Helper class for sending event related works.
* All send event from a room are using the same workchain, in order to ensure order.
* WorkRequest must always return success (even if server error, in this case marking the event as failed to send)
* , if not the chain will be doomed in failed state.
*
* WorkRequest must always return success (even if server error, in this case marking the event as failed to send),
* if not the chain will be doomed in failed state.
*/
internal object TimelineSendEventWorkCommon {
internal class TimelineSendEventWorkCommon @Inject constructor(
// TODO @Assisted private val roomId: String,
private val workManagerProvider: WorkManagerProvider
) {
fun postSequentialWorks(context: Context, roomId: String, vararg workRequests: OneTimeWorkRequest) {
fun postSequentialWorks(roomId: String, vararg workRequests: OneTimeWorkRequest) {
when {
workRequests.isEmpty() -> return
workRequests.size == 1 -> postWork(context, roomId, workRequests.first())
workRequests.size == 1 -> postWork(roomId, workRequests.first())
else -> {
val firstWork = workRequests.first()
var continuation = WorkManager.getInstance(context)
var continuation = workManagerProvider.workManager
.beginUniqueWork(buildWorkName(roomId), ExistingWorkPolicy.APPEND, firstWork)
for (i in 1 until workRequests.size) {
val workRequest = workRequests[i]
@ -51,15 +49,15 @@ internal object TimelineSendEventWorkCommon {
}
}
fun postWork(context: Context, roomId: String, workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND) {
WorkManager.getInstance(context)
fun postWork(roomId: String, workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND) {
workManagerProvider.workManager
.beginUniqueWork(buildWorkName(roomId), policy, workRequest)
.enqueue()
}
inline fun <reified W : ListenableWorker> createWork(data: Data, startChain: Boolean): OneTimeWorkRequest {
return matrixOneTimeWorkRequestBuilder<W>()
.setConstraints(WorkManagerUtil.workConstraints)
return workManagerProvider.matrixOneTimeWorkRequestBuilder<W>()
.setConstraints(WorkManagerProvider.workConstraints)
.startChain(startChain)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, BACKOFF_DELAY, TimeUnit.MILLISECONDS)
@ -70,7 +68,13 @@ internal object TimelineSendEventWorkCommon {
return "${roomId}_$SEND_WORK"
}
fun cancelAllWorks(context: Context, roomId: String) {
WorkManager.getInstance(context).cancelUniqueWork(buildWorkName(roomId))
fun cancelAllWorks(roomId: String) {
workManagerProvider.workManager
.cancelUniqueWork(buildWorkName(roomId))
}
companion object {
private const val SEND_WORK = "SEND_WORK"
private const val BACKOFF_DELAY = 10_000L
}
}

View File

@ -16,7 +16,6 @@
package im.vector.matrix.android.internal.session.signout
import android.content.Context
import im.vector.matrix.android.BuildConfig
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.failure.MatrixError
@ -29,7 +28,6 @@ import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.SessionModule
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import io.realm.Realm
import io.realm.RealmConfiguration
import org.greenrobot.eventbus.EventBus
@ -45,7 +43,7 @@ internal interface SignOutTask : Task<SignOutTask.Params, Unit> {
}
internal class DefaultSignOutTask @Inject constructor(
private val context: Context,
private val workManagerProvider: WorkManagerProvider,
@SessionId private val sessionId: String,
private val signOutAPI: SignOutAPI,
private val sessionManager: SessionManager,
@ -87,7 +85,7 @@ internal class DefaultSignOutTask @Inject constructor(
sessionManager.releaseSession(sessionId)
Timber.d("SignOut: cancel pending works...")
WorkManagerUtil.cancelAllWorks(context)
workManagerProvider.cancelAllWorks()
Timber.d("SignOut: delete session params...")
sessionParamsStore.delete(sessionId)

View File

@ -16,15 +16,17 @@
package im.vector.matrix.android.internal.session.sync.job
import android.content.Context
import androidx.work.*
import androidx.work.BackoffPolicy
import androidx.work.CoroutineWorker
import androidx.work.ExistingWorkPolicy
import androidx.work.WorkerParameters
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.failure.isTokenError
import im.vector.matrix.android.internal.di.WorkManagerProvider
import im.vector.matrix.android.internal.network.NetworkConnectivityChecker
import im.vector.matrix.android.internal.session.sync.SyncTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.worker.SessionWorkerParams
import im.vector.matrix.android.internal.worker.WorkManagerUtil
import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.getSessionComponent
import timber.log.Timber
@ -75,30 +77,33 @@ internal class SyncWorker(context: Context,
companion object {
const val BG_SYNC_WORK_NAME = "BG_SYNCP"
private const val BG_SYNC_WORK_NAME = "BG_SYNCP"
fun requireBackgroundSync(context: Context, sessionId: String, serverTimeout: Long = 0) {
fun requireBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0) {
val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, false))
val workRequest = matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setBackoffCriteria(BackoffPolicy.LINEAR, 1_000, TimeUnit.MILLISECONDS)
.setInputData(data)
.build()
WorkManager.getInstance(context).enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
workManagerProvider.workManager
.enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
}
fun automaticallyBackgroundSync(context: Context, sessionId: String, serverTimeout: Long = 0, delay: Long = 30_000) {
fun automaticallyBackgroundSync(workManagerProvider: WorkManagerProvider, sessionId: String, serverTimeout: Long = 0, delay: Long = 30_000) {
val data = WorkerParamsFactory.toData(Params(sessionId, serverTimeout, true))
val workRequest = matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(WorkManagerUtil.workConstraints)
val workRequest = workManagerProvider.matrixOneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(WorkManagerProvider.workConstraints)
.setInputData(data)
.setBackoffCriteria(BackoffPolicy.LINEAR, delay, TimeUnit.MILLISECONDS)
.build()
WorkManager.getInstance(context).enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
workManagerProvider.workManager
.enqueueUniqueWork(BG_SYNC_WORK_NAME, ExistingWorkPolicy.REPLACE, workRequest)
}
fun stopAnyBackgroundSync(context: Context) {
WorkManager.getInstance(context).cancelUniqueWork(BG_SYNC_WORK_NAME)
fun stopAnyBackgroundSync(workManagerProvider: WorkManagerProvider) {
workManagerProvider.workManager
.cancelUniqueWork(BG_SYNC_WORK_NAME)
}
}
}

View File

@ -16,15 +16,14 @@
package im.vector.matrix.android.internal.util
import android.content.Context
import androidx.work.WorkManager
import im.vector.matrix.android.api.util.Cancelable
import java.util.UUID
import java.util.*
internal class CancelableWork(private val context: Context,
internal class CancelableWork(private val workManager: WorkManager,
private val workId: UUID) : Cancelable {
override fun cancel() {
WorkManager.getInstance(context).cancelWorkById(workId)
workManager.cancelWorkById(workId)
}
}

View File

@ -1,49 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.worker
import android.content.Context
import androidx.work.*
// TODO Multiaccount
internal object WorkManagerUtil {
private const val MATRIX_SDK_TAG = "MatrixSDK"
/**
* Default constraints: connected network
*/
val workConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
/**
* Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag
*/
inline fun <reified W : ListenableWorker> matrixOneTimeWorkRequestBuilder() =
OneTimeWorkRequestBuilder<W>()
.addTag(MATRIX_SDK_TAG)
/**
* Cancel all works instantiated by the Matrix SDK and not those from the SDK client
*/
fun cancelAllWorks(context: Context) {
WorkManager.getInstance(context).also {
it.cancelAllWorkByTag(MATRIX_SDK_TAG)
it.pruneWork()
}
}
}