Loading app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +12 −10 Original line number Diff line number Diff line Loading @@ -8,11 +8,13 @@ package foundation.e.drive.FileObservers; import static foundation.e.drive.models.SyncRequest.Type.REMOTE_DELETE; import static foundation.e.drive.models.SyncRequest.Type.DISABLE_SYNCING; import static foundation.e.drive.models.SyncRequest.Type.UPLOAD; import static foundation.e.drive.models.SyncedFileState.DEVICE_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.ECLOUD_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.NOT_SCANNABLE; import android.content.Context; import android.content.Intent; import android.os.FileObserver; import androidx.annotation.NonNull; Loading @@ -25,7 +27,6 @@ import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncRequest; import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.services.SynchronizationService; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.SynchronizationServiceConnection; import timber.log.Timber; Loading Loading @@ -192,10 +193,10 @@ public class FileEventListener { Timber.d("Won't send sync request: no parent are known for new file: %s", file.getName()); return; } int scannableValue = 0; int scannableValue = NOT_SCANNABLE; if (parentFolder.isEnabled()) { if (parentFolder.isScanRemote()) scannableValue++; if (parentFolder.isScanLocal()) scannableValue += 2; if (parentFolder.isScanRemote()) scannableValue = ECLOUD_SCANNABLE; if (parentFolder.isScanLocal()) scannableValue += DEVICE_SCANNABLE; } final String remotePath = parentFolder.getRemoteFolder()+file.getName(); Loading @@ -209,7 +210,7 @@ public class FileEventListener { } } else { //File update final boolean isWaitingForDownload = fileState.isLastEtagStored() && fileState.getLocalLastModified() == 0L; if (fileState.getScannable() > 1 && !isWaitingForDownload) { if (fileState.getScannable() > ECLOUD_SCANNABLE && !isWaitingForDownload) { request = new SyncRequest(fileState, UPLOAD); } } Loading @@ -231,9 +232,10 @@ public class FileEventListener { } //If already in DB if (fileState.getScannable() > 0) { SyncRequest deleteRequest = new SyncRequest(fileState, REMOTE_DELETE); this.sendSyncRequestToSynchronizationService(deleteRequest); if (fileState.getScannable() > NOT_SCANNABLE) { //todo: if file is already sync disabled, we should probably remove file from DB final SyncRequest disableSyncingRequest = new SyncRequest(fileState, DISABLE_SYNCING); this.sendSyncRequestToSynchronizationService(disableSyncingRequest); } } Loading app/src/main/java/foundation/e/drive/RecycleBin.ktdeleted 100644 → 0 +0 −86 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ @file:JvmName("RecycleBin") package foundation.e.drive import foundation.e.drive.utils.AppConstants import timber.log.Timber import java.io.File import java.io.IOException import java.nio.file.Files import kotlin.io.path.Path import kotlin.time.Duration import kotlin.time.DurationUnit import kotlin.time.toDuration /** * This class contains method for trashing file & cleaning the trash */ object RecycleBin { private val DELAY_FOR_DELETION = 30.toDuration(DurationUnit.DAYS) private val BIN_PATH = AppConstants.RECYCLE_BIN_PATH //TMP only, Need to find a way to get context /** * Remove files which are in recycle bin * for more than DELAY_FOR_DELETION * @return false as soon as some files that should be removed is not removed */ fun clearOldestFiles(): Boolean { val binDir = File(BIN_PATH) if (!binDir.exists()) return true try { val filesToRemove = binDir.listFiles { file -> computeTimeInBin(file.lastModified()) > DELAY_FOR_DELETION } filesToRemove?.forEach { file -> file?.delete() } } catch (exception: IOException) { //Note that some files might have already been removed Timber.e(exception, "Caught exception when clearing oldest file in bin") return false } return true } /** * Compute time from which file is in Bin * and return it as a Duration in days */ private fun computeTimeInBin(fileLastModified: Long): Duration { return (System.currentTimeMillis() - fileLastModified).toDuration(DurationUnit.DAYS) } /** * put a file into the bin */ fun trashFile(file: File): Boolean { File(BIN_PATH).mkdirs() //Assert that recycle bin exist if (file.exists()) { val targetPath = File(BIN_PATH, file.name).absolutePath try { val moveResult = Files.move(file.toPath(), Path(targetPath)) if (moveResult.toFile().exists()) { return true } } catch (exception: IOException) { Timber.e(exception) } catch (exception: SecurityException) { Timber.e(exception) } catch (exception: NullPointerException) { Timber.e(exception) } } Timber.d("Can't move %s to trashbin", file.absolutePath) return false } } No newline at end of file app/src/main/java/foundation/e/drive/contentScanner/AbstractContentScanner.java +4 −1 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ public abstract class AbstractContentScanner<T> { } for (SyncedFileState remainingFileState : fileStates) { if (remainingFileState.getScannable() == SyncedFileState.NOT_SCANNABLE) { continue; } onMissingFile(remainingFileState); } return syncRequests; Loading app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java +11 −5 Original line number Diff line number Diff line Loading @@ -7,6 +7,10 @@ */ package foundation.e.drive.contentScanner; import static foundation.e.drive.models.SyncedFileState.DEVICE_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.ECLOUD_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.NOT_SCANNABLE; import android.content.Context; import androidx.annotation.NonNull; Loading Loading @@ -44,9 +48,9 @@ public class LocalContentScanner extends AbstractContentScanner<File>{ Timber.d("Expected %s to be missing. but it still exists", file.getAbsolutePath()); return; } //todo: should we check if already sync disabled, and then remove it from DB ? Timber.d("Add remove SyncRequest for file %s", file.getAbsolutePath()); syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.REMOTE_DELETE)); syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.DISABLE_SYNCING)); } @Override Loading @@ -55,10 +59,10 @@ public class LocalContentScanner extends AbstractContentScanner<File>{ final SyncedFolder parentDir = getParentSyncedFolder(filePath); if (parentDir == null) return; int scannableValue = 0; int scannableValue = NOT_SCANNABLE; if (parentDir.isEnabled()) { if (parentDir.isScanRemote()) scannableValue++; if (parentDir.isScanLocal()) scannableValue += 2; if (parentDir.isScanRemote()) scannableValue += ECLOUD_SCANNABLE; if (parentDir.isScanLocal()) scannableValue += DEVICE_SCANNABLE; } final SyncedFileState newSyncedFileState = new SyncedFileState(-1, file.getName(), filePath, parentDir.getRemoteFolder() + file.getName(), "", 0, parentDir.getId(), parentDir.isMediaType(),scannableValue); Loading @@ -73,6 +77,8 @@ public class LocalContentScanner extends AbstractContentScanner<File>{ @Override protected void onKnownFileFound(@NonNull File file, @NonNull SyncedFileState fileState) { if (fileState.getScannable() == NOT_SCANNABLE) return; if (FileDiffUtils.getActionForFileDiff(file, fileState) == FileDiffUtils.Action.Upload) { Timber.d("Add upload SyncRequest for %s", file.getAbsolutePath()); syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.UPLOAD)); Loading app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java +11 −6 Original line number Diff line number Diff line Loading @@ -7,7 +7,10 @@ */ package foundation.e.drive.contentScanner; import static foundation.e.drive.models.SyncRequest.Type.LOCAL_DELETE; import static foundation.e.drive.models.SyncRequest.Type.DISABLE_SYNCING; import static foundation.e.drive.models.SyncedFileState.DEVICE_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.ECLOUD_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.NOT_SCANNABLE; import static foundation.e.drive.utils.FileDiffUtils.getActionForFileDiff; import android.content.Context; Loading Loading @@ -43,6 +46,8 @@ public class RemoteContentScanner extends AbstractContentScanner<RemoteFile> { @Override protected void onKnownFileFound(@NonNull RemoteFile file, @NonNull SyncedFileState fileState) { if (fileState.getScannable() == NOT_SCANNABLE) return; final FileDiffUtils.Action action = getActionForFileDiff(file, fileState); if (action == FileDiffUtils.Action.Download) { Loading @@ -66,10 +71,10 @@ public class RemoteContentScanner extends AbstractContentScanner<RemoteFile> { final String fileName = CommonUtils.getFileNameFromPath(remoteFilePath); int scannableValue = 0; int scannableValue = NOT_SCANNABLE; if (parentDir.isEnabled()) { if (parentDir.isScanRemote()) scannableValue++; if (parentDir.isScanLocal()) scannableValue += 2; if (parentDir.isScanRemote()) scannableValue += ECLOUD_SCANNABLE; if (parentDir.isScanLocal()) scannableValue += DEVICE_SCANNABLE; } final SyncedFileState newFileState = new SyncedFileState(-1, fileName, parentDir.getLocalFolder() + fileName, remoteFilePath, file.getEtag(), 0, parentDir.getId(), parentDir.isMediaType(), scannableValue); Loading @@ -88,8 +93,8 @@ public class RemoteContentScanner extends AbstractContentScanner<RemoteFile> { return; } Timber.d("Add local deletion request for file: %s", fileState.getLocalPath()); this.syncRequests.put(fileState.getId(), new SyncRequest(fileState, LOCAL_DELETE)); Timber.d("Add Disable syncing request for file: %s", fileState.getLocalPath()); this.syncRequests.put(fileState.getId(), new SyncRequest(fileState, DISABLE_SYNCING)); } @Override Loading Loading
app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +12 −10 Original line number Diff line number Diff line Loading @@ -8,11 +8,13 @@ package foundation.e.drive.FileObservers; import static foundation.e.drive.models.SyncRequest.Type.REMOTE_DELETE; import static foundation.e.drive.models.SyncRequest.Type.DISABLE_SYNCING; import static foundation.e.drive.models.SyncRequest.Type.UPLOAD; import static foundation.e.drive.models.SyncedFileState.DEVICE_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.ECLOUD_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.NOT_SCANNABLE; import android.content.Context; import android.content.Intent; import android.os.FileObserver; import androidx.annotation.NonNull; Loading @@ -25,7 +27,6 @@ import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncRequest; import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFolder; import foundation.e.drive.services.SynchronizationService; import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.SynchronizationServiceConnection; import timber.log.Timber; Loading Loading @@ -192,10 +193,10 @@ public class FileEventListener { Timber.d("Won't send sync request: no parent are known for new file: %s", file.getName()); return; } int scannableValue = 0; int scannableValue = NOT_SCANNABLE; if (parentFolder.isEnabled()) { if (parentFolder.isScanRemote()) scannableValue++; if (parentFolder.isScanLocal()) scannableValue += 2; if (parentFolder.isScanRemote()) scannableValue = ECLOUD_SCANNABLE; if (parentFolder.isScanLocal()) scannableValue += DEVICE_SCANNABLE; } final String remotePath = parentFolder.getRemoteFolder()+file.getName(); Loading @@ -209,7 +210,7 @@ public class FileEventListener { } } else { //File update final boolean isWaitingForDownload = fileState.isLastEtagStored() && fileState.getLocalLastModified() == 0L; if (fileState.getScannable() > 1 && !isWaitingForDownload) { if (fileState.getScannable() > ECLOUD_SCANNABLE && !isWaitingForDownload) { request = new SyncRequest(fileState, UPLOAD); } } Loading @@ -231,9 +232,10 @@ public class FileEventListener { } //If already in DB if (fileState.getScannable() > 0) { SyncRequest deleteRequest = new SyncRequest(fileState, REMOTE_DELETE); this.sendSyncRequestToSynchronizationService(deleteRequest); if (fileState.getScannable() > NOT_SCANNABLE) { //todo: if file is already sync disabled, we should probably remove file from DB final SyncRequest disableSyncingRequest = new SyncRequest(fileState, DISABLE_SYNCING); this.sendSyncRequestToSynchronizationService(disableSyncingRequest); } } Loading
app/src/main/java/foundation/e/drive/RecycleBin.ktdeleted 100644 → 0 +0 −86 Original line number Diff line number Diff line /* * Copyright © MURENA SAS 2023. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ @file:JvmName("RecycleBin") package foundation.e.drive import foundation.e.drive.utils.AppConstants import timber.log.Timber import java.io.File import java.io.IOException import java.nio.file.Files import kotlin.io.path.Path import kotlin.time.Duration import kotlin.time.DurationUnit import kotlin.time.toDuration /** * This class contains method for trashing file & cleaning the trash */ object RecycleBin { private val DELAY_FOR_DELETION = 30.toDuration(DurationUnit.DAYS) private val BIN_PATH = AppConstants.RECYCLE_BIN_PATH //TMP only, Need to find a way to get context /** * Remove files which are in recycle bin * for more than DELAY_FOR_DELETION * @return false as soon as some files that should be removed is not removed */ fun clearOldestFiles(): Boolean { val binDir = File(BIN_PATH) if (!binDir.exists()) return true try { val filesToRemove = binDir.listFiles { file -> computeTimeInBin(file.lastModified()) > DELAY_FOR_DELETION } filesToRemove?.forEach { file -> file?.delete() } } catch (exception: IOException) { //Note that some files might have already been removed Timber.e(exception, "Caught exception when clearing oldest file in bin") return false } return true } /** * Compute time from which file is in Bin * and return it as a Duration in days */ private fun computeTimeInBin(fileLastModified: Long): Duration { return (System.currentTimeMillis() - fileLastModified).toDuration(DurationUnit.DAYS) } /** * put a file into the bin */ fun trashFile(file: File): Boolean { File(BIN_PATH).mkdirs() //Assert that recycle bin exist if (file.exists()) { val targetPath = File(BIN_PATH, file.name).absolutePath try { val moveResult = Files.move(file.toPath(), Path(targetPath)) if (moveResult.toFile().exists()) { return true } } catch (exception: IOException) { Timber.e(exception) } catch (exception: SecurityException) { Timber.e(exception) } catch (exception: NullPointerException) { Timber.e(exception) } } Timber.d("Can't move %s to trashbin", file.absolutePath) return false } } No newline at end of file
app/src/main/java/foundation/e/drive/contentScanner/AbstractContentScanner.java +4 −1 Original line number Diff line number Diff line Loading @@ -68,6 +68,9 @@ public abstract class AbstractContentScanner<T> { } for (SyncedFileState remainingFileState : fileStates) { if (remainingFileState.getScannable() == SyncedFileState.NOT_SCANNABLE) { continue; } onMissingFile(remainingFileState); } return syncRequests; Loading
app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java +11 −5 Original line number Diff line number Diff line Loading @@ -7,6 +7,10 @@ */ package foundation.e.drive.contentScanner; import static foundation.e.drive.models.SyncedFileState.DEVICE_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.ECLOUD_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.NOT_SCANNABLE; import android.content.Context; import androidx.annotation.NonNull; Loading Loading @@ -44,9 +48,9 @@ public class LocalContentScanner extends AbstractContentScanner<File>{ Timber.d("Expected %s to be missing. but it still exists", file.getAbsolutePath()); return; } //todo: should we check if already sync disabled, and then remove it from DB ? Timber.d("Add remove SyncRequest for file %s", file.getAbsolutePath()); syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.REMOTE_DELETE)); syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.DISABLE_SYNCING)); } @Override Loading @@ -55,10 +59,10 @@ public class LocalContentScanner extends AbstractContentScanner<File>{ final SyncedFolder parentDir = getParentSyncedFolder(filePath); if (parentDir == null) return; int scannableValue = 0; int scannableValue = NOT_SCANNABLE; if (parentDir.isEnabled()) { if (parentDir.isScanRemote()) scannableValue++; if (parentDir.isScanLocal()) scannableValue += 2; if (parentDir.isScanRemote()) scannableValue += ECLOUD_SCANNABLE; if (parentDir.isScanLocal()) scannableValue += DEVICE_SCANNABLE; } final SyncedFileState newSyncedFileState = new SyncedFileState(-1, file.getName(), filePath, parentDir.getRemoteFolder() + file.getName(), "", 0, parentDir.getId(), parentDir.isMediaType(),scannableValue); Loading @@ -73,6 +77,8 @@ public class LocalContentScanner extends AbstractContentScanner<File>{ @Override protected void onKnownFileFound(@NonNull File file, @NonNull SyncedFileState fileState) { if (fileState.getScannable() == NOT_SCANNABLE) return; if (FileDiffUtils.getActionForFileDiff(file, fileState) == FileDiffUtils.Action.Upload) { Timber.d("Add upload SyncRequest for %s", file.getAbsolutePath()); syncRequests.put(fileState.getId(), new SyncRequest(fileState, SyncRequest.Type.UPLOAD)); Loading
app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java +11 −6 Original line number Diff line number Diff line Loading @@ -7,7 +7,10 @@ */ package foundation.e.drive.contentScanner; import static foundation.e.drive.models.SyncRequest.Type.LOCAL_DELETE; import static foundation.e.drive.models.SyncRequest.Type.DISABLE_SYNCING; import static foundation.e.drive.models.SyncedFileState.DEVICE_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.ECLOUD_SCANNABLE; import static foundation.e.drive.models.SyncedFileState.NOT_SCANNABLE; import static foundation.e.drive.utils.FileDiffUtils.getActionForFileDiff; import android.content.Context; Loading Loading @@ -43,6 +46,8 @@ public class RemoteContentScanner extends AbstractContentScanner<RemoteFile> { @Override protected void onKnownFileFound(@NonNull RemoteFile file, @NonNull SyncedFileState fileState) { if (fileState.getScannable() == NOT_SCANNABLE) return; final FileDiffUtils.Action action = getActionForFileDiff(file, fileState); if (action == FileDiffUtils.Action.Download) { Loading @@ -66,10 +71,10 @@ public class RemoteContentScanner extends AbstractContentScanner<RemoteFile> { final String fileName = CommonUtils.getFileNameFromPath(remoteFilePath); int scannableValue = 0; int scannableValue = NOT_SCANNABLE; if (parentDir.isEnabled()) { if (parentDir.isScanRemote()) scannableValue++; if (parentDir.isScanLocal()) scannableValue += 2; if (parentDir.isScanRemote()) scannableValue += ECLOUD_SCANNABLE; if (parentDir.isScanLocal()) scannableValue += DEVICE_SCANNABLE; } final SyncedFileState newFileState = new SyncedFileState(-1, fileName, parentDir.getLocalFolder() + fileName, remoteFilePath, file.getEtag(), 0, parentDir.getId(), parentDir.isMediaType(), scannableValue); Loading @@ -88,8 +93,8 @@ public class RemoteContentScanner extends AbstractContentScanner<RemoteFile> { return; } Timber.d("Add local deletion request for file: %s", fileState.getLocalPath()); this.syncRequests.put(fileState.getId(), new SyncRequest(fileState, LOCAL_DELETE)); Timber.d("Add Disable syncing request for file: %s", fileState.getLocalPath()); this.syncRequests.put(fileState.getId(), new SyncRequest(fileState, DISABLE_SYNCING)); } @Override Loading