diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt b/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt index c8277ee2a..996c139ea 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt @@ -70,7 +70,7 @@ class AnalysisWorker(context: Context, parameters: WorkerParameters) : Coroutine private fun onStart() { Log.i(LOG_TAG, "Start analysis worker $id") runBlocking { - FlutterUtils.initFlutterEngine(applicationContext, SHARED_PREFERENCES_KEY, CALLBACK_HANDLE_KEY) { + FlutterUtils.initFlutterEngine(applicationContext, SHARED_PREFERENCES_KEY, PREF_CALLBACK_HANDLE_KEY) { flutterEngine = it } } @@ -78,14 +78,15 @@ class AnalysisWorker(context: Context, parameters: WorkerParameters) : Coroutine try { initChannels(applicationContext) + val preferences = applicationContext.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) + val entryIdStrings = preferences.getStringSet(PREF_ENTRY_IDS_KEY, null) + runBlocking { FlutterUtils.runOnUiThread { backgroundChannel?.invokeMethod( "start", hashMapOf( - "entryIds" to inputData.getIntArray(KEY_ENTRY_IDS)?.toList(), + "entryIds" to entryIdStrings?.map { Integer.parseUnsignedInt(it) }?.toList(), "force" to inputData.getBoolean(KEY_FORCE, false), - "progressTotal" to inputData.getInt(KEY_PROGRESS_TOTAL, 0), - "progressOffset" to inputData.getInt(KEY_PROGRESS_OFFSET, 0), ) ) } @@ -194,14 +195,12 @@ class AnalysisWorker(context: Context, parameters: WorkerParameters) : Coroutine private val LOG_TAG = LogUtils.createTag() private const val BACKGROUND_CHANNEL = "deckers.thibault/aves/analysis_service_background" const val SHARED_PREFERENCES_KEY = "analysis_service" - const val CALLBACK_HANDLE_KEY = "callback_handle" + const val PREF_CALLBACK_HANDLE_KEY = "callback_handle" + const val PREF_ENTRY_IDS_KEY = "entry_ids" const val NOTIFICATION_CHANNEL = "analysis" const val NOTIFICATION_ID = 1 - const val KEY_ENTRY_IDS = "entry_ids" const val KEY_FORCE = "force" - const val KEY_PROGRESS_TOTAL = "progress_total" - const val KEY_PROGRESS_OFFSET = "progress_offset" } } diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt index b6eb80626..ed365f821 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt @@ -2,7 +2,6 @@ package deckers.thibault.aves.channel.calls import android.content.Context import androidx.work.ExistingWorkPolicy -import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkInfo import androidx.work.WorkManager @@ -39,7 +38,7 @@ class AnalysisHandler(private val activity: FlutterActivity, private val onAnaly val preferences = activity.getSharedPreferences(AnalysisWorker.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) with(preferences.edit()) { - putLong(AnalysisWorker.CALLBACK_HANDLE_KEY, callbackHandle) + putLong(AnalysisWorker.PREF_CALLBACK_HANDLE_KEY, callbackHandle) apply() } result.success(true) @@ -54,33 +53,24 @@ class AnalysisHandler(private val activity: FlutterActivity, private val onAnaly // can be null or empty val allEntryIds = call.argument>("entryIds") - val progressTotal = allEntryIds?.size ?: 0 - var progressOffset = 0 // work `Data` cannot occupy more than 10240 bytes when serialized - // so we split it when we have a long list of entry IDs - val chunked = allEntryIds?.chunked(WORK_DATA_CHUNK_SIZE) ?: listOf(null) - - fun buildRequest(entryIds: List?, progressOffset: Int): OneTimeWorkRequest { - val workData = workDataOf( - AnalysisWorker.KEY_ENTRY_IDS to entryIds?.toIntArray(), - AnalysisWorker.KEY_FORCE to force, - AnalysisWorker.KEY_PROGRESS_TOTAL to progressTotal, - AnalysisWorker.KEY_PROGRESS_OFFSET to progressOffset, - ) - return OneTimeWorkRequestBuilder().apply { setInputData(workData) }.build() + // so we save the possibly long list of entry IDs to shared preferences + val preferences = activity.getSharedPreferences(AnalysisWorker.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE) + with(preferences.edit()) { + putStringSet(AnalysisWorker.PREF_ENTRY_IDS_KEY, allEntryIds?.map { it.toString() }?.toSet()) + apply() } - var work = WorkManager.getInstance(activity).beginUniqueWork( + val workData = workDataOf( + AnalysisWorker.KEY_FORCE to force, + ) + + WorkManager.getInstance(activity).beginUniqueWork( ANALYSIS_WORK_NAME, ExistingWorkPolicy.KEEP, - buildRequest(chunked.first(), progressOffset), - ) - chunked.drop(1).forEach { entryIds -> - progressOffset += WORK_DATA_CHUNK_SIZE - work = work.then(buildRequest(entryIds, progressOffset)) - } - work.enqueue() + OneTimeWorkRequestBuilder().apply { setInputData(workData) }.build(), + ).enqueue() attachToActivity() result.success(null) @@ -106,6 +96,5 @@ class AnalysisHandler(private val activity: FlutterActivity, private val onAnaly companion object { const val CHANNEL = "deckers.thibault/aves/analysis" private const val ANALYSIS_WORK_NAME = "analysis_work" - private const val WORK_DATA_CHUNK_SIZE = 1000 } } diff --git a/lib/services/analysis_service.dart b/lib/services/analysis_service.dart index 6efd63410..da6042143 100644 --- a/lib/services/analysis_service.dart +++ b/lib/services/analysis_service.dart @@ -127,21 +127,16 @@ class Analyzer with WidgetsBindingObserver { Future start(dynamic args) async { List? entryIds; var force = false; - var progressTotal = 0, progressOffset = 0; if (args is Map) { entryIds = (args['entryIds'] as List?)?.cast(); force = args['force'] ?? false; - progressTotal = args['progressTotal']; - progressOffset = args['progressOffset']; } - await reportService.log('Analyzer start for ${entryIds?.length ?? 'all'} entries, at $progressOffset/$progressTotal'); + await reportService.log('Analyzer start for ${entryIds?.length ?? 'all'} entries'); _controller?.dispose(); _controller = AnalysisController( canStartService: false, entryIds: entryIds, force: force, - progressTotal: progressTotal, - progressOffset: progressOffset, ); settings.systemLocalesFallback = await deviceService.getLocales(); diff --git a/lib/utils/android_file_utils.dart b/lib/utils/android_file_utils.dart index e3c620ce0..0152bd1aa 100644 --- a/lib/utils/android_file_utils.dart +++ b/lib/utils/android_file_utils.dart @@ -106,8 +106,8 @@ class AndroidFileUtils { if (isScreenshotsPath(dirPath)) return AlbumType.screenshots; if (isVideoCapturesPath(dirPath)) return AlbumType.videoCaptures; - final dir = pContext.split(dirPath).last; - if (dirPath.startsWith(primaryStorage) && appInventory.isPotentialAppDir(dir)) return AlbumType.app; + final dir = pContext.split(dirPath).lastOrNull; + if (dir != null && dirPath.startsWith(primaryStorage) && appInventory.isPotentialAppDir(dir)) return AlbumType.app; return AlbumType.regular; }