mirror of
https://github.com/nextcloud/android.git
synced 2024-12-20 16:02:01 +03:00
Merge remote-tracking branch 'origin/master' into dev
This commit is contained in:
commit
880ad62cf5
6 changed files with 215 additions and 119 deletions
|
@ -27,6 +27,7 @@ import org.junit.runner.RunWith;
|
|||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
|
@ -174,15 +175,22 @@ public class UploadStorageManagerTest extends AbstractIT {
|
|||
}
|
||||
}
|
||||
|
||||
public String generateUniqueNumber() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
return uuid.toString();
|
||||
}
|
||||
|
||||
private OCUpload createUpload(Account account) {
|
||||
OCUpload upload = new OCUpload(File.separator + "very long long long long long long long long long long long " +
|
||||
"long long long long long long long long long long long long long long " +
|
||||
"long long long long long long long long long long long long long long " +
|
||||
"long long long long long long long LocalPath",
|
||||
"long long long long long long long LocalPath " +
|
||||
generateUniqueNumber(),
|
||||
OCFile.PATH_SEPARATOR + "very long long long long long long long long long " +
|
||||
"long long long long long long long long long long long long long long " +
|
||||
"long long long long long long long long long long long long long long " +
|
||||
"long long long long long long long long long long long long RemotePath",
|
||||
"long long long long long long long long long long long long RemotePath " +
|
||||
generateUniqueNumber(),
|
||||
account.name);
|
||||
|
||||
upload.setFileSize(new Random().nextInt(20000) * 10000);
|
||||
|
|
|
@ -384,6 +384,12 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
||||
android:directBootAware="false"
|
||||
android:enabled="@bool/enable_system_foreground_service_default"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync" />
|
||||
<service
|
||||
android:name=".services.OperationsService"
|
||||
android:exported="false" />
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -225,9 +225,10 @@ public class FilesystemDataProvider {
|
|||
|
||||
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();
|
||||
|
|
|
@ -87,6 +87,17 @@ public class UploadsStorageManager extends Observable {
|
|||
* @return upload id, -1 if the insert process fails.
|
||||
*/
|
||||
public long storeUpload(OCUpload ocUpload) {
|
||||
OCUpload existingUpload = getPendingCurrentOrFailedUpload(ocUpload);
|
||||
if (existingUpload != null) {
|
||||
Log_OC.v(TAG, "Will update upload in db since " + ocUpload.getLocalPath() + " already exists as " +
|
||||
"pending, current or failed upload");
|
||||
long existingId = existingUpload.getUploadId();
|
||||
ocUpload.setUploadId(existingId);
|
||||
updateUpload(ocUpload);
|
||||
return existingId;
|
||||
}
|
||||
|
||||
|
||||
Log_OC.v(TAG, "Inserting " + ocUpload.getLocalPath() + " with status=" + ocUpload.getUploadStatus());
|
||||
|
||||
ContentValues cv = getContentValues(ocUpload);
|
||||
|
@ -100,14 +111,26 @@ public class UploadsStorageManager extends Observable {
|
|||
long new_id = Long.parseLong(result.getPathSegments().get(1));
|
||||
ocUpload.setUploadId(new_id);
|
||||
notifyObserversNow();
|
||||
|
||||
return new_id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public long[] storeUploads(final List<OCUpload> ocUploads) {
|
||||
Log_OC.v(TAG, "Inserting " + ocUploads.size() + " uploads");
|
||||
ArrayList<ContentProviderOperation> operations = new ArrayList<>(ocUploads.size());
|
||||
for (OCUpload ocUpload : ocUploads) {
|
||||
|
||||
OCUpload existingUpload = getPendingCurrentOrFailedUpload(ocUpload);
|
||||
if (existingUpload != null) {
|
||||
Log_OC.v(TAG, "Will update upload in db since " + ocUpload.getLocalPath() + " already exists as" +
|
||||
" pending, current or failed upload");
|
||||
ocUpload.setUploadId(existingUpload.getUploadId());
|
||||
updateUpload(ocUpload);
|
||||
continue;
|
||||
}
|
||||
|
||||
final ContentProviderOperation operation = ContentProviderOperation
|
||||
.newInsert(ProviderTableMeta.CONTENT_URI_UPLOADS)
|
||||
.withValues(getContentValues(ocUpload))
|
||||
|
@ -260,8 +283,7 @@ public class UploadsStorageManager extends Observable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Should be called when some value of this DB was changed. All observers
|
||||
* are informed.
|
||||
* Should be called when some value of this DB was changed. All observers are informed.
|
||||
*/
|
||||
public void notifyObserversNow() {
|
||||
Log_OC.d(TAG, "notifyObserversNow");
|
||||
|
@ -345,6 +367,33 @@ public class UploadsStorageManager extends Observable {
|
|||
return getUploads(null, (String[]) null);
|
||||
}
|
||||
|
||||
public OCUpload getPendingCurrentOrFailedUpload(OCUpload upload) {
|
||||
try (Cursor cursor = getDB().query(
|
||||
ProviderTableMeta.CONTENT_URI_UPLOADS,
|
||||
null,
|
||||
ProviderTableMeta.UPLOADS_REMOTE_PATH + "=? and " +
|
||||
ProviderTableMeta.UPLOADS_LOCAL_PATH + "=? and " +
|
||||
ProviderTableMeta.UPLOADS_ACCOUNT_NAME + "=? and (" +
|
||||
ProviderTableMeta.UPLOADS_STATUS + "=? or " +
|
||||
ProviderTableMeta.UPLOADS_STATUS + "=? )",
|
||||
new String[]{
|
||||
upload.getRemotePath(),
|
||||
upload.getLocalPath(),
|
||||
upload.getAccountName(),
|
||||
String.valueOf(UploadStatus.UPLOAD_IN_PROGRESS.value),
|
||||
String.valueOf(UploadStatus.UPLOAD_FAILED.value)
|
||||
},
|
||||
ProviderTableMeta.UPLOADS_REMOTE_PATH + " ASC")) {
|
||||
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToFirst()) {
|
||||
return createOCUploadFromCursor(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public OCUpload getUploadByRemotePath(String remotePath) {
|
||||
OCUpload result = null;
|
||||
try (Cursor cursor = getDB().query(
|
||||
|
@ -717,8 +766,7 @@ public class UploadsStorageManager extends Observable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Changes the status of any in progress upload from UploadStatus.UPLOAD_IN_PROGRESS
|
||||
* to UploadStatus.UPLOAD_FAILED
|
||||
* Changes the status of any in progress upload from UploadStatus.UPLOAD_IN_PROGRESS to UploadStatus.UPLOAD_FAILED
|
||||
*
|
||||
* @return Number of uploads which status was changed.
|
||||
*/
|
||||
|
|
|
@ -628,6 +628,7 @@
|
|||
<string name="autoupload_hide_folder">Hide folder</string>
|
||||
<string name="autoupload_configure">Configure</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="test_server_button">Test server connection</string>
|
||||
|
|
Loading…
Reference in a new issue