Loading app/build.gradle +1 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ android { includeAndroidResources = true all { systemProperty 'robolectric.usePreinstrumentedJars', 'false' maxParallelForks = 1 } } } Loading app/src/main/java/foundation/e/apps/data/install/updates/UpdatesWorkManager.kt +52 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package foundation.e.apps.data.install.updates import android.content.Context import androidx.annotation.VisibleForTesting import androidx.work.Constraints import androidx.work.Data import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingWorkPolicy Loading Loading @@ -45,25 +47,26 @@ object UpdatesWorkManager { } private fun buildOneTimeWorkRequest(): OneTimeWorkRequest { val spec = buildOneTimeRequestSpec() return OneTimeWorkRequest.Builder(UpdatesWorker::class.java).apply { setConstraints(WorkRequestConstraints.build(WorkType.UpdateOneTime)) setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) addTag(TAG_WORK_USER_INITIATED_UPDATE) }.setInputData( Data.Builder() .putBoolean(UpdatesWorker.IS_AUTO_UPDATE, false) .build() ).build() setConstraints(spec.constraints) if (spec.expedited) { setExpedited(spec.outOfQuotaPolicy) } spec.tags.forEach { addTag(it) } setInputData(spec.inputData) }.build() } private fun buildPeriodicWorkRequest(interval: Long): PeriodicWorkRequest { val spec = buildPeriodicRequestSpec(interval) return PeriodicWorkRequest.Builder( UpdatesWorker::class.java, interval, spec.intervalHours, TimeUnit.HOURS ).apply { setConstraints(WorkRequestConstraints.build(WorkType.UpdatePeriodic)) addTag(TAG_WORK_PERIODIC_UPDATE) setConstraints(spec.constraints) spec.tags.forEach { addTag(it) } }.build() } Loading @@ -80,4 +83,42 @@ object UpdatesWorkManager { ) Timber.i("UpdatesWorker started") } @VisibleForTesting internal data class OneTimeRequestSpec( val inputData: Data, val constraints: Constraints, val tags: Set<String>, val expedited: Boolean, val outOfQuotaPolicy: OutOfQuotaPolicy ) @VisibleForTesting internal data class PeriodicRequestSpec( val intervalHours: Long, val constraints: Constraints, val tags: Set<String> ) @VisibleForTesting internal fun buildOneTimeRequestSpec(): OneTimeRequestSpec { return OneTimeRequestSpec( inputData = Data.Builder() .putBoolean(UpdatesWorker.IS_AUTO_UPDATE, false) .build(), constraints = WorkRequestConstraints.build(WorkType.UpdateOneTime), tags = setOf(TAG_WORK_USER_INITIATED_UPDATE), expedited = true, outOfQuotaPolicy = OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST ) } @VisibleForTesting internal fun buildPeriodicRequestSpec(interval: Long): PeriodicRequestSpec { return PeriodicRequestSpec( intervalHours = interval, constraints = WorkRequestConstraints.build(WorkType.UpdatePeriodic), tags = setOf(TAG_WORK_PERIODIC_UPDATE) ) } } app/src/main/java/foundation/e/apps/data/install/workmanager/InstallWorkManager.kt +37 −10 Original line number Diff line number Diff line package foundation.e.apps.data.install.workmanager import android.content.Context import androidx.annotation.VisibleForTesting import androidx.work.Constraints import androidx.work.Data import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder Loading @@ -14,17 +16,16 @@ object InstallWorkManager { const val INSTALL_WORK_NAME = "APP_LOUNGE_INSTALL_APP" fun enqueueWork(context: Context, appInstall: AppInstall, isUpdateWork: Boolean = false): Operation { val inputData = Data.Builder() .putString(InstallAppWorker.INPUT_DATA_FUSED_DOWNLOAD, appInstall.id) .putBoolean(InstallAppWorker.IS_UPDATE_WORK, isUpdateWork) .build() val spec = buildInstallRequestSpec(appInstall, isUpdateWork) val request = OneTimeWorkRequestBuilder<InstallAppWorker>() .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .setInputData(inputData) .addTag(appInstall.id) .addTag(INSTALL_WORK_NAME) .setConstraints(WorkRequestConstraints.build(WorkType.InstallOneTime)) .setInputData(spec.inputData) .setConstraints(spec.constraints) .apply { if (spec.expedited) { setExpedited(spec.outOfQuotaPolicy) } spec.tags.forEach { addTag(it) } } .build() val operation = WorkManager.getInstance(context) Loading Loading @@ -52,4 +53,30 @@ object InstallWorkManager { } fun getUniqueWorkName(appPackageName: String): String = "${INSTALL_WORK_NAME}/$appPackageName" @VisibleForTesting internal data class InstallRequestSpec( val inputData: Data, val constraints: Constraints, val tags: Set<String>, val expedited: Boolean, val outOfQuotaPolicy: OutOfQuotaPolicy ) @VisibleForTesting internal fun buildInstallRequestSpec( appInstall: AppInstall, isUpdateWork: Boolean ): InstallRequestSpec { return InstallRequestSpec( inputData = Data.Builder() .putString(InstallAppWorker.INPUT_DATA_FUSED_DOWNLOAD, appInstall.id) .putBoolean(InstallAppWorker.IS_UPDATE_WORK, isUpdateWork) .build(), constraints = WorkRequestConstraints.build(WorkType.InstallOneTime), tags = setOf(appInstall.id, INSTALL_WORK_NAME), expedited = true, outOfQuotaPolicy = OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST ) } } app/src/test/java/foundation/e/apps/data/install/updates/UpdatesWorkManagerTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ class UpdatesWorkManagerTest { @Test fun enqueueWork_buildsExpectedPeriodicRequest() { UpdatesWorkManager.enqueueWork(context, interval = 6, ExistingPeriodicWorkPolicy.REPLACE) UpdatesWorkManager.enqueueWork(context, interval = 6, ExistingPeriodicWorkPolicy.KEEP) val workInfo = getActiveUniqueWorkInfo("updates_work") val workSpec = getWorkSpec(workInfo.id) Loading @@ -105,21 +105,22 @@ class UpdatesWorkManagerTest { fun enqueueWork_respectsExistingPeriodicWorkPolicy() { UpdatesWorkManager.enqueueWork(context, interval = 6, ExistingPeriodicWorkPolicy.KEEP) val initialWorkInfo = getActiveUniqueWorkInfo("updates_work") val initialWorkSpec = getWorkSpec(initialWorkInfo.id) val initialSpec = getWorkSpec(initialWorkInfo.id) assertThat(initialSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(6)) UpdatesWorkManager.enqueueWork(context, interval = 12, ExistingPeriodicWorkPolicy.KEEP) val keptWorkInfo = getActiveUniqueWorkInfo("updates_work") val keptWorkSpec = getWorkSpec(keptWorkInfo.id) val keptSpec = getWorkSpec(keptWorkInfo.id) assertThat(keptWorkInfo.id).isEqualTo(initialWorkInfo.id) assertThat(keptWorkSpec.intervalDuration).isEqualTo(initialWorkSpec.intervalDuration) assertThat(keptSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(6)) UpdatesWorkManager.enqueueWork(context, interval = 24, ExistingPeriodicWorkPolicy.REPLACE) val replacedWorkInfo = getActiveUniqueWorkInfo("updates_work") val replacedWorkSpec = getWorkSpec(replacedWorkInfo.id) val replacedSpec = getWorkSpec(replacedWorkInfo.id) assertThat(replacedWorkInfo.id).isNotEqualTo(initialWorkInfo.id) assertThat(replacedWorkSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(24)) assertThat(replacedSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(24)) } private fun getActiveUniqueWorkInfo(uniqueWorkName: String): WorkInfo { Loading app/src/test/java/foundation/e/apps/data/install/updates/UpdatesWorkerTest.kt +16 −8 Original line number Diff line number Diff line Loading @@ -296,8 +296,12 @@ class UpdatesWorkerTest { systemAppsUpdatesRepository ) try { val response = worker.checkManualUpdateRunning() assertFalse(response) } finally { WorkManager.getInstance(appContext).cancelAllWork().result.get() } } @Test Loading Loading @@ -398,6 +402,7 @@ class UpdatesWorkerTest { systemAppsUpdatesRepository ) try { val result = worker.doWork() assertThat(result).isEqualTo(androidx.work.ListenableWorker.Result.success()) Loading @@ -405,6 +410,9 @@ class UpdatesWorkerTest { verify(systemAppsUpdatesRepository, never()).fetchUpdatableSystemApps(true) verify(updatesManagerRepository, never()).getUpdates() verify(updatesManagerRepository, never()).getUpdatesOSS() } finally { WorkManager.getInstance(appContext).cancelAllWork().result.get() } } @Test Loading Loading
app/build.gradle +1 −0 Original line number Diff line number Diff line Loading @@ -137,6 +137,7 @@ android { includeAndroidResources = true all { systemProperty 'robolectric.usePreinstrumentedJars', 'false' maxParallelForks = 1 } } } Loading
app/src/main/java/foundation/e/apps/data/install/updates/UpdatesWorkManager.kt +52 −11 Original line number Diff line number Diff line Loading @@ -18,6 +18,8 @@ package foundation.e.apps.data.install.updates import android.content.Context import androidx.annotation.VisibleForTesting import androidx.work.Constraints import androidx.work.Data import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingWorkPolicy Loading Loading @@ -45,25 +47,26 @@ object UpdatesWorkManager { } private fun buildOneTimeWorkRequest(): OneTimeWorkRequest { val spec = buildOneTimeRequestSpec() return OneTimeWorkRequest.Builder(UpdatesWorker::class.java).apply { setConstraints(WorkRequestConstraints.build(WorkType.UpdateOneTime)) setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) addTag(TAG_WORK_USER_INITIATED_UPDATE) }.setInputData( Data.Builder() .putBoolean(UpdatesWorker.IS_AUTO_UPDATE, false) .build() ).build() setConstraints(spec.constraints) if (spec.expedited) { setExpedited(spec.outOfQuotaPolicy) } spec.tags.forEach { addTag(it) } setInputData(spec.inputData) }.build() } private fun buildPeriodicWorkRequest(interval: Long): PeriodicWorkRequest { val spec = buildPeriodicRequestSpec(interval) return PeriodicWorkRequest.Builder( UpdatesWorker::class.java, interval, spec.intervalHours, TimeUnit.HOURS ).apply { setConstraints(WorkRequestConstraints.build(WorkType.UpdatePeriodic)) addTag(TAG_WORK_PERIODIC_UPDATE) setConstraints(spec.constraints) spec.tags.forEach { addTag(it) } }.build() } Loading @@ -80,4 +83,42 @@ object UpdatesWorkManager { ) Timber.i("UpdatesWorker started") } @VisibleForTesting internal data class OneTimeRequestSpec( val inputData: Data, val constraints: Constraints, val tags: Set<String>, val expedited: Boolean, val outOfQuotaPolicy: OutOfQuotaPolicy ) @VisibleForTesting internal data class PeriodicRequestSpec( val intervalHours: Long, val constraints: Constraints, val tags: Set<String> ) @VisibleForTesting internal fun buildOneTimeRequestSpec(): OneTimeRequestSpec { return OneTimeRequestSpec( inputData = Data.Builder() .putBoolean(UpdatesWorker.IS_AUTO_UPDATE, false) .build(), constraints = WorkRequestConstraints.build(WorkType.UpdateOneTime), tags = setOf(TAG_WORK_USER_INITIATED_UPDATE), expedited = true, outOfQuotaPolicy = OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST ) } @VisibleForTesting internal fun buildPeriodicRequestSpec(interval: Long): PeriodicRequestSpec { return PeriodicRequestSpec( intervalHours = interval, constraints = WorkRequestConstraints.build(WorkType.UpdatePeriodic), tags = setOf(TAG_WORK_PERIODIC_UPDATE) ) } }
app/src/main/java/foundation/e/apps/data/install/workmanager/InstallWorkManager.kt +37 −10 Original line number Diff line number Diff line package foundation.e.apps.data.install.workmanager import android.content.Context import androidx.annotation.VisibleForTesting import androidx.work.Constraints import androidx.work.Data import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequestBuilder Loading @@ -14,17 +16,16 @@ object InstallWorkManager { const val INSTALL_WORK_NAME = "APP_LOUNGE_INSTALL_APP" fun enqueueWork(context: Context, appInstall: AppInstall, isUpdateWork: Boolean = false): Operation { val inputData = Data.Builder() .putString(InstallAppWorker.INPUT_DATA_FUSED_DOWNLOAD, appInstall.id) .putBoolean(InstallAppWorker.IS_UPDATE_WORK, isUpdateWork) .build() val spec = buildInstallRequestSpec(appInstall, isUpdateWork) val request = OneTimeWorkRequestBuilder<InstallAppWorker>() .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) .setInputData(inputData) .addTag(appInstall.id) .addTag(INSTALL_WORK_NAME) .setConstraints(WorkRequestConstraints.build(WorkType.InstallOneTime)) .setInputData(spec.inputData) .setConstraints(spec.constraints) .apply { if (spec.expedited) { setExpedited(spec.outOfQuotaPolicy) } spec.tags.forEach { addTag(it) } } .build() val operation = WorkManager.getInstance(context) Loading Loading @@ -52,4 +53,30 @@ object InstallWorkManager { } fun getUniqueWorkName(appPackageName: String): String = "${INSTALL_WORK_NAME}/$appPackageName" @VisibleForTesting internal data class InstallRequestSpec( val inputData: Data, val constraints: Constraints, val tags: Set<String>, val expedited: Boolean, val outOfQuotaPolicy: OutOfQuotaPolicy ) @VisibleForTesting internal fun buildInstallRequestSpec( appInstall: AppInstall, isUpdateWork: Boolean ): InstallRequestSpec { return InstallRequestSpec( inputData = Data.Builder() .putString(InstallAppWorker.INPUT_DATA_FUSED_DOWNLOAD, appInstall.id) .putBoolean(InstallAppWorker.IS_UPDATE_WORK, isUpdateWork) .build(), constraints = WorkRequestConstraints.build(WorkType.InstallOneTime), tags = setOf(appInstall.id, INSTALL_WORK_NAME), expedited = true, outOfQuotaPolicy = OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST ) } }
app/src/test/java/foundation/e/apps/data/install/updates/UpdatesWorkManagerTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -90,7 +90,7 @@ class UpdatesWorkManagerTest { @Test fun enqueueWork_buildsExpectedPeriodicRequest() { UpdatesWorkManager.enqueueWork(context, interval = 6, ExistingPeriodicWorkPolicy.REPLACE) UpdatesWorkManager.enqueueWork(context, interval = 6, ExistingPeriodicWorkPolicy.KEEP) val workInfo = getActiveUniqueWorkInfo("updates_work") val workSpec = getWorkSpec(workInfo.id) Loading @@ -105,21 +105,22 @@ class UpdatesWorkManagerTest { fun enqueueWork_respectsExistingPeriodicWorkPolicy() { UpdatesWorkManager.enqueueWork(context, interval = 6, ExistingPeriodicWorkPolicy.KEEP) val initialWorkInfo = getActiveUniqueWorkInfo("updates_work") val initialWorkSpec = getWorkSpec(initialWorkInfo.id) val initialSpec = getWorkSpec(initialWorkInfo.id) assertThat(initialSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(6)) UpdatesWorkManager.enqueueWork(context, interval = 12, ExistingPeriodicWorkPolicy.KEEP) val keptWorkInfo = getActiveUniqueWorkInfo("updates_work") val keptWorkSpec = getWorkSpec(keptWorkInfo.id) val keptSpec = getWorkSpec(keptWorkInfo.id) assertThat(keptWorkInfo.id).isEqualTo(initialWorkInfo.id) assertThat(keptWorkSpec.intervalDuration).isEqualTo(initialWorkSpec.intervalDuration) assertThat(keptSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(6)) UpdatesWorkManager.enqueueWork(context, interval = 24, ExistingPeriodicWorkPolicy.REPLACE) val replacedWorkInfo = getActiveUniqueWorkInfo("updates_work") val replacedWorkSpec = getWorkSpec(replacedWorkInfo.id) val replacedSpec = getWorkSpec(replacedWorkInfo.id) assertThat(replacedWorkInfo.id).isNotEqualTo(initialWorkInfo.id) assertThat(replacedWorkSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(24)) assertThat(replacedSpec.intervalDuration).isEqualTo(TimeUnit.HOURS.toMillis(24)) } private fun getActiveUniqueWorkInfo(uniqueWorkName: String): WorkInfo { Loading
app/src/test/java/foundation/e/apps/data/install/updates/UpdatesWorkerTest.kt +16 −8 Original line number Diff line number Diff line Loading @@ -296,8 +296,12 @@ class UpdatesWorkerTest { systemAppsUpdatesRepository ) try { val response = worker.checkManualUpdateRunning() assertFalse(response) } finally { WorkManager.getInstance(appContext).cancelAllWork().result.get() } } @Test Loading Loading @@ -398,6 +402,7 @@ class UpdatesWorkerTest { systemAppsUpdatesRepository ) try { val result = worker.doWork() assertThat(result).isEqualTo(androidx.work.ListenableWorker.Result.success()) Loading @@ -405,6 +410,9 @@ class UpdatesWorkerTest { verify(systemAppsUpdatesRepository, never()).fetchUpdatableSystemApps(true) verify(updatesManagerRepository, never()).getUpdates() verify(updatesManagerRepository, never()).getUpdatesOSS() } finally { WorkManager.getInstance(appContext).cancelAllWork().result.get() } } @Test Loading