From 30fe564a2cbdc34054e59c3493b9b00bbe38dd33 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 29 Nov 2021 19:13:38 +0100 Subject: [PATCH] Throw clear error when MatrixWorkerFactory is not set up on worker configuration --- .../sdk/internal/di/WorkManagerProvider.kt | 37 ++++++++++++++++++- .../internal/worker/MatrixWorkerFactory.kt | 27 +++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt index bafffdf852..7d004bc5c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/di/WorkManagerProvider.kt @@ -17,24 +17,38 @@ package org.matrix.android.sdk.internal.di import android.content.Context +import androidx.lifecycle.Observer import androidx.work.Constraints import androidx.work.ListenableWorker import androidx.work.NetworkType import androidx.work.OneTimeWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkInfo import androidx.work.WorkManager import androidx.work.WorkRequest +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.MatrixCoroutineDispatchers +import org.matrix.android.sdk.internal.session.SessionScope +import org.matrix.android.sdk.internal.worker.MatrixWorkerFactory import java.util.concurrent.TimeUnit import javax.inject.Inject +@SessionScope internal class WorkManagerProvider @Inject constructor( context: Context, - @SessionId private val sessionId: String + @SessionId private val sessionId: String, + private val coroutineDispatchers: MatrixCoroutineDispatchers, + private val sessionScope: CoroutineScope ) { private val tag = MATRIX_SDK_TAG_PREFIX + sessionId val workManager = WorkManager.getInstance(context) + init { + checkIfWorkerFactoryIsSetup() + } + /** * Create a OneTimeWorkRequestBuilder, with the Matrix SDK tag */ @@ -60,6 +74,27 @@ internal class WorkManagerProvider @Inject constructor( } } + private fun checkIfWorkerFactoryIsSetup() { + sessionScope.launch(coroutineDispatchers.main) { + val checkWorkerRequest = OneTimeWorkRequestBuilder().build() + workManager.enqueue(checkWorkerRequest) + val checkWorkerLiveState = workManager.getWorkInfoByIdLiveData(checkWorkerRequest.id) + val observer = object : Observer { + override fun onChanged(workInfo: WorkInfo) { + if (workInfo.state.isFinished) { + checkWorkerLiveState.removeObserver(this) + if (workInfo.state == WorkInfo.State.FAILED) { + throw RuntimeException("MatrixWorkerFactory is not being set on your worker configuration.\n" + + "Makes sure to add it to a DelegatingWorkerFactory if you have your own factory or use it directly.\n" + + "You can grab the instance through the Matrix class.") + } + } + } + } + checkWorkerLiveState.observeForever(observer) + } + } + companion object { private const val MATRIX_SDK_TAG_PREFIX = "MatrixSDK-" diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt index 6edb42c605..c54dea4a00 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/MatrixWorkerFactory.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.worker import android.content.Context +import androidx.work.CoroutineWorker import androidx.work.ListenableWorker import androidx.work.WorkerFactory import androidx.work.WorkerParameters @@ -51,7 +52,9 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage ): ListenableWorker? { Timber.d("MatrixWorkerFactory.createWorker for $workerClassName") return when (workerClassName) { - AddPusherWorker::class.java.name -> + CheckFactoryWorker::class.java.name -> + CheckFactoryWorker(appContext, workerParameters, true) + AddPusherWorker::class.java.name -> AddPusherWorker(appContext, workerParameters, sessionManager) CancelGossipRequestWorker::class.java.name -> CancelGossipRequestWorker(appContext, workerParameters, sessionManager) @@ -75,9 +78,29 @@ internal class MatrixWorkerFactory @Inject constructor(private val sessionManage UpdateTrustWorker(appContext, workerParameters, sessionManager) UploadContentWorker::class.java.name -> UploadContentWorker(appContext, workerParameters, sessionManager) - else -> + else -> { + Timber.w("No worker defined on MatrixWorkerFactory for $workerClassName will delegate to default.") // Return null to delegate to the default WorkerFactory. null + } + } + } + + /** + * This worker is launched by the factory with the isCreatedByMatrixWorkerFactory flag to true. + * If the MatrixWorkerFactory is not set up, it will default to the other constructor and it will throw + */ + class CheckFactoryWorker(context: Context, workerParameters: WorkerParameters, private val isCreatedByMatrixWorkerFactory: Boolean) : CoroutineWorker(context, workerParameters) { + + // Called by WorkManager if there is no MatrixWorkerFactory + constructor(context: Context, workerParameters: WorkerParameters) : this(context, workerParameters, isCreatedByMatrixWorkerFactory = false) + + override suspend fun doWork(): Result { + return if (!isCreatedByMatrixWorkerFactory) { + Result.failure() + } else { + Result.success() + } } } }