diff --git a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java index 5f9a07f442b51d78fa0092a4f9fa854091079d96..6cec272c34989bab085eec4a9f2a68c3614deb82 100644 --- a/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java +++ b/app/src/main/java/foundation/e/drive/FileObservers/FileEventListener.java @@ -13,13 +13,14 @@ 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 static foundation.e.drive.utils.FileUtils.getLocalPath; import android.content.Context; import android.os.FileObserver; import androidx.annotation.NonNull; -import com.owncloud.android.lib.resources.files.FileUtils; +import static com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR; import java.io.File; @@ -28,7 +29,6 @@ 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; @@ -125,10 +125,10 @@ public class FileEventListener { */ private void handleDirectoryCreate(@NonNull File directory) { Timber.d("handleDirectoryCreate( %s )",directory.getAbsolutePath()); - final String parentPath = CommonUtils.getLocalPath(directory.getParentFile()); + final String parentPath = getLocalPath(directory.getParentFile()); final SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); if (parentFolder != null) { - final SyncedFolder folder = new SyncedFolder(parentFolder, directory.getName() + FileUtils.PATH_SEPARATOR, directory.lastModified(), ""); + final SyncedFolder folder = new SyncedFolder(parentFolder, directory.getName() + PATH_SEPARATOR, directory.lastModified(), ""); DbHelper.insertSyncedFolder(folder, appContext); } } @@ -139,7 +139,7 @@ public class FileEventListener { * @param directory */ private void handleDirectoryCloseWrite(@NonNull File directory) { - final String fileLocalPath = CommonUtils.getLocalPath(directory); + final String fileLocalPath = getLocalPath(directory); Timber.d("handleDirectoryCloseWrite( %s )",fileLocalPath ); final SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { @@ -155,7 +155,7 @@ public class FileEventListener { * @param directory */ private void handleDirectoryDelete(@NonNull File directory) { - final String fileLocalPath = CommonUtils.getLocalPath(directory); + final String fileLocalPath = getLocalPath(directory); Timber.d("handleDirectoryDelete( %s )", fileLocalPath); SyncedFolder folder = DbHelper.getSyncedFolderByLocalPath(fileLocalPath, appContext); if (folder == null) { @@ -163,12 +163,12 @@ public class FileEventListener { final File parentFile = directory.getParentFile(); if (parentFile == null) return; - final String parentPath = CommonUtils.getLocalPath(parentFile); + final String parentPath = getLocalPath(parentFile); final SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); if (parentFolder == null ) { //if parent is not in the DB return; } - folder = new SyncedFolder(parentFolder, directory.getName()+ FileUtils.PATH_SEPARATOR, directory.lastModified(), ""); + folder = new SyncedFolder(parentFolder, directory.getName() + PATH_SEPARATOR, directory.lastModified(), ""); folder.setEnabled(false); DbHelper.insertSyncedFolder(folder, appContext); } else if (folder.isEnabled()) { @@ -182,13 +182,13 @@ public class FileEventListener { * @param file */ private void handleFileCloseWrite(@NonNull File file) { - final String fileLocalPath = CommonUtils.getLocalPath(file); + final String fileLocalPath = getLocalPath(file); Timber.d("handleFileCloseWrite( %s )", fileLocalPath); SyncRequest request = null; SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); if (fileState == null) { //New file discovered - final String parentPath = CommonUtils.getLocalPath(file.getParentFile()); + final String parentPath = getLocalPath(file.getParentFile()); SyncedFolder parentFolder = DbHelper.getSyncedFolderByLocalPath(parentPath, appContext); if (parentFolder == null || !parentFolder.isEnabled()) { Timber.d("Won't send sync request: no parent are known for new file: %s", file.getName()); @@ -201,7 +201,7 @@ public class FileEventListener { } final String remotePath = parentFolder.getRemoteFolder()+file.getName(); - fileState = new SyncedFileState(-1, file.getName(), CommonUtils.getLocalPath(file), remotePath, "", 0L, parentFolder.getId(), parentFolder.isMediaType(), scannableValue); + fileState = new SyncedFileState(-1, file.getName(), getLocalPath(file), remotePath, "", 0L, parentFolder.getId(), parentFolder.isMediaType(), scannableValue); int storedId = DbHelper.manageSyncedFileStateDB(fileState, "INSERT", appContext); if (storedId > 0) { fileState.setId(storedId); @@ -225,7 +225,7 @@ public class FileEventListener { * @param file */ private void handleFileDelete(@NonNull File file) { - final String fileLocalPath = CommonUtils.getLocalPath(file); + final String fileLocalPath = getLocalPath(file); Timber.d("handleFileDelete( %s )",fileLocalPath); final SyncedFileState fileState = DbHelper.loadSyncedFile( appContext, fileLocalPath, true); if (fileState == null) { diff --git a/app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java b/app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java index 1a9417c7307d2f8f6bad286ba7687ef9fd415498..bd637fa63ebb53bd9ec4c333211fb283fe7c84d4 100644 --- a/app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java +++ b/app/src/main/java/foundation/e/drive/contentScanner/LocalContentScanner.java @@ -22,8 +22,8 @@ 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.utils.CommonUtils; import foundation.e.drive.utils.FileDiffUtils; +import foundation.e.drive.utils.FileUtils; import timber.log.Timber; /** @@ -92,7 +92,7 @@ public class LocalContentScanner extends AbstractContentScanner{ @Override protected boolean isFileMatchingSyncedFileState(@NonNull File file, @NonNull SyncedFileState fileState) { - final String filePath = CommonUtils.getLocalPath(file); + final String filePath = FileUtils.getLocalPath(file); final String localPath = fileState.getLocalPath(); return localPath != null && localPath.equals(filePath); diff --git a/app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java b/app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java index 25b008ad7be975ac10062361304a8389d37d625b..3a7d500fa46232a20b401fe2dca04ea15954e316 100644 --- a/app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java +++ b/app/src/main/java/foundation/e/drive/contentScanner/RemoteContentScanner.java @@ -26,8 +26,8 @@ import foundation.e.drive.models.DownloadRequest; import foundation.e.drive.models.SyncRequest; import foundation.e.drive.models.SyncedFileState; import foundation.e.drive.models.SyncedFolder; -import foundation.e.drive.utils.CommonUtils; import foundation.e.drive.utils.FileDiffUtils; +import foundation.e.drive.utils.FileUtils; import timber.log.Timber; /** @@ -69,7 +69,7 @@ public class RemoteContentScanner extends AbstractContentScanner { final SyncedFolder parentDir = getParentSyncedFolder(remoteFilePath); if (parentDir == null) return; - final String fileName = CommonUtils.getFileNameFromPath(remoteFilePath); + final String fileName = FileUtils.getFileNameFromPath(remoteFilePath); int scannableValue = NOT_SCANNABLE; if (parentDir.isEnabled()) { diff --git a/app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java b/app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java index f8ae821bb47129c22298e6b8adfbaf0de4983354..8c54a6492588d6c419edfe4583dbbf5752cf4cb7 100644 --- a/app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java +++ b/app/src/main/java/foundation/e/drive/contentScanner/RemoteFileLister.java @@ -23,7 +23,7 @@ import java.util.List; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncedFolder; -import foundation.e.drive.utils.CommonUtils; +import foundation.e.drive.utils.FileUtils; /** * Implementation of AbstractFileLister with method adapted to remote content @@ -42,13 +42,13 @@ public class RemoteFileLister extends AbstractFileLister { @Override protected boolean skipSyncedFolder(@NonNull SyncedFolder folder) { return (folder.isMediaType() - && CommonUtils.getFileNameFromPath(folder.getRemoteFolder()).startsWith(".")) + && FileUtils.getFileNameFromPath(folder.getRemoteFolder()).startsWith(".")) || !folder.isScanRemote(); } @Override protected boolean skipFile(@NonNull RemoteFile file) { - final String fileName = CommonUtils.getFileNameFromPath(file.getRemotePath()); + final String fileName = FileUtils.getFileNameFromPath(file.getRemotePath()); return fileName == null || fileName.isEmpty() || fileName.startsWith("."); } @@ -66,7 +66,7 @@ public class RemoteFileLister extends AbstractFileLister { @Override @Nullable protected String getFileName(@NonNull RemoteFile file) { - return CommonUtils.getFileNameFromPath(file.getRemotePath()); + return FileUtils.getFileNameFromPath(file.getRemotePath()); } @Override diff --git a/app/src/main/java/foundation/e/drive/fileFilters/MediaFileFilter.java b/app/src/main/java/foundation/e/drive/fileFilters/MediaFileFilter.java index f99e757b86600432ea87c84ba69d5a07bba6ef6f..6ac1740a766dc308978117983e2bfb8da96dd8cb 100644 --- a/app/src/main/java/foundation/e/drive/fileFilters/MediaFileFilter.java +++ b/app/src/main/java/foundation/e/drive/fileFilters/MediaFileFilter.java @@ -12,16 +12,18 @@ package foundation.e.drive.fileFilters; import java.io.File; import java.io.FileFilter; -import foundation.e.drive.utils.CommonUtils; - /** * @author Vincent Bourgmayer */ class MediaFileFilter implements FileFilter { + /** + * Only accept not hidden files: + * Media should not be synced if they're hidden files + * @param file File to check + * @return true if file is accepted + */ @Override public boolean accept(File file) { - //Return true if it's not a hidden file - return !file.isHidden(); } } diff --git a/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java index 11c1dfd10c5e9d43ff0e413abef4ab1a2464e04d..c54934544700e52a8677ff8b88f59a3c51a2d27e 100644 --- a/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/DownloadFileOperation.java @@ -19,6 +19,7 @@ import static com.owncloud.android.lib.common.operations.RemoteOperationResult.R import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import android.content.Context; +import android.media.MediaScannerConnection; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -35,7 +36,7 @@ import java.nio.file.Path; import foundation.e.drive.database.DbHelper; import foundation.e.drive.models.SyncedFileState; -import foundation.e.drive.utils.CommonUtils; +import foundation.e.drive.utils.FileUtils; import timber.log.Timber; /** @@ -155,7 +156,7 @@ public class DownloadFileOperation extends RemoteOperation { syncedFileState.setLocalLastModified(targetFile.lastModified()) .setLastETAG(remoteFile.getEtag()); - CommonUtils.doActionMediaScannerConnexionScanFile(context, syncedFileState.getLocalPath()); //required to make Gallery show new image + doActionMediaScannerConnectionScanFile(context, syncedFileState.getLocalPath()); //required to make Gallery show new image return OK; } @@ -190,4 +191,22 @@ public class DownloadFileOperation extends RemoteOperation { public String getRemoteFilePath() { return remoteFile.getRemotePath(); } + + + /** + * Update Gallery for showing the file in parameter + * + * @param context Calling service context + * @param filePath String containing path the file to update by mediaScanner + */ + private void doActionMediaScannerConnectionScanFile(@NonNull Context context, @NonNull final String filePath) { + Timber.v("doActionMediaScannerConnectionScanFile( %s )", filePath); + final String[] filePathArray = new String[] { filePath }; + final String[] mimeType = new String[] {FileUtils.getMimeType(new File(filePath))}; + MediaScannerConnection.scanFile(context, + filePathArray, + mimeType, + (path, uri) -> Timber.tag("MediaScannerConnection") + .v("file %s was scanned with success: %s ", path, uri)); + } } diff --git a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java index 75e09b3f02872dbfb2cf309aa732458988a46cda..3900c261bc63e34bdc0f1484a94c1331f178bc9d 100644 --- a/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java +++ b/app/src/main/java/foundation/e/drive/operations/UploadFileOperation.java @@ -9,6 +9,8 @@ package foundation.e.drive.operations; +import static foundation.e.drive.utils.FileUtils.getMimeType; + import android.accounts.Account; import android.content.Context; @@ -253,7 +255,7 @@ public class UploadFileOperation extends RemoteOperation { @NonNull public RemoteOperationResult uploadChunkedFile(@NonNull final File file, @NonNull final OwnCloudClient client) { final String timeStamp = formatTimestampToMatchCloud(file.lastModified()); - final String mimeType = CommonUtils.getMimeType(file); + final String mimeType = getMimeType(file); final ChunkedFileUploadRemoteOperation uploadOperation = new ChunkedFileUploadRemoteOperation(syncedState.getLocalPath(), syncedState.getRemotePath(), mimeType, syncedState.getLastETAG(), @@ -311,7 +313,7 @@ public class UploadFileOperation extends RemoteOperation { final UploadFileRemoteOperation uploadOperation = new UploadFileRemoteOperation(syncedState.getLocalPath(), syncedState.getRemotePath(), - CommonUtils.getMimeType(file), + getMimeType(file), eTag, //If not null, This can cause error 412; that means remote file has change timeStamp); return uploadOperation.execute(client); diff --git a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java index 1ffb3a1ec3c21f81e9d30dd9377b22198e1cbc65..92bdef24ecd4a665b5b5b49fdf562352145e53aa 100644 --- a/app/src/main/java/foundation/e/drive/utils/CommonUtils.java +++ b/app/src/main/java/foundation/e/drive/utils/CommonUtils.java @@ -19,18 +19,12 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.ContentResolver; import android.content.Context; -import android.media.MediaScannerConnection; import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.net.Uri; -import android.webkit.MimeTypeMap; import android.widget.Toast; -import com.owncloud.android.lib.resources.files.FileUtils; - -import java.io.File; -import java.io.IOException; import java.lang.reflect.Method; import java.text.CharacterIterator; import java.text.StringCharacterIterator; @@ -63,7 +57,6 @@ import androidx.work.WorkManager; * @author Mohit Mali */ public abstract class CommonUtils { - private final static String TAG = CommonUtils.class.getSimpleName(); /** * Set ServiceUncaughtExceptionHandler to be the MainThread Exception Handler @@ -123,7 +116,7 @@ public abstract class CommonUtils { * * @param account Account used for synchronisation * @param syncedFileStateIsMedia true if the concerned syncedFileState is a media's type element, false if it is a settings's type element - * @return + * @return true if sync is allowed in given condition */ public static boolean isThisSyncAllowed(@NonNull Account account, boolean syncedFileStateIsMedia) { return (syncedFileStateIsMedia && isMediaSyncEnabled(account)) @@ -152,28 +145,17 @@ public abstract class CommonUtils { /** * Read accountManager settings - * - * @param account + * to check if user can sync on metered network + * @param account account used to check settings * @return true if usage of metered connection is allowed */ public static boolean isMeteredNetworkAllowed(@NonNull Account account) { return ContentResolver.getSyncAutomatically(account, METERED_NETWORK_ALLOWED_AUTHORITY); } - /** methods relative to file **/ + /* methods relative to file */ + - /** - * Return name of a file from its access path - * - * @param path File name will be extracted from this path. Do not provide directory path - * @return String, the last part after separator of path or null if invalid path has been provided - */ - @Nullable - public static String getFileNameFromPath(@NonNull String path) { - final String[] splittedString = path.split(FileUtils.PATH_SEPARATOR); - if (splittedString.length <= 0) return null; - return splittedString[splittedString.length - 1]; - } /** * Tell if there is internet connection @@ -183,82 +165,21 @@ public abstract class CommonUtils { * @return True if there is connection, false either */ public static boolean haveNetworkConnection(@NonNull Context context, boolean meteredNetworkAllowed) { - Timber.tag(TAG).v("haveNetworkConnection()"); + Timber.v("haveNetworkConnection()"); final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class); final NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork()); - if (capabilities != null + return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) && (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) - || meteredNetworkAllowed)) { - return true; - } - return false; - } - - - /** - * Get mimetype of file from the file itself - * - * @param file the file for whom we want Mime type - * @return String containing mimeType of the file - */ - @NonNull - public static String getMimeType(@NonNull File file) { - final String mimetype = MimeTypeMap.getSingleton() - .getMimeTypeFromExtension( - MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(file).toString()).toLowerCase(Locale.ROOT)); - if (mimetype == null) { - return "*/*"; - } - return mimetype; - } - - /** - * Update Gallery for showing the file in paramater - * - * @param context Calling service context - * @param filePath String containing path the file to update by mediaScanner - */ - public static void doActionMediaScannerConnexionScanFile(@NonNull Context context, @NonNull final String filePath) { - Timber.v("doActionMediaScannerConnexionScanFile( %s )", filePath); - final String[] filePathArray = new String[] { filePath }; - final String[] mimeType = new String[] {getMimeType(new File(filePath))}; - MediaScannerConnection.scanFile(context, - filePathArray, - mimeType, - new MediaScannerConnection.OnScanCompletedListener() { - @Override - public void onScanCompleted(String path, Uri uri) { - Timber.tag("MediaScannerConnection") - .v("file %s was scanned with success: %s ", path, uri); - } - }); - } - - /** - * Return the canonical path if available, either return absolute path - * - * @param file file from which we want the path - * @return canonical path if available - */ - @NonNull - public static String getLocalPath(@NonNull File file) { - String result; - try { - result = file.getCanonicalPath(); - } catch (SecurityException | IOException exception ) { - Timber.v(exception); - result = file.getAbsolutePath(); //todo why not simply always use getAbsolutePath? - } - return result; + || meteredNetworkAllowed); } /** * Formatter class is not used since bytes passed by server are in SI unit aka 1kb = 1024byte - * https://stackoverflow.com/questions/3758606/how-can-i-convert-byte-size-into-a-human-readable-format-in-java/3758880#3758880 + * ... * * @param bytes file/data size in bytes * @return String in human readable format @@ -296,7 +217,7 @@ public abstract class CommonUtils { */ public static void registerInitializationWorkers(@Nullable List syncedFolders, @NonNull WorkManager workManager) { if (syncedFolders == null || syncedFolders.isEmpty()) { - Timber.tag(TAG).d("registerInitializationWorkers: Can't create remote folders. List is empty"); + Timber.d("registerInitializationWorkers: Can't create remote folders. List is empty"); return; } @@ -342,11 +263,11 @@ public abstract class CommonUtils { /** * Job for Widget & notification about quota * - * @param workManager + * @param workManager component used to register worker */ public static void registerPeriodicUserInfoChecking(@NonNull WorkManager workManager) { final PeriodicWorkRequest workRequest = WorkRequestFactory.getPeriodicWorkRequest(WorkRequestFactory.WorkType.PERIODIC_USER_INFO); - workManager.enqueueUniquePeriodicWork(AccountUserInfoWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.REPLACE, workRequest); + workManager.enqueueUniquePeriodicWork(AccountUserInfoWorker.UNIQUE_WORK_NAME, ExistingPeriodicWorkPolicy.UPDATE, workRequest); } /** diff --git a/app/src/main/java/foundation/e/drive/utils/FileUtils.kt b/app/src/main/java/foundation/e/drive/utils/FileUtils.kt new file mode 100644 index 0000000000000000000000000000000000000000..77185ebdc069cb47c985c1ea22c6883b43e92aa3 --- /dev/null +++ b/app/src/main/java/foundation/e/drive/utils/FileUtils.kt @@ -0,0 +1,69 @@ +/* + * 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 + */ +package foundation.e.drive.utils + +import com.owncloud.android.lib.resources.files.FileUtils +import com.owncloud.android.lib.resources.files.FileUtils.PATH_SEPARATOR +import timber.log.Timber +import java.io.File +import java.io.IOException +import java.net.URLConnection + +object FileUtils { + /** + * Return name of a file from its access path + * Also work with folder path. If last char is PATH separator, then the last occurence is removed. + * + * @param rawPath File name will be extracted from this path. Do not provide directory path + * @return String, the last part after separator of path or null if invalid path has been provided + */ + @JvmStatic + fun getFileNameFromPath(rawPath: String): String? { + val path = rawPath.removeSuffix(PATH_SEPARATOR) + val lastIndexOfPathSeparator = path.lastIndexOf(FileUtils.PATH_SEPARATOR) + if (lastIndexOfPathSeparator == -1) return null + return path.substring(lastIndexOfPathSeparator + 1) + } + + /** + * Return the canonical path if available, either return absolute path + * + * @param file file from which we want the path + * @return canonical path if available + */ + @JvmStatic + fun getLocalPath(file: File): String { + val result: String = try { + file.canonicalPath + } catch (exception: SecurityException) { + Timber.v(exception) + file.absolutePath //todo why not simply always use getAbsolutePath? + } catch (exception: IOException) { + Timber.v(exception) + file.absolutePath + } + return result + } + + /** + * Guess mimetype of the file from file extension + * + * URLConnection method throw NPE if no extension or unknown extension (e.g: .tmo) + * + * @param file the file for whom we want Mime type + * @return String containing mimeType of the file for known type default value for others + */ + @JvmStatic + fun getMimeType(file: File): String { + try { + return URLConnection.guessContentTypeFromName(file.name) + } catch(e: java.lang.NullPointerException) { + return "*/*" + } + } +} \ No newline at end of file diff --git a/app/src/main/java/foundation/e/drive/utils/RootSyncedFolderProvider.kt b/app/src/main/java/foundation/e/drive/utils/RootSyncedFolderProvider.kt index cd03ed03637abac006796c2a735299d369989ec4..5f7295af7cf45f00c652365610cf1cb139135043 100644 --- a/app/src/main/java/foundation/e/drive/utils/RootSyncedFolderProvider.kt +++ b/app/src/main/java/foundation/e/drive/utils/RootSyncedFolderProvider.kt @@ -123,7 +123,7 @@ object RootSyncedFolderProvider { } private fun createMediaSyncedFolder(category: String, publicDirectoryType: String, remotePath: String): SyncedFolder { - val dirPath = CommonUtils.getLocalPath(Environment.getExternalStoragePublicDirectory(publicDirectoryType)) + val dirPath = FileUtils.getLocalPath(Environment.getExternalStoragePublicDirectory(publicDirectoryType)) val localPath = dirPath + PATH_SEPARATOR return SyncedFolder(category, localPath, remotePath, true) } @@ -137,7 +137,7 @@ object RootSyncedFolderProvider { * * @return true or false */ - fun isAboveA12(): Boolean { + private fun isAboveA12(): Boolean { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S } } \ No newline at end of file diff --git a/app/src/test/java/foundation/e/drive/utils/FileUtilsTest.kt b/app/src/test/java/foundation/e/drive/utils/FileUtilsTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..174fc2c2791a99f6aa31997673508c6ea51122bd --- /dev/null +++ b/app/src/test/java/foundation/e/drive/utils/FileUtilsTest.kt @@ -0,0 +1,67 @@ +/* + * 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 + */ +package foundation.e.drive.utils + +import org.junit.Assert +import org.junit.Test +import java.io.File + +internal class FileUtilsTest { + + @Test + fun `get file name from path with invalid path should return null`() { + val invalidPath = "photo.jpg" + val result = FileUtils.getFileNameFromPath(invalidPath) + Assert.assertNull("Null was expected but got ${result.toString()}", result) + } + + @Test + fun `get file name from path with valid path should return the file name`() { + val expectedResult = "photo.jpg" + val validPath = "folder/photo.jpg" + val result = FileUtils.getFileNameFromPath(validPath) + Assert.assertEquals("Got $result instead of $expectedResult", expectedResult, result) + + val validPath2 = "/folder0/folder1/folder2/photo.jpg" + val result2 = FileUtils.getFileNameFromPath(validPath2) + Assert.assertEquals("Got $result2 instead of $expectedResult", expectedResult, result2) + } + + @Test + fun `get file name from path with wrong path separator should return null`() { + val invalidPath = "\\folder\\photo.jpg" + val result = FileUtils.getFileNameFromPath(invalidPath) + Assert.assertNull("Got $result instead of null", result) + } + + @Test + fun `getMimeType from file with unusual extension `() { + val expected = "*/*" + val file = File("dummy.tmo") + val result = FileUtils.getMimeType(file) + + Assert.assertEquals("Expected $expected but got $result", expected, result) + } + + @Test + fun `getMimeType from file without extension `() { + val expected = "*/*" + val file = File("dummy") + val result = FileUtils.getMimeType(file) + + Assert.assertEquals("Expected $expected but got $result", expected, result) + } + + @Test + fun `getMimeType for picture file`() { + val expected = "image/jpeg" + val file = File("../files-for-test/picture.jpeg") + val result = FileUtils.getMimeType(file) + Assert.assertEquals("Expected $expected but got $result", expected, result) + } +} \ No newline at end of file diff --git a/files-for-test/picture.jpeg b/files-for-test/picture.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d663a2e5aa0c4fe68de1103bc57658dbd849e2b7 Binary files /dev/null and b/files-for-test/picture.jpeg differ