diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 11fdfa1d941e..627b1e8a22ee 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -384,6 +384,12 @@
+
diff --git a/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt b/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt
index 8570240ba2fd..56982b5cd34e 100644
--- a/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt
+++ b/app/src/main/java/com/nextcloud/client/jobs/FilesSyncWork.kt
@@ -25,9 +25,12 @@ package com.nextcloud.client.jobs
import android.content.ContentResolver
import android.content.Context
import android.content.res.Resources
+import android.os.Build
import android.text.TextUtils
+import androidx.core.app.NotificationCompat
import androidx.exifinterface.media.ExifInterface
-import androidx.work.Worker
+import androidx.work.CoroutineWorker
+import androidx.work.ForegroundInfo
import androidx.work.WorkerParameters
import com.nextcloud.client.account.UserAccountManager
import com.nextcloud.client.device.PowerManagementService
@@ -37,6 +40,7 @@ import com.owncloud.android.R
import com.owncloud.android.datamodel.ArbitraryDataProvider
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
import com.owncloud.android.datamodel.FilesystemDataProvider
+import com.owncloud.android.datamodel.ForegroundServiceType
import com.owncloud.android.datamodel.MediaFolderType
import com.owncloud.android.datamodel.SyncedFolder
import com.owncloud.android.datamodel.SyncedFolderProvider
@@ -45,6 +49,7 @@ import com.owncloud.android.files.services.FileUploader
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.operations.UploadFileOperation
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.FilesSyncHelper
import com.owncloud.android.utils.MimeType
@@ -66,16 +71,38 @@ class FilesSyncWork(
private val powerManagementService: PowerManagementService,
private val syncedFolderProvider: SyncedFolderProvider,
private val backgroundJobManager: BackgroundJobManager
-) : Worker(context, params) {
+) : CoroutineWorker(context, params) {
companion object {
const val TAG = "FilesSyncJob"
const val SKIP_CUSTOM = "skipCustom"
const val OVERRIDE_POWER_SAVING = "overridePowerSaving"
+ const val FOREGROUND_SERVICE_ID = 414
}
- override fun doWork(): Result {
+ @Suppress("MagicNumber")
+ private fun createForegroundInfo(progressPercent: Int): ForegroundInfo {
+ // 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()
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ ForegroundInfo(FOREGROUND_SERVICE_ID, notification, ForegroundServiceType.DataSync.getId())
+ } else {
+ ForegroundInfo(FOREGROUND_SERVICE_ID, notification)
+ }
+ }
+
+ @Suppress("MagicNumber")
+ override suspend fun doWork(): Result {
backgroundJobManager.logStartOfWorker(BackgroundJobManagerImpl.formatClassTag(this::class))
+ setForeground(createForegroundInfo(0))
val overridePowerSaving = inputData.getBoolean(OVERRIDE_POWER_SAVING, false)
// If we are in power save mode, better to postpone upload
@@ -93,13 +120,18 @@ class FilesSyncWork(
connectivityService,
powerManagementService
)
+ setForeground(createForegroundInfo(5))
FilesSyncHelper.insertAllDBEntries(skipCustom, syncedFolderProvider)
+ setForeground(createForegroundInfo(50))
// Create all the providers we'll need
val filesystemDataProvider = FilesystemDataProvider(contentResolver)
val currentLocale = resources.configuration.locale
val dateFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss", currentLocale)
dateFormat.timeZone = TimeZone.getTimeZone(TimeZone.getDefault().id)
- for (syncedFolder in syncedFolderProvider.syncedFolders) {
+
+ val syncedFolders = syncedFolderProvider.syncedFolders
+ for ((index, syncedFolder) in syncedFolders.withIndex()) {
+ setForeground(createForegroundInfo((50 + (index.toDouble() / syncedFolders.size.toDouble()) * 50).toInt()))
if (syncedFolder.isEnabled && (!skipCustom || MediaFolderType.CUSTOM != syncedFolder.type)) {
syncFolder(
context,
diff --git a/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java b/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java
index 9e91738bb962..92cc7b19c982 100644
--- a/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java
+++ b/app/src/main/java/com/owncloud/android/datamodel/FilesystemDataProvider.java
@@ -55,10 +55,10 @@ public FilesystemDataProvider(ContentResolver contentResolver) {
public int deleteAllEntriesForSyncedFolder(String syncedFolderId) {
return contentResolver.delete(
- ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
- ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
- new String[]{syncedFolderId}
- );
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
+ new String[]{syncedFolderId}
+ );
}
public void updateFilesystemFileAsSentForUpload(String path, String syncedFolderId) {
@@ -66,12 +66,12 @@ public void updateFilesystemFileAsSentForUpload(String path, String syncedFolder
cv.put(ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD, 1);
contentResolver.update(
- ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
- cv,
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
- ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
- new String[]{path, syncedFolderId}
- );
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ cv,
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
+ new String[]{path, syncedFolderId}
+ );
}
public Set getFilesForUpload(String localPath, String syncedFolderId) {
@@ -80,20 +80,20 @@ public Set getFilesForUpload(String localPath, String syncedFolderId) {
String likeParam = localPath + "%";
Cursor cursor = contentResolver.query(
- ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
- null,
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " LIKE ? and " +
- ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ? and " +
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD + " = ? and " +
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER + " = ?",
- new String[]{likeParam, syncedFolderId, "0", "0"},
- null);
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ null,
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " LIKE ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER + " = ?",
+ new String[]{likeParam, syncedFolderId, "0", "0"},
+ null);
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
String value = cursor.getString(cursor.getColumnIndexOrThrow(
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
if (value == null) {
Log_OC.e(TAG, "Cannot get local path");
} else {
@@ -159,11 +159,11 @@ public void storeOrUpdateFileValue(String localPath, long modifiedAt, boolean is
int result = contentResolver.update(
- ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
- cv,
- ProviderMeta.ProviderTableMeta._ID + "=?",
- new String[]{String.valueOf(data.getId())}
- );
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ cv,
+ ProviderMeta.ProviderTableMeta._ID + "=?",
+ new String[]{String.valueOf(data.getId())}
+ );
if (result == 0) {
Log_OC.v(TAG, "Failed to update filesystem data with local path: " + localPath);
@@ -174,33 +174,33 @@ public void storeOrUpdateFileValue(String localPath, long modifiedAt, boolean is
private FileSystemDataSet getFilesystemDataSet(String localPathParam, SyncedFolder syncedFolder) {
Cursor cursor = contentResolver.query(
- ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
- null,
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
- ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
- new String[]{localPathParam, Long.toString(syncedFolder.getId())},
- null
- );
+ ProviderMeta.ProviderTableMeta.CONTENT_URI_FILESYSTEM,
+ null,
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH + " = ? and " +
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_SYNCED_FOLDER_ID + " = ?",
+ new String[]{localPathParam, Long.toString(syncedFolder.getId())},
+ null
+ );
FileSystemDataSet dataSet = null;
if (cursor != null) {
if (cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndexOrThrow(ProviderMeta.ProviderTableMeta._ID));
String localPath = cursor.getString(cursor.getColumnIndexOrThrow(
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_LOCAL_PATH));
long modifiedAt = cursor.getLong(cursor.getColumnIndexOrThrow(
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED));
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_MODIFIED));
boolean isFolder = false;
if (cursor.getInt(cursor.getColumnIndexOrThrow(
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER)) != 0) {
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_IS_FOLDER)) != 0) {
isFolder = true;
}
long foundAt = cursor.getLong(cursor.getColumnIndexOrThrow(ProviderMeta.
- ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY));
+ ProviderTableMeta.FILESYSTEM_FILE_FOUND_RECENTLY));
boolean isSentForUpload = false;
if (cursor.getInt(cursor.getColumnIndexOrThrow(
- ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD)) != 0) {
+ ProviderMeta.ProviderTableMeta.FILESYSTEM_FILE_SENT_FOR_UPLOAD)) != 0) {
isSentForUpload = true;
}
@@ -210,7 +210,7 @@ private FileSystemDataSet getFilesystemDataSet(String localPathParam, SyncedFold
Log_OC.e(TAG, "Arbitrary value could not be created from cursor");
} else {
dataSet = new FileSystemDataSet(id, localPath, modifiedAt, isFolder, isSentForUpload, foundAt,
- syncedFolder.getId(), crc32);
+ syncedFolder.getId(), crc32);
}
}
cursor.close();
@@ -223,11 +223,12 @@ private FileSystemDataSet getFilesystemDataSet(String localPathParam, SyncedFold
private long getFileChecksum(String filepath) {
- try (InputStream inputStream = new BufferedInputStream(new FileInputStream(filepath))){
+ try (InputStream inputStream = new BufferedInputStream(new FileInputStream(filepath))) {
CRC32 crc = new CRC32();
- int cnt;
- while ((cnt = inputStream.read()) != -1) {
- crc.update(cnt);
+ byte[] buf = new byte[1024 * 64];
+ int size;
+ while ((size = inputStream.read(buf)) > 0) {
+ crc.update(buf, 0, size);
}
return crc.getValue();
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7fc2bcfbbc2e..26a79a3a08c8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -628,6 +628,7 @@
Hide folder
Configure
Configure folders
+ Preparing auto upload
Test server connection