mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 05:35:39 +03:00
Merge pull request #13015 from nextcloud/remove-foreground-worker-for-auto-upload
Create individual workers for every Autoupload Folder
This commit is contained in:
commit
0459e97a84
13 changed files with 235 additions and 167 deletions
|
@ -119,9 +119,13 @@ interface BackgroundJobManager {
|
||||||
|
|
||||||
fun startImmediateFilesExportJob(files: Collection<OCFile>): LiveData<JobInfo?>
|
fun startImmediateFilesExportJob(files: Collection<OCFile>): LiveData<JobInfo?>
|
||||||
|
|
||||||
fun schedulePeriodicFilesSyncJob()
|
fun schedulePeriodicFilesSyncJob(syncedFolderID: Long)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immediately start File Sync job for given syncFolderID.
|
||||||
|
*/
|
||||||
fun startImmediateFilesSyncJob(
|
fun startImmediateFilesSyncJob(
|
||||||
|
syncedFolderID: Long,
|
||||||
overridePowerSaving: Boolean = false,
|
overridePowerSaving: Boolean = false,
|
||||||
changedFiles: Array<String> = arrayOf<String>()
|
changedFiles: Array<String> = arrayOf<String>()
|
||||||
)
|
)
|
||||||
|
@ -163,5 +167,5 @@ interface BackgroundJobManager {
|
||||||
fun cancelAllJobs()
|
fun cancelAllJobs()
|
||||||
fun schedulePeriodicHealthStatus()
|
fun schedulePeriodicHealthStatus()
|
||||||
fun startHealthStatus()
|
fun startHealthStatus()
|
||||||
fun bothFilesSyncJobsRunning(): Boolean
|
fun bothFilesSyncJobsRunning(syncedFolderID: Long): Boolean
|
||||||
}
|
}
|
||||||
|
|
|
@ -404,37 +404,55 @@ internal class BackgroundJobManagerImpl(
|
||||||
workManager.cancelJob(JOB_PERIODIC_CALENDAR_BACKUP, user)
|
workManager.cancelJob(JOB_PERIODIC_CALENDAR_BACKUP, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun bothFilesSyncJobsRunning(): Boolean {
|
override fun bothFilesSyncJobsRunning(syncedFolderID: Long): Boolean {
|
||||||
return workManager.isWorkRunning(JOB_PERIODIC_FILES_SYNC) &&
|
return workManager.isWorkRunning(JOB_PERIODIC_FILES_SYNC + "_" + syncedFolderID) &&
|
||||||
workManager.isWorkRunning(JOB_IMMEDIATE_FILES_SYNC)
|
workManager.isWorkRunning(JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun schedulePeriodicFilesSyncJob() {
|
override fun schedulePeriodicFilesSyncJob(
|
||||||
|
syncedFolderID: Long
|
||||||
|
) {
|
||||||
|
val arguments = Data.Builder()
|
||||||
|
.putLong(FilesSyncWork.SYNCED_FOLDER_ID, syncedFolderID)
|
||||||
|
.build()
|
||||||
|
|
||||||
val request = periodicRequestBuilder(
|
val request = periodicRequestBuilder(
|
||||||
jobClass = FilesSyncWork::class,
|
jobClass = FilesSyncWork::class,
|
||||||
jobName = JOB_PERIODIC_FILES_SYNC,
|
jobName = JOB_PERIODIC_FILES_SYNC + "_" + syncedFolderID,
|
||||||
intervalMins = DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES
|
intervalMins = DEFAULT_PERIODIC_JOB_INTERVAL_MINUTES
|
||||||
).build()
|
)
|
||||||
workManager.enqueueUniquePeriodicWork(JOB_PERIODIC_FILES_SYNC, ExistingPeriodicWorkPolicy.REPLACE, request)
|
.setInputData(arguments)
|
||||||
|
.build()
|
||||||
|
workManager.enqueueUniquePeriodicWork(
|
||||||
|
JOB_PERIODIC_FILES_SYNC + "_" + syncedFolderID,
|
||||||
|
ExistingPeriodicWorkPolicy.REPLACE,
|
||||||
|
request
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startImmediateFilesSyncJob(
|
override fun startImmediateFilesSyncJob(
|
||||||
|
syncedFolderID: Long,
|
||||||
overridePowerSaving: Boolean,
|
overridePowerSaving: Boolean,
|
||||||
changedFiles: Array<String>
|
changedFiles: Array<String>
|
||||||
) {
|
) {
|
||||||
val arguments = Data.Builder()
|
val arguments = Data.Builder()
|
||||||
.putBoolean(FilesSyncWork.OVERRIDE_POWER_SAVING, overridePowerSaving)
|
.putBoolean(FilesSyncWork.OVERRIDE_POWER_SAVING, overridePowerSaving)
|
||||||
.putStringArray(FilesSyncWork.CHANGED_FILES, changedFiles)
|
.putStringArray(FilesSyncWork.CHANGED_FILES, changedFiles)
|
||||||
|
.putLong(FilesSyncWork.SYNCED_FOLDER_ID, syncedFolderID)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val request = oneTimeRequestBuilder(
|
val request = oneTimeRequestBuilder(
|
||||||
jobClass = FilesSyncWork::class,
|
jobClass = FilesSyncWork::class,
|
||||||
jobName = JOB_IMMEDIATE_FILES_SYNC
|
jobName = JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID
|
||||||
)
|
)
|
||||||
.setInputData(arguments)
|
.setInputData(arguments)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
workManager.enqueueUniqueWork(JOB_IMMEDIATE_FILES_SYNC, ExistingWorkPolicy.APPEND, request)
|
workManager.enqueueUniqueWork(
|
||||||
|
JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID,
|
||||||
|
ExistingWorkPolicy.APPEND,
|
||||||
|
request
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun scheduleOfflineSync() {
|
override fun scheduleOfflineSync() {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import androidx.work.WorkerParameters
|
||||||
import com.nextcloud.client.device.PowerManagementService
|
import com.nextcloud.client.device.PowerManagementService
|
||||||
import com.owncloud.android.datamodel.SyncedFolderProvider
|
import com.owncloud.android.datamodel.SyncedFolderProvider
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC
|
import com.owncloud.android.lib.common.utils.Log_OC
|
||||||
|
import com.owncloud.android.utils.FilesSyncHelper
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This work is triggered when OS detects change in media folders.
|
* This work is triggered when OS detects change in media folders.
|
||||||
|
@ -23,7 +24,7 @@ import com.owncloud.android.lib.common.utils.Log_OC
|
||||||
class ContentObserverWork(
|
class ContentObserverWork(
|
||||||
appContext: Context,
|
appContext: Context,
|
||||||
private val params: WorkerParameters,
|
private val params: WorkerParameters,
|
||||||
private val syncerFolderProvider: SyncedFolderProvider,
|
private val syncedFolderProvider: SyncedFolderProvider,
|
||||||
private val powerManagementService: PowerManagementService,
|
private val powerManagementService: PowerManagementService,
|
||||||
private val backgroundJobManager: BackgroundJobManager
|
private val backgroundJobManager: BackgroundJobManager
|
||||||
) : Worker(appContext, params) {
|
) : Worker(appContext, params) {
|
||||||
|
@ -48,13 +49,17 @@ class ContentObserverWork(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAndStartFileSyncJob() {
|
private fun checkAndStartFileSyncJob() {
|
||||||
val syncFolders = syncerFolderProvider.countEnabledSyncedFolders() > 0
|
if (!powerManagementService.isPowerSavingEnabled && syncedFolderProvider.countEnabledSyncedFolders() > 0) {
|
||||||
if (!powerManagementService.isPowerSavingEnabled && syncFolders) {
|
|
||||||
val changedFiles = mutableListOf<String>()
|
val changedFiles = mutableListOf<String>()
|
||||||
for (uri in params.triggeredContentUris) {
|
for (uri in params.triggeredContentUris) {
|
||||||
changedFiles.add(uri.toString())
|
changedFiles.add(uri.toString())
|
||||||
}
|
}
|
||||||
backgroundJobManager.startImmediateFilesSyncJob(false, changedFiles.toTypedArray())
|
FilesSyncHelper.startFilesSyncForAllFolders(
|
||||||
|
syncedFolderProvider,
|
||||||
|
backgroundJobManager,
|
||||||
|
false,
|
||||||
|
changedFiles.toTypedArray()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,8 @@ package com.nextcloud.client.jobs
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.os.Build
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.core.app.NotificationCompat
|
|
||||||
import androidx.exifinterface.media.ExifInterface
|
import androidx.exifinterface.media.ExifInterface
|
||||||
import androidx.work.ForegroundInfo
|
|
||||||
import androidx.work.Worker
|
import androidx.work.Worker
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.nextcloud.client.account.UserAccountManager
|
import com.nextcloud.client.account.UserAccountManager
|
||||||
|
@ -28,7 +25,6 @@ import com.owncloud.android.R
|
||||||
import com.owncloud.android.datamodel.ArbitraryDataProvider
|
import com.owncloud.android.datamodel.ArbitraryDataProvider
|
||||||
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
|
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
|
||||||
import com.owncloud.android.datamodel.FilesystemDataProvider
|
import com.owncloud.android.datamodel.FilesystemDataProvider
|
||||||
import com.owncloud.android.datamodel.ForegroundServiceType
|
|
||||||
import com.owncloud.android.datamodel.MediaFolderType
|
import com.owncloud.android.datamodel.MediaFolderType
|
||||||
import com.owncloud.android.datamodel.SyncedFolder
|
import com.owncloud.android.datamodel.SyncedFolder
|
||||||
import com.owncloud.android.datamodel.SyncedFolderProvider
|
import com.owncloud.android.datamodel.SyncedFolderProvider
|
||||||
|
@ -36,7 +32,6 @@ import com.owncloud.android.datamodel.UploadsStorageManager
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC
|
import com.owncloud.android.lib.common.utils.Log_OC
|
||||||
import com.owncloud.android.operations.UploadFileOperation
|
import com.owncloud.android.operations.UploadFileOperation
|
||||||
import com.owncloud.android.ui.activity.SettingsActivity
|
import com.owncloud.android.ui.activity.SettingsActivity
|
||||||
import com.owncloud.android.ui.notifications.NotificationUtils
|
|
||||||
import com.owncloud.android.utils.FileStorageUtils
|
import com.owncloud.android.utils.FileStorageUtils
|
||||||
import com.owncloud.android.utils.FilesSyncHelper
|
import com.owncloud.android.utils.FilesSyncHelper
|
||||||
import com.owncloud.android.utils.MimeType
|
import com.owncloud.android.utils.MimeType
|
||||||
|
@ -64,80 +59,32 @@ class FilesSyncWork(
|
||||||
const val TAG = "FilesSyncJob"
|
const val TAG = "FilesSyncJob"
|
||||||
const val OVERRIDE_POWER_SAVING = "overridePowerSaving"
|
const val OVERRIDE_POWER_SAVING = "overridePowerSaving"
|
||||||
const val CHANGED_FILES = "changedFiles"
|
const val CHANGED_FILES = "changedFiles"
|
||||||
const val FOREGROUND_SERVICE_ID = 414
|
const val SYNCED_FOLDER_ID = "syncedFolderId"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
private lateinit var syncedFolder: SyncedFolder
|
||||||
private fun updateForegroundWorker(progressPercent: Int, useForegroundWorker: Boolean) {
|
|
||||||
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)
|
|
||||||
.setTicker(context.getString(R.string.autoupload_worker_foreground_info))
|
|
||||||
.setContentText(context.getString(R.string.autoupload_worker_foreground_info))
|
|
||||||
.setSmallIcon(R.drawable.notification_icon)
|
|
||||||
.setContentTitle(context.getString(R.string.autoupload_worker_foreground_info))
|
|
||||||
.setOngoing(true)
|
|
||||||
.setProgress(100, progressPercent, false)
|
|
||||||
.build()
|
|
||||||
val foregroundInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
ForegroundInfo(FOREGROUND_SERVICE_ID, notification, ForegroundServiceType.DataSync.getId())
|
|
||||||
} else {
|
|
||||||
ForegroundInfo(FOREGROUND_SERVICE_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
setForegroundAsync(foregroundInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun canExitEarly(changedFiles: Array<String>?): Boolean {
|
|
||||||
var canExitEarly = false
|
|
||||||
// If we are in power save mode better to postpone scan and upload
|
|
||||||
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
|
|
||||||
if ((powerManagementService.isPowerSavingEnabled && !overridePowerSaving)) {
|
|
||||||
canExitEarly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// or sync worker already running and no changed files to be processed
|
|
||||||
val alreadyRunning = backgroundJobManager.bothFilesSyncJobsRunning()
|
|
||||||
if (alreadyRunning && changedFiles.isNullOrEmpty()) {
|
|
||||||
Log_OC.d(TAG, "File-sync kill worker since another instance of the worker seems to be running already!")
|
|
||||||
canExitEarly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!syncedFolderProvider.syncedFolders.any { it.isEnabled }) {
|
|
||||||
Log_OC.d(TAG, "File-sync kill worker since no sync folder is enabled!")
|
|
||||||
canExitEarly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncedFolderProvider.syncedFolders.all { it.isChargingOnly } &&
|
|
||||||
!powerManagementService.battery.isCharging &&
|
|
||||||
!powerManagementService.battery.isFull
|
|
||||||
) {
|
|
||||||
Log_OC.d(TAG, "File-sync kill worker since phone is not charging!")
|
|
||||||
canExitEarly = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return canExitEarly
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
override fun doWork(): Result {
|
override fun doWork(): Result {
|
||||||
backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class))
|
val syncFolderId = inputData.getLong(SYNCED_FOLDER_ID, -1)
|
||||||
Log_OC.d(TAG, "File-sync worker started")
|
|
||||||
|
|
||||||
val changedFiles = inputData.getStringArray(CHANGED_FILES)
|
val changedFiles = inputData.getStringArray(CHANGED_FILES)
|
||||||
|
|
||||||
if (canExitEarly(changedFiles)) {
|
backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class) + "_" + syncFolderId)
|
||||||
|
Log_OC.d(TAG, "File-sync worker started for folder ID: $syncFolderId")
|
||||||
|
|
||||||
|
if (canExitEarly(changedFiles, syncFolderId)) {
|
||||||
val result = Result.success()
|
val result = Result.success()
|
||||||
backgroundJobManager.logEndOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class), result)
|
backgroundJobManager.logEndOfWorker(
|
||||||
|
BackgroundJobManagerImpl.formatClassTag(this::class) +
|
||||||
|
"_" + syncFolderId,
|
||||||
|
result
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
val resources = context.resources
|
val resources = context.resources
|
||||||
val lightVersion = resources.getBoolean(R.bool.syncedFolder_light)
|
val lightVersion = resources.getBoolean(R.bool.syncedFolder_light)
|
||||||
FilesSyncHelper.restartJobsIfNeeded(
|
FilesSyncHelper.restartUploadsIfNeeded(
|
||||||
uploadsStorageManager,
|
uploadsStorageManager,
|
||||||
userAccountManager,
|
userAccountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
|
@ -145,9 +92,13 @@ class FilesSyncWork(
|
||||||
)
|
)
|
||||||
|
|
||||||
// Get changed files from ContentObserverWork (only images and videos) or by scanning filesystem
|
// Get changed files from ContentObserverWork (only images and videos) or by scanning filesystem
|
||||||
Log_OC.d(TAG, "File-sync worker changed files from observer: " + changedFiles.contentToString())
|
Log_OC.d(
|
||||||
|
TAG,
|
||||||
|
"File-sync worker (${syncedFolder.remotePath}) changed files from observer: " +
|
||||||
|
changedFiles.contentToString()
|
||||||
|
)
|
||||||
collectChangedFiles(changedFiles)
|
collectChangedFiles(changedFiles)
|
||||||
Log_OC.d(TAG, "File-sync worker finished checking files.")
|
Log_OC.d(TAG, "File-sync worker (${syncedFolder.remotePath}) finished checking files.")
|
||||||
|
|
||||||
// Create all the providers we'll need
|
// Create all the providers we'll need
|
||||||
val filesystemDataProvider = FilesystemDataProvider(contentResolver)
|
val filesystemDataProvider = FilesystemDataProvider(contentResolver)
|
||||||
|
@ -155,14 +106,6 @@ class FilesSyncWork(
|
||||||
val dateFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale)
|
val dateFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale)
|
||||||
dateFormat.timeZone = TimeZone.getTimeZone(TimeZone.getDefault().id)
|
dateFormat.timeZone = TimeZone.getTimeZone(TimeZone.getDefault().id)
|
||||||
|
|
||||||
// start upload of changed / new files
|
|
||||||
val syncedFolders = syncedFolderProvider.syncedFolders
|
|
||||||
for ((index, syncedFolder) in syncedFolders.withIndex()) {
|
|
||||||
updateForegroundWorker(
|
|
||||||
(50 + (index.toDouble() / syncedFolders.size.toDouble()) * 50).toInt(),
|
|
||||||
changedFiles.isNullOrEmpty()
|
|
||||||
)
|
|
||||||
if (syncedFolder.isEnabled) {
|
|
||||||
syncFolder(
|
syncFolder(
|
||||||
context,
|
context,
|
||||||
resources,
|
resources,
|
||||||
|
@ -172,24 +115,74 @@ class FilesSyncWork(
|
||||||
dateFormat,
|
dateFormat,
|
||||||
syncedFolder
|
syncedFolder
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
Log_OC.d(TAG, "File-sync worker (${syncedFolder.remotePath}) finished")
|
||||||
Log_OC.d(TAG, "File-sync worker finished")
|
|
||||||
val result = Result.success()
|
val result = Result.success()
|
||||||
backgroundJobManager.logEndOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class), result)
|
backgroundJobManager.logEndOfWorker(
|
||||||
|
BackgroundJobManagerImpl.formatClassTag(this::class) +
|
||||||
|
"_" + syncFolderId,
|
||||||
|
result
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setSyncedFolder(syncedFolderID: Long): Boolean {
|
||||||
|
val syncedFolderTmp = syncedFolderProvider.getSyncedFolderByID(syncedFolderID)
|
||||||
|
if (syncedFolderTmp == null || !syncedFolderTmp.isEnabled || !syncedFolderTmp.isExisting) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
syncedFolder = syncedFolderTmp
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("ReturnCount")
|
||||||
|
private fun canExitEarly(changedFiles: Array<String>?, syncedFolderID: Long): Boolean {
|
||||||
|
// If we are in power save mode better to postpone scan and upload
|
||||||
|
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
|
||||||
|
if ((powerManagementService.isPowerSavingEnabled && !overridePowerSaving)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncedFolderID < 0) {
|
||||||
|
Log_OC.d(TAG, "File-sync kill worker since no valid syncedFolderID provided!")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// or sync worker already running and no changed files to be processed
|
||||||
|
val alreadyRunning = backgroundJobManager.bothFilesSyncJobsRunning(syncedFolderID)
|
||||||
|
if (alreadyRunning && changedFiles.isNullOrEmpty()) {
|
||||||
|
Log_OC.d(
|
||||||
|
TAG,
|
||||||
|
"File-sync kill worker since another instance of the worker " +
|
||||||
|
"($syncedFolderID) seems to be running already!"
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setSyncedFolder(syncedFolderID)) {
|
||||||
|
Log_OC.d(TAG, "File-sync kill worker since syncedFolder ($syncedFolderID) is not enabled!")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncedFolder.isChargingOnly &&
|
||||||
|
!powerManagementService.battery.isCharging &&
|
||||||
|
!powerManagementService.battery.isFull
|
||||||
|
) {
|
||||||
|
Log_OC.d(TAG, "File-sync kill worker since phone is not charging (${syncedFolder.localPath})!")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
private fun collectChangedFiles(changedFiles: Array<String>?) {
|
private fun collectChangedFiles(changedFiles: Array<String>?) {
|
||||||
if (!changedFiles.isNullOrEmpty()) {
|
if (!changedFiles.isNullOrEmpty()) {
|
||||||
FilesSyncHelper.insertChangedEntries(syncedFolderProvider, changedFiles)
|
FilesSyncHelper.insertChangedEntries(syncedFolder, changedFiles)
|
||||||
} else {
|
} else {
|
||||||
// Check every file in every synced folder for changes and update
|
// Check every file in synced folder for changes and update
|
||||||
// filesystemDataProvider database (potentially needs a long time so use foreground worker)
|
// filesystemDataProvider database (potentially needs a long time)
|
||||||
updateForegroundWorker(5, true)
|
FilesSyncHelper.insertAllDBEntries(syncedFolder, powerManagementService)
|
||||||
FilesSyncHelper.insertAllDBEntries(syncedFolderProvider, powerManagementService)
|
|
||||||
updateForegroundWorker(50, true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,9 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
@Inject
|
@Inject
|
||||||
ConnectivityService connectivityService;
|
ConnectivityService connectivityService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SyncedFolderProvider syncedFolderProvider;
|
||||||
|
|
||||||
@Inject PowerManagementService powerManagementService;
|
@Inject PowerManagementService powerManagementService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -359,7 +362,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
backgroundJobManager,
|
backgroundJobManager,
|
||||||
clock,
|
clock,
|
||||||
viewThemeUtils,
|
viewThemeUtils,
|
||||||
walledCheckCache);
|
walledCheckCache,
|
||||||
|
syncedFolderProvider);
|
||||||
initContactsBackup(accountManager, backgroundJobManager);
|
initContactsBackup(accountManager, backgroundJobManager);
|
||||||
notificationChannels();
|
notificationChannels();
|
||||||
|
|
||||||
|
@ -586,7 +590,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
final BackgroundJobManager backgroundJobManager,
|
final BackgroundJobManager backgroundJobManager,
|
||||||
final Clock clock,
|
final Clock clock,
|
||||||
final ViewThemeUtils viewThemeUtils,
|
final ViewThemeUtils viewThemeUtils,
|
||||||
final WalledCheckCache walledCheckCache) {
|
final WalledCheckCache walledCheckCache,
|
||||||
|
final SyncedFolderProvider syncedFolderProvider) {
|
||||||
updateToAutoUpload();
|
updateToAutoUpload();
|
||||||
cleanOldEntries(clock);
|
cleanOldEntries(clock);
|
||||||
updateAutoUploadEntries(clock);
|
updateAutoUploadEntries(clock);
|
||||||
|
@ -600,12 +605,12 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!preferences.isAutoUploadInitialized()) {
|
if (!preferences.isAutoUploadInitialized()) {
|
||||||
backgroundJobManager.startImmediateFilesSyncJob(false, new String[]{});
|
FilesSyncHelper.startFilesSyncForAllFolders(syncedFolderProvider, backgroundJobManager,false, new String[]{});
|
||||||
preferences.setAutoUploadInit(true);
|
preferences.setAutoUploadInit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
FilesSyncHelper.scheduleFilesSyncIfNeeded(mContext, backgroundJobManager);
|
FilesSyncHelper.scheduleFilesSyncForAllFoldersIfNeeded(mContext, syncedFolderProvider, backgroundJobManager);
|
||||||
FilesSyncHelper.restartJobsIfNeeded(
|
FilesSyncHelper.restartUploadsIfNeeded(
|
||||||
uploadsStorageManager,
|
uploadsStorageManager,
|
||||||
accountManager,
|
accountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
|
|
|
@ -27,6 +27,8 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import static com.owncloud.android.datamodel.OCFile.PATH_SEPARATOR;
|
import static com.owncloud.android.datamodel.OCFile.PATH_SEPARATOR;
|
||||||
|
@ -210,6 +212,29 @@ public class SyncedFolderProvider extends Observable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public SyncedFolder getSyncedFolderByID(Long syncedFolderID) {
|
||||||
|
SyncedFolder result = null;
|
||||||
|
Cursor cursor = mContentResolver.query(
|
||||||
|
ProviderMeta.ProviderTableMeta.CONTENT_URI_SYNCED_FOLDERS,
|
||||||
|
null,
|
||||||
|
ProviderMeta.ProviderTableMeta._ID + " =? ",
|
||||||
|
new String[]{syncedFolderID.toString()},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cursor != null && cursor.getCount() == 1 && cursor.moveToFirst()) {
|
||||||
|
result = createSyncedFolderFromCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete all synced folders for an account
|
* Delete all synced folders for an account
|
||||||
*
|
*
|
||||||
|
|
|
@ -23,6 +23,7 @@ import com.nextcloud.client.network.ConnectivityService;
|
||||||
import com.nextcloud.client.network.WalledCheckCache;
|
import com.nextcloud.client.network.WalledCheckCache;
|
||||||
import com.nextcloud.client.preferences.AppPreferences;
|
import com.nextcloud.client.preferences.AppPreferences;
|
||||||
import com.owncloud.android.MainApp;
|
import com.owncloud.android.MainApp;
|
||||||
|
import com.owncloud.android.datamodel.SyncedFolderProvider;
|
||||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||||
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
import com.owncloud.android.utils.theme.ViewThemeUtils;
|
||||||
|
@ -48,6 +49,7 @@ public class BootupBroadcastReceiver extends BroadcastReceiver {
|
||||||
@Inject Clock clock;
|
@Inject Clock clock;
|
||||||
@Inject ViewThemeUtils viewThemeUtils;
|
@Inject ViewThemeUtils viewThemeUtils;
|
||||||
@Inject WalledCheckCache walledCheckCache;
|
@Inject WalledCheckCache walledCheckCache;
|
||||||
|
@Inject SyncedFolderProvider syncedFolderProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives broadcast intent reporting that the system was just boot up. *
|
* Receives broadcast intent reporting that the system was just boot up. *
|
||||||
|
@ -68,7 +70,9 @@ public class BootupBroadcastReceiver extends BroadcastReceiver {
|
||||||
backgroundJobManager,
|
backgroundJobManager,
|
||||||
clock,
|
clock,
|
||||||
viewThemeUtils,
|
viewThemeUtils,
|
||||||
walledCheckCache);
|
walledCheckCache,
|
||||||
|
syncedFolderProvider
|
||||||
|
);
|
||||||
MainApp.initContactsBackup(accountManager, backgroundJobManager);
|
MainApp.initContactsBackup(accountManager, backgroundJobManager);
|
||||||
} else {
|
} else {
|
||||||
Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction());
|
Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction());
|
||||||
|
|
|
@ -571,7 +571,7 @@ class SyncedFoldersActivity :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (syncedFolderDisplayItem.isEnabled) {
|
if (syncedFolderDisplayItem.isEnabled) {
|
||||||
backgroundJobManager.startImmediateFilesSyncJob(overridePowerSaving = false)
|
backgroundJobManager.startImmediateFilesSyncJob(syncedFolderDisplayItem.id, overridePowerSaving = false)
|
||||||
showBatteryOptimizationInfo()
|
showBatteryOptimizationInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -702,7 +702,7 @@ class SyncedFoldersActivity :
|
||||||
// existing synced folder setup to be updated
|
// existing synced folder setup to be updated
|
||||||
syncedFolderProvider.updateSyncFolder(item)
|
syncedFolderProvider.updateSyncFolder(item)
|
||||||
if (item.isEnabled) {
|
if (item.isEnabled) {
|
||||||
backgroundJobManager.startImmediateFilesSyncJob(overridePowerSaving = false)
|
backgroundJobManager.startImmediateFilesSyncJob(item.id, overridePowerSaving = false)
|
||||||
} else {
|
} else {
|
||||||
val syncedFolderInitiatedKey = KEY_SYNCED_FOLDER_INITIATED_PREFIX + item.id
|
val syncedFolderInitiatedKey = KEY_SYNCED_FOLDER_INITIATED_PREFIX + item.id
|
||||||
val arbitraryDataProvider =
|
val arbitraryDataProvider =
|
||||||
|
@ -719,7 +719,7 @@ class SyncedFoldersActivity :
|
||||||
if (storedId != -1L) {
|
if (storedId != -1L) {
|
||||||
item.id = storedId
|
item.id = storedId
|
||||||
if (item.isEnabled) {
|
if (item.isEnabled) {
|
||||||
backgroundJobManager.startImmediateFilesSyncJob(overridePowerSaving = false)
|
backgroundJobManager.startImmediateFilesSyncJob(item.id, overridePowerSaving = false)
|
||||||
} else {
|
} else {
|
||||||
val syncedFolderInitiatedKey = KEY_SYNCED_FOLDER_INITIATED_PREFIX + item.id
|
val syncedFolderInitiatedKey = KEY_SYNCED_FOLDER_INITIATED_PREFIX + item.id
|
||||||
arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey)
|
arbitraryDataProvider.deleteKeyForAccount("global", syncedFolderInitiatedKey)
|
||||||
|
|
|
@ -34,6 +34,8 @@ import com.nextcloud.model.WorkerStateLiveData;
|
||||||
import com.owncloud.android.R;
|
import com.owncloud.android.R;
|
||||||
import com.owncloud.android.databinding.UploadListLayoutBinding;
|
import com.owncloud.android.databinding.UploadListLayoutBinding;
|
||||||
import com.owncloud.android.datamodel.OCFile;
|
import com.owncloud.android.datamodel.OCFile;
|
||||||
|
import com.owncloud.android.datamodel.SyncedFolder;
|
||||||
|
import com.owncloud.android.datamodel.SyncedFolderProvider;
|
||||||
import com.owncloud.android.datamodel.UploadsStorageManager;
|
import com.owncloud.android.datamodel.UploadsStorageManager;
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
import com.owncloud.android.lib.common.operations.RemoteOperation;
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
|
||||||
|
@ -84,6 +86,9 @@ public class UploadListActivity extends FileActivity {
|
||||||
@Inject
|
@Inject
|
||||||
BackgroundJobManager backgroundJobManager;
|
BackgroundJobManager backgroundJobManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SyncedFolderProvider syncedFolderProvider;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LocalBroadcastManager localBroadcastManager;
|
LocalBroadcastManager localBroadcastManager;
|
||||||
|
|
||||||
|
@ -193,7 +198,10 @@ public class UploadListActivity extends FileActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
backgroundJobManager.startImmediateFilesSyncJob(true,new String[]{});
|
FilesSyncHelper.startFilesSyncForAllFolders(syncedFolderProvider,
|
||||||
|
backgroundJobManager,
|
||||||
|
true,
|
||||||
|
new String[]{});
|
||||||
|
|
||||||
if (uploadsStorageManager.getFailedUploads().length > 0) {
|
if (uploadsStorageManager.getFailedUploads().length > 0) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
|
@ -316,7 +324,7 @@ public class UploadListActivity extends FileActivity {
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (requestCode == FileActivity.REQUEST_CODE__UPDATE_CREDENTIALS && resultCode == RESULT_OK) {
|
if (requestCode == FileActivity.REQUEST_CODE__UPDATE_CREDENTIALS && resultCode == RESULT_OK) {
|
||||||
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager,
|
||||||
userAccountManager,
|
userAccountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
powerManagementService);
|
powerManagementService);
|
||||||
|
@ -339,7 +347,7 @@ public class UploadListActivity extends FileActivity {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// already updated -> just retry!
|
// already updated -> just retry!
|
||||||
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager,
|
||||||
userAccountManager,
|
userAccountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
powerManagementService);
|
powerManagementService);
|
||||||
|
|
|
@ -146,9 +146,8 @@ public final class FilesSyncHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void insertAllDBEntries(SyncedFolderProvider syncedFolderProvider,
|
public static void insertAllDBEntries(SyncedFolder syncedFolder,
|
||||||
PowerManagementService powerManagementService) {
|
PowerManagementService powerManagementService) {
|
||||||
for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
|
|
||||||
if (syncedFolder.isEnabled() &&
|
if (syncedFolder.isEnabled() &&
|
||||||
!(syncedFolder.isChargingOnly() &&
|
!(syncedFolder.isChargingOnly() &&
|
||||||
!powerManagementService.getBattery().isCharging() &&
|
!powerManagementService.getBattery().isCharging() &&
|
||||||
|
@ -158,22 +157,18 @@ public final class FilesSyncHelper {
|
||||||
insertAllDBEntriesForSyncedFolder(syncedFolder);
|
insertAllDBEntriesForSyncedFolder(syncedFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static void insertChangedEntries(SyncedFolderProvider syncedFolderProvider,
|
public static void insertChangedEntries(SyncedFolder syncedFolder,
|
||||||
String[] changedFiles) {
|
String[] changedFiles) {
|
||||||
final ContentResolver contentResolver = MainApp.getAppContext().getContentResolver();
|
final ContentResolver contentResolver = MainApp.getAppContext().getContentResolver();
|
||||||
final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
|
final FilesystemDataProvider filesystemDataProvider = new FilesystemDataProvider(contentResolver);
|
||||||
for (String changedFileURI : changedFiles){
|
for (String changedFileURI : changedFiles){
|
||||||
String changedFile = getFileFromURI(changedFileURI);
|
String changedFile = getFileFromURI(changedFileURI);
|
||||||
for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
|
|
||||||
if (syncedFolder.isEnabled() && syncedFolder.containsFile(changedFile)){
|
if (syncedFolder.isEnabled() && syncedFolder.containsFile(changedFile)){
|
||||||
File file = new File(changedFile);
|
File file = new File(changedFile);
|
||||||
filesystemDataProvider.storeOrUpdateFileValue(changedFile,
|
filesystemDataProvider.storeOrUpdateFileValue(changedFile,
|
||||||
file.lastModified(),file.isDirectory(),
|
file.lastModified(),file.isDirectory(),
|
||||||
syncedFolder);
|
syncedFolder);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +244,7 @@ public final class FilesSyncHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void restartJobsIfNeeded(final UploadsStorageManager uploadsStorageManager,
|
public static void restartUploadsIfNeeded(final UploadsStorageManager uploadsStorageManager,
|
||||||
final UserAccountManager accountManager,
|
final UserAccountManager accountManager,
|
||||||
final ConnectivityService connectivityService,
|
final ConnectivityService connectivityService,
|
||||||
final PowerManagementService powerManagementService) {
|
final PowerManagementService powerManagementService) {
|
||||||
|
@ -316,11 +311,23 @@ public final class FilesSyncHelper {
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void scheduleFilesSyncIfNeeded(Context context, BackgroundJobManager jobManager) {
|
public static void scheduleFilesSyncForAllFoldersIfNeeded(Context context, SyncedFolderProvider syncedFolderProvider, BackgroundJobManager jobManager) {
|
||||||
jobManager.schedulePeriodicFilesSyncJob();
|
for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
|
||||||
|
if (syncedFolder.isEnabled()) {
|
||||||
|
jobManager.schedulePeriodicFilesSyncJob(syncedFolder.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
jobManager.scheduleContentObserverJob();
|
jobManager.scheduleContentObserverJob();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void startFilesSyncForAllFolders(SyncedFolderProvider syncedFolderProvider, BackgroundJobManager jobManager, boolean overridePowerSaving, String[] changedFiles) {
|
||||||
|
for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) {
|
||||||
|
if (syncedFolder.isEnabled()) {
|
||||||
|
jobManager.startImmediateFilesSyncJob(syncedFolder.getId(),overridePowerSaving,changedFiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ public final class ReceiversHelper {
|
||||||
DNSCache.clear();
|
DNSCache.clear();
|
||||||
walledCheckCache.clear();
|
walledCheckCache.clear();
|
||||||
if (connectivityService.getConnectivity().isConnected()) {
|
if (connectivityService.getConnectivity().isConnected()) {
|
||||||
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager,
|
||||||
accountManager,
|
accountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
powerManagementService);
|
powerManagementService);
|
||||||
|
@ -76,7 +76,7 @@ public final class ReceiversHelper {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
|
if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
|
||||||
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager,
|
||||||
accountManager,
|
accountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
powerManagementService);
|
powerManagementService);
|
||||||
|
@ -102,7 +102,7 @@ public final class ReceiversHelper {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (!powerManagementService.isPowerSavingEnabled()) {
|
if (!powerManagementService.isPowerSavingEnabled()) {
|
||||||
FilesSyncHelper.restartJobsIfNeeded(uploadsStorageManager,
|
FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager,
|
||||||
accountManager,
|
accountManager,
|
||||||
connectivityService,
|
connectivityService,
|
||||||
powerManagementService);
|
powerManagementService);
|
||||||
|
|
|
@ -687,7 +687,6 @@
|
||||||
<string name="autoupload_hide_folder">Hide folder</string>
|
<string name="autoupload_hide_folder">Hide folder</string>
|
||||||
<string name="autoupload_configure">Configure</string>
|
<string name="autoupload_configure">Configure</string>
|
||||||
<string name="synced_folders_configure_folders">Configure folders</string>
|
<string name="synced_folders_configure_folders">Configure folders</string>
|
||||||
<string name="autoupload_worker_foreground_info">Preparing auto upload</string>
|
|
||||||
|
|
||||||
<string name="empty" translatable="false" />
|
<string name="empty" translatable="false" />
|
||||||
<string name="test_server_button">Test server connection</string>
|
<string name="test_server_button">Test server connection</string>
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ContentObserverWorkTest {
|
||||||
worker = ContentObserverWork(
|
worker = ContentObserverWork(
|
||||||
appContext = context,
|
appContext = context,
|
||||||
params = params,
|
params = params,
|
||||||
syncerFolderProvider = folderProvider,
|
syncedFolderProvider = folderProvider,
|
||||||
powerManagementService = powerManagementService,
|
powerManagementService = powerManagementService,
|
||||||
backgroundJobManager = backgroundJobManager
|
backgroundJobManager = backgroundJobManager
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue