Add delta sync functionality

Signed-off-by: Jonas Mayer <jonas.a.mayer@gmx.net>
This commit is contained in:
Jonas Mayer 2024-03-20 14:45:52 +01:00 committed by Jonas Mayer
parent 058fcf9468
commit 92074e197a
2 changed files with 40 additions and 12 deletions

View file

@ -29,8 +29,8 @@ import android.os.Build
import android.text.TextUtils import android.text.TextUtils
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.exifinterface.media.ExifInterface import androidx.exifinterface.media.ExifInterface
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo import androidx.work.ForegroundInfo
import androidx.work.Worker
import androidx.work.WorkerParameters import androidx.work.WorkerParameters
import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.device.PowerManagementService
@ -72,19 +72,23 @@ class FilesSyncWork(
private val powerManagementService: PowerManagementService, private val powerManagementService: PowerManagementService,
private val syncedFolderProvider: SyncedFolderProvider, private val syncedFolderProvider: SyncedFolderProvider,
private val backgroundJobManager: BackgroundJobManager private val backgroundJobManager: BackgroundJobManager
) : CoroutineWorker(context, params) { ) : Worker(context, params) {
companion object { companion object {
const val TAG = "FilesSyncJob" const val TAG = "FilesSyncJob"
const val SKIP_CUSTOM = "skipCustom" const val SKIP_CUSTOM = "skipCustom"
const val OVERRIDE_POWER_SAVING = "overridePowerSaving" const val OVERRIDE_POWER_SAVING = "overridePowerSaving"
const val CHANGED_FILES = "changedFiles"
const val FOREGROUND_SERVICE_ID = 414 const val FOREGROUND_SERVICE_ID = 414
} }
@Suppress("MagicNumber") @Suppress("MagicNumber")
private fun createForegroundInfo(progressPercent: Int): ForegroundInfo { private fun updateForegroundWorker(progressPercent: Int, useForegroundWorker: Boolean) {
// update throughout worker execution to give use feedback how far worker is if (useForegroundWorker) {
return
}
// update throughout worker execution to give use feedback how far worker is
val notification = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_FILE_SYNC) val notification = NotificationCompat.Builder(context, NotificationUtils.NOTIFICATION_CHANNEL_FILE_SYNC)
.setTicker(context.getString(R.string.autoupload_worker_foreground_info)) .setTicker(context.getString(R.string.autoupload_worker_foreground_info))
.setContentText(context.getString(R.string.autoupload_worker_foreground_info)) .setContentText(context.getString(R.string.autoupload_worker_foreground_info))
@ -93,17 +97,18 @@ class FilesSyncWork(
.setOngoing(true) .setOngoing(true)
.setProgress(100, progressPercent, false) .setProgress(100, progressPercent, false)
.build() .build()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val foregroundInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ForegroundInfo(FOREGROUND_SERVICE_ID, notification, ForegroundServiceType.DataSync.getId()) ForegroundInfo(FOREGROUND_SERVICE_ID, notification, ForegroundServiceType.DataSync.getId())
} else { } else {
ForegroundInfo(FOREGROUND_SERVICE_ID, notification) ForegroundInfo(FOREGROUND_SERVICE_ID, notification)
} }
setForegroundAsync(foregroundInfo)
} }
@Suppress("MagicNumber") @Suppress("MagicNumber")
override suspend fun doWork(): Result { override fun doWork(): Result {
backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class)) backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class))
setForeground(createForegroundInfo(0))
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false) val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
// If we are in power save mode, better to postpone upload // If we are in power save mode, better to postpone upload
@ -121,10 +126,20 @@ class FilesSyncWork(
connectivityService, connectivityService,
powerManagementService powerManagementService
) )
setForeground(createForegroundInfo(5))
// Check every file in every synced folder for changes and update filesystemDataProvider database (expensive) // Get changed files from ContentObserverWork or by scanning filesystem
FilesSyncHelper.insertAllDBEntries(skipCustom, syncedFolderProvider) val changedFiles = inputData.getStringArray(CHANGED_FILES)
setForeground(createForegroundInfo(50)) var useForegroundWorker = false
if (changedFiles != null) {
// TODO Handle single files
FilesSyncHelper.insertChangedEntries(skipCustom,syncedFolderProvider,changedFiles)
} else {
useForegroundWorker = true
updateForegroundWorker(5, true)
// Check every file in every synced folder for changes and update filesystemDataProvider database (expensive)
FilesSyncHelper.insertAllDBEntries(skipCustom, syncedFolderProvider)
updateForegroundWorker(50, true)
}
// Create all the providers we'll need // Create all the providers we'll need
val filesystemDataProvider = FilesystemDataProvider(contentResolver) val filesystemDataProvider = FilesystemDataProvider(contentResolver)
val currentLocale = resources.configuration.locale val currentLocale = resources.configuration.locale
@ -134,7 +149,10 @@ class FilesSyncWork(
// start upload of changed / new files // start upload of changed / new files
val syncedFolders = syncedFolderProvider.syncedFolders val syncedFolders = syncedFolderProvider.syncedFolders
for ((index, syncedFolder) in syncedFolders.withIndex()) { for ((index, syncedFolder) in syncedFolders.withIndex()) {
setForeground(createForegroundInfo((50 + (index.toDouble() / syncedFolders.size.toDouble()) * 50).toInt())) updateForegroundWorker(
(50 + (index.toDouble() / syncedFolders.size.toDouble()) * 50).toInt(),
useForegroundWorker
)
if (syncedFolder.isEnabled && (!skipCustom || MediaFolderType.CUSTOM != syncedFolder.type)) { if (syncedFolder.isEnabled && (!skipCustom || MediaFolderType.CUSTOM != syncedFolder.type)) {
syncFolder( syncFolder(
context, context,

View file

@ -139,6 +139,16 @@ public final class FilesSyncHelper {
} }
} }
public static void insertChangedEntries(boolean skipCustom,
SyncedFolderProvider syncedFolderProvider,
String[] changedFiles) {
for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
if (syncedFolder.isEnabled() && (!skipCustom || syncedFolder.getType() != MediaFolderType.CUSTOM)) {
insertAllDBEntriesForSyncedFolder(syncedFolder);
}
}
}
private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder) { private static void insertContentIntoDB(Uri uri, SyncedFolder syncedFolder) {
final Context context = MainApp.getAppContext(); final Context context = MainApp.getAppContext();
final ContentResolver contentResolver = context.getContentResolver(); final ContentResolver contentResolver = context.getContentResolver();