diff --git a/app/src/org/commcare/tasks/EntityLoaderHelper.kt b/app/src/org/commcare/tasks/EntityLoaderHelper.kt index 35cd11c99..e55c75354 100644 --- a/app/src/org/commcare/tasks/EntityLoaderHelper.kt +++ b/app/src/org/commcare/tasks/EntityLoaderHelper.kt @@ -35,8 +35,22 @@ class EntityLoaderHelper( } } - fun loadEntities(nodeset: TreeReference): Pair>, List>? { + /** + * Loads and prepares a list of entities derived from the given nodeset + */ + fun loadEntities(nodeset: TreeReference): Pair>, List> { val references = factory.expandReferenceList(nodeset) + val entities = loadEntitiesWithReferences(references) + factory.prepareEntities(entities) + factory.printAndClearTraces("build") + return Pair>, List>(entities, references) + } + + + /** + * Loads a list of entities corresponding to the given references + */ + private fun loadEntitiesWithReferences(references: List): MutableList>? { val entities: MutableList> = ArrayList() focusTargetIndex = -1 var indexInFullList = 0 @@ -53,10 +67,7 @@ class EntityLoaderHelper( indexInFullList++ } } - - factory.prepareEntities(entities) - factory.printAndClearTraces("build") - return Pair>, List>(entities, references) + return entities } override fun cancel() { diff --git a/app/src/org/commcare/tasks/PrimeEntityCache.kt b/app/src/org/commcare/tasks/PrimeEntityCache.kt new file mode 100644 index 000000000..8c8bb72b5 --- /dev/null +++ b/app/src/org/commcare/tasks/PrimeEntityCache.kt @@ -0,0 +1,24 @@ +package org.commcare.tasks + +import android.content.Context +import androidx.work.Worker +import androidx.work.WorkerParameters +import org.commcare.CommCareApplication +import org.commcare.utils.SessionUnavailableException + +class PrimeEntityCache(appContext: Context, workerParams: WorkerParameters) + : Worker(appContext, workerParams) { + + override fun doWork(): Result { + try { + PrimeEntityCacheHelper.getInstance().primeEntityCache() + return Result.success(); + } catch (_: SessionUnavailableException) { + } + return Result.failure() + } + + override fun onStopped() { + PrimeEntityCacheHelper.getInstance().cancel() + } +} diff --git a/app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt b/app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt new file mode 100644 index 000000000..4065f957e --- /dev/null +++ b/app/src/org/commcare/tasks/PrimeEntityCacheHelper.kt @@ -0,0 +1,74 @@ +package org.commcare.tasks + +import io.reactivex.functions.Cancellable +import okhttp3.internal.notifyAll +import org.commcare.CommCareApplication +import org.commcare.suite.model.Detail +import org.commcare.suite.model.EntityDatum +import org.commcare.utils.AndroidCommCarePlatform +import org.javarosa.core.model.condition.EvaluationContext + +class PrimeEntityCacheHelper private constructor() : Cancellable { + + private var entityLoaderHelper: EntityLoaderHelper? = null + private var inProgress = false + + companion object { + @Volatile + private var instance: PrimeEntityCacheHelper? = null + + fun getInstance() = + instance ?: synchronized(this) { + instance ?: PrimeEntityCacheHelper().also { instance = it } + } + } + + fun primeEntityCache() { + checkPreConditions() + primeEntityCacheForApp(CommCareApplication.instance().commCarePlatform) + clearState() + } + + private fun primeEntityCacheForApp(commCarePlatform: AndroidCommCarePlatform) { + inProgress = true + val commandMap = commCarePlatform.commandToEntryMap + for (command in commandMap.keys()) { + val entry = commandMap[command]!! + val sessionDatums = entry.sessionDataReqs + for (sessionDatum in sessionDatums) { + if (sessionDatum is EntityDatum) { + val shortDetailId = sessionDatum.shortDetail + if (shortDetailId != null) { + val detail = commCarePlatform.getDetail(shortDetailId) + primeCacheForDetail(detail, sessionDatum) + } + } + } + } + } + + private fun primeCacheForDetail(detail: Detail, sessionDatum: EntityDatum) { + if (detail.shouldCache()) { + entityLoaderHelper = EntityLoaderHelper(detail, evalCtx()) + entityLoaderHelper!!.loadEntities(sessionDatum.nodeset) + } + } + + private fun evalCtx(): EvaluationContext { + return CommCareApplication.instance().currentSessionWrapper.evaluationContext + } + + private fun clearState() { + entityLoaderHelper = null + inProgress = false + } + + private fun checkPreConditions() { + require(CommCareApplication.instance().session.isActive) { "User session must be active to prime entity cache" } + require(!inProgress) { "We are already priming the cache" } + } + + override fun cancel() { + entityLoaderHelper?.cancel() + } +}