From c3278b3c258209912f000de1572bb7ba1cd3c8aa Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Tue, 16 Nov 2021 20:45:57 +0100 Subject: [PATCH 1/5] Fixes #389 app crash when file deleted during auto upload --- .../exception/FileRemovedDuringUploadException.java | 7 +++++++ .../presentation/service/AutoUploadService.java | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 domain/src/main/java/org/cryptomator/domain/exception/FileRemovedDuringUploadException.java diff --git a/domain/src/main/java/org/cryptomator/domain/exception/FileRemovedDuringUploadException.java b/domain/src/main/java/org/cryptomator/domain/exception/FileRemovedDuringUploadException.java new file mode 100644 index 000000000..eb456f523 --- /dev/null +++ b/domain/src/main/java/org/cryptomator/domain/exception/FileRemovedDuringUploadException.java @@ -0,0 +1,7 @@ +package org.cryptomator.domain.exception; + +public class FileRemovedDuringUploadException extends BackendException { + + public FileRemovedDuringUploadException() { + } +} diff --git a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java index 1ce3585a5..b0b5feee3 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java +++ b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java @@ -17,6 +17,7 @@ import org.cryptomator.domain.exception.CancellationException; import org.cryptomator.domain.exception.CloudNodeAlreadyExistsException; import org.cryptomator.domain.exception.FatalBackendException; +import org.cryptomator.domain.exception.FileRemovedDuringUploadException; import org.cryptomator.domain.exception.MissingCryptorException; import org.cryptomator.domain.exception.NoSuchCloudFileException; import org.cryptomator.domain.repository.CloudContentRepository; @@ -182,7 +183,11 @@ private void upload(ProgressAware progressAware) throws BackendExce } catch (CloudNodeAlreadyExistsException e) { Timber.tag("AutoUploadService").i("Not uploading file because it already exists in the cloud"); Timber.tag("AutoUploadService").v(format("Not uploading file because it already exists in the cloud %s", file.getFileName())); - } catch (Exception e) { + } catch (FileRemovedDuringUploadException e) { + Timber.tag("AutoUploadService").i("Not uploading file because it was removed during upload"); + Timber.tag("AutoUploadService").v(format("Not uploading file because it was removed during upload %s", file.getFileName())); + } + catch (Exception e) { cancelled = true; fileUtil.removeImagesFromAutoUploads(uploadedCloudFileNames); throw e; @@ -211,6 +216,9 @@ private CloudFile upload(UploadFile uploadFile, DataSource dataSource, ProgressA private CloudFile writeCloudFile(String fileName, CancelAwareDataSource dataSource, boolean replacing, ProgressAware progressAware) throws BackendException { Long size = dataSource.size(context); + if(size == null) { + throw new FileRemovedDuringUploadException(); + } CloudFile source = cloudContentRepository.file(parent, fileName, size); return cloudContentRepository.write(source, dataSource, progressAware, replacing, size); } From 5a1a3c22442f3e45ff8d5de9b804dbd32bb87edb Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Fri, 26 Nov 2021 14:38:23 +0100 Subject: [PATCH 2/5] Only run CI on push or labeled PR --- .github/workflows/build.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d85846e37..9ac4f6d0e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,9 @@ name: Build on: - [push, pull_request] + push: + pull_request_target: + types: [labeled] jobs: build: From 10d34dcac21e1d95dfcf95c3806640f90e53a4dd Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 29 Nov 2021 16:11:53 +0100 Subject: [PATCH 3/5] Fix crash when starting service outside of UI code (Fixes #390) Fix crash if not running, vault for the auto upload is removed and picture created --- .../presentation/CryptomatorApp.kt | 20 +++++-- .../presenter/VaultListPresenter.kt | 8 +-- .../service/AutoUploadNotification.kt | 5 ++ .../service/AutoUploadService.java | 52 +++++-------------- 4 files changed, 38 insertions(+), 47 deletions(-) diff --git a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt index 37bf82a3d..3ba4a15e4 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/CryptomatorApp.kt @@ -12,6 +12,7 @@ import androidx.multidex.MultiDexApplication import org.cryptomator.data.cloud.crypto.Cryptors import org.cryptomator.data.cloud.crypto.CryptorsModule import org.cryptomator.data.repository.RepositoryModule +import org.cryptomator.domain.Cloud import org.cryptomator.presentation.di.HasComponent import org.cryptomator.presentation.di.component.ApplicationComponent import org.cryptomator.presentation.di.component.DaggerApplicationComponent @@ -20,6 +21,7 @@ import org.cryptomator.presentation.di.module.ThreadModule import org.cryptomator.presentation.logging.CrashLogging.Companion.setup import org.cryptomator.presentation.logging.DebugLogger import org.cryptomator.presentation.logging.ReleaseLogger +import org.cryptomator.presentation.service.AutoUploadNotification import org.cryptomator.presentation.service.AutoUploadService import org.cryptomator.presentation.service.CryptorsService import org.cryptomator.util.NoOpActivityLifecycleCallbacks @@ -37,7 +39,7 @@ class CryptomatorApp : MultiDexApplication(), HasComponent private var cryptoServiceBinder: CryptorsService.Binder? = null @Volatile - private lateinit var autoUploadServiceBinder: AutoUploadService.Binder + private var autoUploadServiceBinder: AutoUploadService.Binder? = null override fun onCreate() { super.onCreate() @@ -59,8 +61,8 @@ class CryptomatorApp : MultiDexApplication(), HasComponent ) Timber.tag("App").d("appId %s", BuildConfig.APPLICATION_ID) - launchServices() initializeInjector() + launchServices() registerActivityLifecycleCallbacks(serviceNotifier) AppCompatDelegate.setDefaultNightMode(SharedPreferencesHandler(applicationContext()).screenStyleMode) cleanupCache() @@ -106,7 +108,7 @@ class CryptomatorApp : MultiDexApplication(), HasComponent override fun onServiceConnected(name: ComponentName, service: IBinder) { Timber.tag("App").i("Auto upload service connected") autoUploadServiceBinder = service as AutoUploadService.Binder - autoUploadServiceBinder.init( // + autoUploadServiceBinder?.init( // applicationComponent.cloudContentRepository(), // applicationComponent.fileUtil(), // applicationComponent.contentResolverUtil(), // @@ -120,6 +122,10 @@ class CryptomatorApp : MultiDexApplication(), HasComponent }, BIND_AUTO_CREATE) } + fun startAutoUpload(cloud: Cloud) { + autoUploadServiceBinder?.startUpload(cloud) + } + fun startAutoUpload() { val sharedPreferencesHandler = SharedPreferencesHandler(applicationContext()) if (checkToStartAutoImageUpload(sharedPreferencesHandler)) { @@ -130,9 +136,13 @@ class CryptomatorApp : MultiDexApplication(), HasComponent } if (vault?.isUnlocked == true) { val cloud = applicationComponent.cloudRepository().decryptedViewOf(vault) - applicationContext().startService(AutoUploadService.startAutoUploadIntent(applicationContext(), cloud)) + startAutoUpload(cloud) } else if (vault == null) { - applicationContext().startService(AutoUploadService.vaultNotFoundUploadIntent(applicationContext())) + autoUploadServiceBinder?.vaultNotFound() + ?: run { + Timber.tag("App").i("autoUploadServiceBinder not yet initialized, manually show notification") + AutoUploadNotification(applicationContext, 0).showVaultNotFoundNotification() + } } } } diff --git a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt index b5e6d288d..101e826b7 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/presenter/VaultListPresenter.kt @@ -33,6 +33,7 @@ import org.cryptomator.domain.usecases.vault.RenameVaultUseCase import org.cryptomator.domain.usecases.vault.SaveVaultUseCase import org.cryptomator.generator.Callback import org.cryptomator.presentation.BuildConfig +import org.cryptomator.presentation.CryptomatorApp import org.cryptomator.presentation.R import org.cryptomator.presentation.exception.ExceptionHandlers import org.cryptomator.presentation.intent.Intents @@ -42,7 +43,6 @@ import org.cryptomator.presentation.model.CloudTypeModel import org.cryptomator.presentation.model.ProgressModel import org.cryptomator.presentation.model.VaultModel import org.cryptomator.presentation.model.mappers.CloudFolderModelMapper -import org.cryptomator.presentation.service.AutoUploadService import org.cryptomator.presentation.ui.activity.LicenseCheckActivity import org.cryptomator.presentation.ui.activity.view.VaultListView import org.cryptomator.presentation.ui.dialog.AppIsObscuredInfoDialog @@ -386,12 +386,14 @@ class VaultListPresenter @Inject constructor( // .withCloud(cloud) // .run(object : DefaultResultHandler() { override fun onSuccess(folder: CloudFolder) { - val vault = (folder.cloud as CryptoCloud).vault + val cryptoCloud = (folder.cloud as CryptoCloud) + val vault = cryptoCloud.vault view?.addOrUpdateVault(VaultModel(vault)) navigateToVaultContent(vault, folder) view?.showProgress(ProgressModel.COMPLETED) if (checkToStartAutoImageUpload(vault)) { - context().startService(AutoUploadService.startAutoUploadIntent(context(), folder.cloud)) + val cryptomatorApp = activity().application as CryptomatorApp + cryptomatorApp.startAutoUpload(cryptoCloud) } } }) diff --git a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadNotification.kt b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadNotification.kt index c22b439a2..232db6e11 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadNotification.kt +++ b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadNotification.kt @@ -17,6 +17,7 @@ import org.cryptomator.presentation.ui.activity.VaultListActivity import org.cryptomator.presentation.util.ResourceHelper.Companion.getColor import org.cryptomator.presentation.util.ResourceHelper.Companion.getString import java.lang.String.format +import timber.log.Timber class AutoUploadNotification(private val context: Context, private val amountOfPictures: Int) { @@ -85,18 +86,22 @@ class AutoUploadNotification(private val context: Context, private val amountOfP } fun showFolderMissing() { + Timber.tag("AutoUploadNotification").i("Show folder not found notification") showErrorWithMessage(context.getString(R.string.notification_auto_upload_failed_due_to_folder_not_exists)) } fun showVaultLockedDuringUpload() { + Timber.tag("AutoUploadNotification").i("Show vault locked during upload notification") showErrorWithMessage(context.getString(R.string.notification_auto_upload_failed_due_to_vault_locked)) } fun showGeneralErrorDuringUpload() { + Timber.tag("AutoUploadNotification").i("Show general error during upload notficiation") showErrorWithMessage(context.getString(R.string.notification_auto_upload_failed_general_error)) } fun showVaultNotFoundNotification() { + Timber.tag("AutoUploadNotification").i("Show vault not found notification") showErrorWithMessage(context.getString(R.string.notification_auto_upload_failed_due_to_vault_not_found)) } diff --git a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java index b0b5feee3..b4a56aecb 100644 --- a/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java +++ b/presentation/src/main/java/org/cryptomator/presentation/service/AutoUploadService.java @@ -1,5 +1,8 @@ package org.cryptomator.presentation.service; +import static org.cryptomator.domain.usecases.cloud.UploadFile.anUploadFile; +import static java.lang.String.format; + import android.app.Service; import android.content.Context; import android.content.Intent; @@ -43,16 +46,10 @@ import timber.log.Timber; -import static java.lang.String.format; -import static org.cryptomator.domain.usecases.cloud.UploadFile.anUploadFile; - public class AutoUploadService extends Service { - private static final String ACTION_START_AUTO_UPLOAD = "START_AUTO_UPLOAD"; private static final String ACTION_CANCEL_AUTO_UPLOAD = "CANCEL_AUTO_UPLOAD"; - private static final String ACTION_VAULT_NOT_FOUND = "VAULT_NOT_FOUND"; - private static Cloud cloud; private AutoUploadNotification notification; private CloudContentRepository cloudContentRepository; private ContentResolverUtil contentResolverUtil; @@ -71,25 +68,12 @@ public boolean get() { } }; - public static Intent startAutoUploadIntent(Context context, Cloud myCloud) { - cloud = myCloud; - Intent startAutoUpload = new Intent(context, AutoUploadService.class); - startAutoUpload.setAction(ACTION_START_AUTO_UPLOAD); - return startAutoUpload; - } - public static Intent cancelAutoUploadIntent(Context context) { Intent cancelAutoUploadIntent = new Intent(context, AutoUploadService.class); cancelAutoUploadIntent.setAction(ACTION_CANCEL_AUTO_UPLOAD); return cancelAutoUploadIntent; } - public static Intent vaultNotFoundUploadIntent(Context context) { - Intent cancelAutoUploadIntent = new Intent(context, AutoUploadService.class); - cancelAutoUploadIntent.setAction(ACTION_VAULT_NOT_FOUND); - return cancelAutoUploadIntent; - } - private void startBackgroundImageUpload(Cloud cloud) { try { uploadFiles = getUploadFiles(fileUtil.getAutoUploadFilesStore()); @@ -233,36 +217,18 @@ public void onCreate() { @Override public int onStartCommand(Intent intent, int flags, int startId) { Timber.tag("AutoUploadService").i("started"); - if (isStartAutoUpload(intent)) { - Timber.tag("AutoUploadService").i("Received start upload"); - - startBackgroundImageUpload(cloud); - } else if (isCancelAutoUpload(intent)) { + if (isCancelAutoUpload(intent)) { Timber.tag("AutoUploadService").i("Received stop auto upload"); cancelled = true; hideNotification(); - } else if(isVaultNotFound(intent)) { - Timber.tag("AutoUploadService").i("Received show vault not found notification"); - notification.showVaultNotFoundNotification(); } return START_STICKY; } - private boolean isStartAutoUpload(Intent intent) { - return intent != null // - && ACTION_START_AUTO_UPLOAD.equals(intent.getAction()); - } - private boolean isCancelAutoUpload(Intent intent) { - return intent != null // - && ACTION_CANCEL_AUTO_UPLOAD.equals(intent.getAction()); - } - - private boolean isVaultNotFound(Intent intent) { - return intent != null // - && ACTION_VAULT_NOT_FOUND.equals(intent.getAction()); + return intent != null && ACTION_CANCEL_AUTO_UPLOAD.equals(intent.getAction()); } @Override @@ -302,5 +268,13 @@ public void init(CloudContentRepository myCloudContentRepository, FileUtil myFil contentResolverUtil = myContentResolverUtil; context = myContext; } + + public void startUpload(Cloud cloud) { + startBackgroundImageUpload(cloud); + } + + public void vaultNotFound() { + notification.showVaultNotFoundNotification(); + } } } From 08df2b06a4da27130ff0554fda69818595147eeb Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 29 Nov 2021 17:09:03 +0100 Subject: [PATCH 4/5] Bump version to 1.6.5 [ci skip] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2be316948..d4bc385ec 100644 --- a/build.gradle +++ b/build.gradle @@ -39,7 +39,7 @@ allprojects { ext { androidApplicationId = 'org.cryptomator' androidVersionCode = getVersionCode() - androidVersionName = '1.7.0-SNAPSHOT' + androidVersionName = '1.6.5' } repositories { mavenCentral() From e0e3192707cb259e70b3f4dfceb104380c26af89 Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Mon, 29 Nov 2021 17:29:58 +0100 Subject: [PATCH 5/5] Update dependencies --- build.gradle | 2 +- buildsystem/dependencies.gradle | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index d4bc385ec..b1bbf6e48 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ apply from: 'buildsystem/dependencies.gradle' apply plugin: "com.vanniktech.android.junit.jacoco" buildscript { - ext.kotlin_version = '1.5.31' + ext.kotlin_version = '1.6.0' repositories { mavenCentral() google() diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle index c18d9e0fd..3375dcb97 100644 --- a/buildsystem/dependencies.gradle +++ b/buildsystem/dependencies.gradle @@ -29,12 +29,12 @@ ext { rxAndroidVersion = '2.1.1' rxBindingVersion = '2.2.0' - daggerVersion = '2.40' + daggerVersion = '2.40.2' - gsonVersion = '2.8.8' + gsonVersion = '2.8.9' okHttpVersion = '4.9.2' - okHttpDigestVersion = '2.5' + okHttpDigestVersion = '2.6' velocityVersion = '2.3' @@ -74,9 +74,9 @@ ext { // testing dependencies - jUnitVersion = '5.8.1' + jUnitVersion = '5.8.2' assertJVersion = '1.7.1' - mockitoVersion = '4.0.0' + mockitoVersion = '4.1.0' mockitoKotlinVersion = '4.0.0' hamcrestVersion = '1.3' dexmakerVersion = '1.0'