refactor: simplify background worker (#21558)
* chore: log hash starting * chore: android - bump the min worker delay * remove local sync only task and always enqueue background workers --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
@@ -61,9 +61,8 @@ private open class BackgroundWorkerPigeonCodec : StandardMessageCodec() {
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface BackgroundWorkerFgHostApi {
|
||||
fun enableSyncWorker()
|
||||
fun enableUploadWorker()
|
||||
fun disableUploadWorker()
|
||||
fun enable()
|
||||
fun disable()
|
||||
|
||||
companion object {
|
||||
/** The codec used by BackgroundWorkerFgHostApi. */
|
||||
@@ -75,11 +74,11 @@ interface BackgroundWorkerFgHostApi {
|
||||
fun setUp(binaryMessenger: BinaryMessenger, api: BackgroundWorkerFgHostApi?, messageChannelSuffix: String = "") {
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.enableSyncWorker$separatedMessageChannelSuffix", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.enable$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
val wrapped: List<Any?> = try {
|
||||
api.enableSyncWorker()
|
||||
api.enable()
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
BackgroundWorkerPigeonUtils.wrapError(exception)
|
||||
@@ -91,27 +90,11 @@ interface BackgroundWorkerFgHostApi {
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.enableUploadWorker$separatedMessageChannelSuffix", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.disable$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
val wrapped: List<Any?> = try {
|
||||
api.enableUploadWorker()
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
BackgroundWorkerPigeonUtils.wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFgHostApi.disableUploadWorker$separatedMessageChannelSuffix", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
val wrapped: List<Any?> = try {
|
||||
api.disableUploadWorker()
|
||||
api.disable()
|
||||
listOf(null)
|
||||
} catch (exception: Throwable) {
|
||||
BackgroundWorkerPigeonUtils.wrapError(exception)
|
||||
@@ -182,23 +165,6 @@ class BackgroundWorkerFlutterApi(private val binaryMessenger: BinaryMessenger, p
|
||||
BackgroundWorkerPigeonCodec()
|
||||
}
|
||||
}
|
||||
fun onLocalSync(maxSecondsArg: Long?, callback: (Result<Unit>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
val channelName = "dev.flutter.pigeon.immich_mobile.BackgroundWorkerFlutterApi.onLocalSync$separatedMessageChannelSuffix"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(maxSecondsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(BackgroundWorkerPigeonUtils.createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onIosUpload(isRefreshArg: Boolean, maxSecondsArg: Long?, callback: (Result<Unit>) -> Unit)
|
||||
{
|
||||
val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else ""
|
||||
|
||||
@@ -16,11 +16,6 @@ import io.flutter.embedding.engine.loader.FlutterLoader
|
||||
|
||||
private const val TAG = "BackgroundWorker"
|
||||
|
||||
enum class BackgroundTaskType {
|
||||
LOCAL_SYNC,
|
||||
UPLOAD,
|
||||
}
|
||||
|
||||
class BackgroundWorker(context: Context, params: WorkerParameters) :
|
||||
ListenableWorker(context, params), BackgroundWorkerBgHostApi {
|
||||
private val ctx: Context = context.applicationContext
|
||||
@@ -84,13 +79,7 @@ class BackgroundWorker(context: Context, params: WorkerParameters) :
|
||||
* This method acts as a bridge between the native Android background task system and Flutter.
|
||||
*/
|
||||
override fun onInitialized() {
|
||||
val taskTypeIndex = inputData.getInt(BackgroundWorkerApiImpl.WORKER_DATA_TASK_TYPE, 0)
|
||||
val taskType = BackgroundTaskType.entries[taskTypeIndex]
|
||||
|
||||
when (taskType) {
|
||||
BackgroundTaskType.LOCAL_SYNC -> flutterApi?.onLocalSync(null) { handleHostResult(it) }
|
||||
BackgroundTaskType.UPLOAD -> flutterApi?.onAndroidUpload { handleHostResult(it) }
|
||||
}
|
||||
flutterApi?.onAndroidUpload { handleHostResult(it) }
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
|
||||
@@ -3,10 +3,8 @@ package app.alextran.immich.background
|
||||
import android.content.Context
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import androidx.work.BackoffPolicy
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.Data
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
@@ -16,18 +14,13 @@ private const val TAG = "BackgroundUploadImpl"
|
||||
|
||||
class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
|
||||
private val ctx: Context = context.applicationContext
|
||||
override fun enableSyncWorker() {
|
||||
|
||||
override fun enable() {
|
||||
enqueueMediaObserver(ctx)
|
||||
Log.i(TAG, "Scheduled media observer")
|
||||
}
|
||||
|
||||
override fun enableUploadWorker() {
|
||||
updateUploadEnabled(ctx, true)
|
||||
Log.i(TAG, "Scheduled background upload tasks")
|
||||
}
|
||||
|
||||
override fun disableUploadWorker() {
|
||||
updateUploadEnabled(ctx, false)
|
||||
override fun disable() {
|
||||
WorkManager.getInstance(ctx).cancelUniqueWork(OBSERVER_WORKER_NAME)
|
||||
WorkManager.getInstance(ctx).cancelUniqueWork(BACKGROUND_WORKER_NAME)
|
||||
Log.i(TAG, "Cancelled background upload tasks")
|
||||
}
|
||||
@@ -36,25 +29,14 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
|
||||
private const val BACKGROUND_WORKER_NAME = "immich/BackgroundWorkerV1"
|
||||
private const val OBSERVER_WORKER_NAME = "immich/MediaObserverV1"
|
||||
|
||||
const val WORKER_DATA_TASK_TYPE = "taskType"
|
||||
|
||||
const val SHARED_PREF_NAME = "Immich::Background"
|
||||
const val SHARED_PREF_BACKUP_ENABLED = "Background::backup::enabled"
|
||||
|
||||
private fun updateUploadEnabled(context: Context, enabled: Boolean) {
|
||||
context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE).edit {
|
||||
putBoolean(SHARED_PREF_BACKUP_ENABLED, enabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun enqueueMediaObserver(ctx: Context) {
|
||||
val constraints = Constraints.Builder()
|
||||
.addContentUriTrigger(MediaStore.Images.Media.INTERNAL_CONTENT_URI, true)
|
||||
.addContentUriTrigger(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true)
|
||||
.addContentUriTrigger(MediaStore.Video.Media.INTERNAL_CONTENT_URI, true)
|
||||
.addContentUriTrigger(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, true)
|
||||
.setTriggerContentUpdateDelay(5, TimeUnit.SECONDS)
|
||||
.setTriggerContentMaxDelay(1, TimeUnit.MINUTES)
|
||||
.setTriggerContentUpdateDelay(30, TimeUnit.SECONDS)
|
||||
.setTriggerContentMaxDelay(3, TimeUnit.MINUTES)
|
||||
.build()
|
||||
|
||||
val work = OneTimeWorkRequest.Builder(MediaObserver::class.java)
|
||||
@@ -66,15 +48,13 @@ class BackgroundWorkerApiImpl(context: Context) : BackgroundWorkerFgHostApi {
|
||||
Log.i(TAG, "Enqueued media observer worker with name: $OBSERVER_WORKER_NAME")
|
||||
}
|
||||
|
||||
fun enqueueBackgroundWorker(ctx: Context, taskType: BackgroundTaskType) {
|
||||
fun enqueueBackgroundWorker(ctx: Context) {
|
||||
val constraints = Constraints.Builder().setRequiresBatteryNotLow(true).build()
|
||||
|
||||
val data = Data.Builder()
|
||||
data.putInt(WORKER_DATA_TASK_TYPE, taskType.ordinal)
|
||||
val work = OneTimeWorkRequest.Builder(BackgroundWorker::class.java)
|
||||
.setConstraints(constraints)
|
||||
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 1, TimeUnit.MINUTES)
|
||||
.setInputData(data.build()).build()
|
||||
.build()
|
||||
WorkManager.getInstance(ctx)
|
||||
.enqueueUniqueWork(BACKGROUND_WORKER_NAME, ExistingWorkPolicy.REPLACE, work)
|
||||
|
||||
|
||||
@@ -6,29 +6,17 @@ import androidx.work.Worker
|
||||
import androidx.work.WorkerParameters
|
||||
|
||||
class MediaObserver(context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||
private val ctx: Context = context.applicationContext
|
||||
private val ctx: Context = context.applicationContext
|
||||
|
||||
override fun doWork(): Result {
|
||||
Log.i("MediaObserver", "Content change detected, starting background worker")
|
||||
override fun doWork(): Result {
|
||||
Log.i("MediaObserver", "Content change detected, starting background worker")
|
||||
// Re-enqueue itself to listen for future changes
|
||||
BackgroundWorkerApiImpl.enqueueMediaObserver(ctx)
|
||||
|
||||
// Enqueue backup worker only if there are new media changes
|
||||
if (triggeredContentUris.isNotEmpty()) {
|
||||
val type =
|
||||
if (isBackupEnabled(ctx)) BackgroundTaskType.UPLOAD else BackgroundTaskType.LOCAL_SYNC
|
||||
BackgroundWorkerApiImpl.enqueueBackgroundWorker(ctx, type)
|
||||
}
|
||||
|
||||
// Re-enqueue itself to listen for future changes
|
||||
BackgroundWorkerApiImpl.enqueueMediaObserver(ctx)
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
private fun isBackupEnabled(context: Context): Boolean {
|
||||
val prefs =
|
||||
context.getSharedPreferences(
|
||||
BackgroundWorkerApiImpl.SHARED_PREF_NAME,
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
return prefs.getBoolean(BackgroundWorkerApiImpl.SHARED_PREF_BACKUP_ENABLED, false)
|
||||
// Enqueue backup worker only if there are new media changes
|
||||
if (triggeredContentUris.isNotEmpty()) {
|
||||
BackgroundWorkerApiImpl.enqueueBackgroundWorker(ctx)
|
||||
}
|
||||
return Result.success()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user